Skip to main content

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.

Tesslate OpenSail

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.
This page covers both. If you’re wiring up a Slack bot, you want external API keys. If you’re trying to bypass platform credit costs by using your own OpenAI key, you want BYOK. For BYOK specifics, see /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:
  1. The server generates 32 random hex characters
  2. Prepends tsk_ to form the full token
  3. Computes SHA-256 of the full token
  4. Stores only the hash plus a 4-character prefix for identification
  5. Returns the raw key to you once
You cannot retrieve the raw key later. If you lose it, rotate it.

Creating a key

1

Open Settings

Settings, then the API Keys section. You’ll see tabs for external keys and BYOK keys.
2

Create External Key

Click Create Key. Give it a human-readable name (“Slack Bot”, “CI Deploy Hook”).
3

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.
4

Set expiration (optional)

Optionally set expires_at. After that timestamp, the key stops authenticating.
5

Copy the key

The raw key is shown one time. Copy it into your secret manager or the integration you’re wiring up. You cannot view it again.
Treat tsk_ keys like passwords. Never commit them to git. Use your platform’s secret store (env vars, Vault, AWS Secrets Manager, etc.).

Using a key

Pass the raw key as a Bearer token:
Authorization: Bearer tsk_8f3a1b2c4d5e6f7a8b9c0d1e2f3a4b5c
The most common endpoint is the agent invoke endpoint:
curl -X POST https://your-opensail.example.com/api/external/agent/invoke \
  -H "Authorization: Bearer tsk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "project_id": "550e8400-e29b-41d4-a716-446655440000",
    "message": "Review the open PR and post a summary in Slack",
    "webhook_url": "https://my-service.example.com/hooks/opensail"
  }'
The response comes back immediately:
{
  "task_id": "arq:task:abc123",
  "chat_id": "660e8400-e29b-41d4-a716-446655440000",
  "events_url": "/api/external/agent/events/arq:task:abc123",
  "status": "queued"
}

Reading results

Three options, pick whichever fits your integration.

Scopes and rate limits

SettingBehavior
project_id scopeKey can only invoke agents on the named project
expires_atKey stops authenticating after this timestamp
Active keys per userCapped at 10
is_activeSoft-delete; revoked keys cannot be reactivated
Rate limits apply per key to prevent runaway loops. Defaults are generous but enforced.

Rotation and revocation

1

Create a replacement

Generate a new key in Settings. Copy the raw value.
2

Deploy the new key

Update your integration to use the new key. Verify calls succeed.
3

Revoke the old key

Back in Settings, click Revoke on the old key. is_active flips to false; the key stops authenticating immediately.
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.
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

1

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.
2

Open Settings, API Keys, BYOK tab

The BYOK tab lists every provider key you have stored (values masked).
3

Add the key

Pick the provider, paste the key, optionally name it.
4

Save

The key is Fernet-encrypted at rest. Raw keys are never logged or cached.
5

Verify

Start an agent session with a matching model. The model selector shows a BYOK badge and the session does not deduct platform credits.

Where keys are stored

Each BYOK key is a UserAPIKey row:
FieldPurpose
providerProvider identifier (openai, anthropic, openrouter, etc.)
auth_typeapi_key, oauth_token, bearer_token, or personal_access_token
key_nameYour label
encrypted_valueFernet-encrypted raw key
is_activeSoft-deleted keys remain in the table for audit
last_used_atTimestamp 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

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.
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.
Rotate external keys whenever a team member changes roles. Rotate BYOK keys on any suspicion of compromise and whenever the provider recommends it.
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

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

Key expired, revoked, or mis-pasted. Check the raw value has no leading whitespace or trailing newline. Verify the key is still active in Settings.
Key is scoped to a different project. Either create a new key for the target project or use an unscoped key.
ARQ worker pods may be saturated. Check worker health. For long queues, tune worker_max_jobs in the platform config.
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