Documentation Index
Fetch the complete documentation index at: https://docs.tesslate.com/llms.txt
Use this file to discover all available pages before exploring further.

Two kinds of keys
OpenSail uses two distinct kinds of API keys, and it’s important to know which one you need.External API keys
For calling OpenSail agents from outside the platform: Slack bots, CI pipelines, cron jobs, external integrations.
tsk_ prefixed. Created in Settings.BYOK provider keys
For using your own OpenAI, Anthropic, OpenRouter, or other provider keys instead of platform credits. Encrypted at rest. Pro and Ultra only.
/guides/model-management.
External API keys
External keys let outside systems invoke OpenSail agents through a REST API. The canonical flow: a Slack bot mentions your agent, a CI job kicks off a code review, a cron schedule fires a weekly report, an external coding agent (Cursor, Claude Code) reaches into your OpenSail instance for sandboxed compute.Key format
- Prefix:
tsk_ - Body: 32 random hex characters
- Example:
tsk_8f3a1b2c4d5e6f7a8b9c0d1e2f3a4b5c
How storage works
Raw keys are never stored. When you create a key:- The server generates 32 random hex characters
- Prepends
tsk_to form the full token - Computes SHA-256 of the full token
- Stores only the hash plus a 4-character prefix for identification
- Returns the raw key to you once
Creating a key
Create External Key
Click Create Key. Give it a human-readable name (“Slack Bot”, “CI Deploy Hook”).
Set scope (optional)
Optionally restrict the key to a single project by setting a
project_id. Scoped keys can only invoke agents on that project. Unscoped keys can access any project you own.Set expiration (optional)
Optionally set
expires_at. After that timestamp, the key stops authenticating.Using a key
Pass the raw key as a Bearer token:Reading results
Three options, pick whichever fits your integration.- SSE stream (recommended)
- Polling
- Webhook callback
Open a Server-Sent Events connection to If the connection drops, reconnect with
events_url. You get live tool calls, text, and the final response as the agent works.?last_event_id=evt_002 to replay missed events before resuming live stream.Scopes and rate limits
| Setting | Behavior |
|---|---|
project_id scope | Key can only invoke agents on the named project |
expires_at | Key stops authenticating after this timestamp |
| Active keys per user | Capped at 10 |
is_active | Soft-delete; revoked keys cannot be reactivated |
Rotation and revocation
Keys can also be revoked via
DELETE /api/external/keys/{key_id}.
BYOK provider keys
BYOK (Bring Your Own Key) lets you route AI calls through your own provider key instead of paying platform credits. Available on Pro and Ultra subscription tiers.- How it works
- Providers
When the agent picks a model whose provider matches a key you have stored, LiteLLM routes the call through your key. Cost is zero in platform credits; you pay the upstream provider directly. The
UsageLog row is still created for your analytics with is_byok=True and billed_status="exempt".Adding a provider key
Get the key from the provider
Sign in at the provider console (platform.openai.com, console.anthropic.com, openrouter.ai, etc.) and generate an API key.
Open Settings, API Keys, BYOK tab
The BYOK tab lists every provider key you have stored (values masked).
Where keys are stored
Each BYOK key is aUserAPIKey row:
| Field | Purpose |
|---|---|
provider | Provider identifier (openai, anthropic, openrouter, etc.) |
auth_type | api_key, oauth_token, bearer_token, or personal_access_token |
key_name | Your label |
encrypted_value | Fernet-encrypted raw key |
is_active | Soft-deleted keys remain in the table for audit |
last_used_at | Timestamp of most recent use |
BYOK detection
When you invoke a model,is_byok_model(model_name) checks the provider prefix against BUILTIN_PROVIDERS. If the prefix matches one of your stored keys, the call runs BYOK. Adding a new provider to the registry automatically enables BYOK routing for its models.
BYOK only applies when a matching key exists for your user. If you have an Anthropic key but pick a DeepSeek model, the DeepSeek call uses platform credits. Keys don’t cross providers.
Security
At-rest encryption
At-rest encryption
External key hashes are SHA-256. BYOK keys are encrypted with Fernet using a server-held key (
ENCRYPTION_KEY). Raw values are never persisted in plaintext.No plaintext in logs
No plaintext in logs
Tool outputs are scrubbed for high-entropy strings before being returned to the model. Your keys never leak into the transcript or an exported trajectory.
Rotation policy
Rotation policy
Rotate external keys whenever a team member changes roles. Rotate BYOK keys on any suspicion of compromise and whenever the provider recommends it.
Separation of duties
Separation of duties
External keys bind to a user, not to a service account. If a user leaves, revoke their external keys. Plan for handover: critical integrations should use service-owned user accounts.
Common patterns
- Slack bot
- CI review bot
- Scheduled report
- External coding agent
Generate an external key scoped to one project. Configure your Slack app to POST mentions to a worker. The worker calls
/api/external/agent/invoke with the mention text. Use the webhook callback to post the agent’s response back into Slack.Troubleshooting
401 Unauthorized on invoke
401 Unauthorized on invoke
403 Forbidden on project access
403 Forbidden on project access
Key is scoped to a different project. Either create a new key for the target project or use an unscoped key.
Task stuck in queued
Task stuck in queued
ARQ worker pods may be saturated. Check worker health. For long queues, tune
worker_max_jobs in the platform config.BYOK call falls through to credits
BYOK call falls through to credits
Verify the model’s provider prefix matches your stored key’s provider. A Claude model call only uses an Anthropic key, not an OpenAI key. Check BYOK is enabled for your tier (Pro or Ultra).
Next steps
Model Management
BYOK routing, passthrough mode, self-hosted models
Billing
How BYOK zeros your credit cost while keeping analytics
Using Agents
Invoke an agent from the chat UI instead of the API
Connectors (MCP)
Wire Slack, Gmail, and more into the agent itself instead of bolting external callers on top