Skip to main content
🤖 LLM Friendly: This page is available in raw Markdown format for LLM consumption:authentication.md|Get full documentation:llms.txt/llms-full.txt

Authentication

The Firetell API supports two authentication methods, each designed for a different use case:

MethodSchemeUse Case
API KeyApiKey sk-...Server-to-server calls from your backend
JWT TokenBearer <jwt>Client-side calls from your web or mobile app

Both methods use the Authorization HTTP header.


API Key Authentication (Server-side)

Use API Keys to authenticate server-to-server requests from your backend. API keys start with the sk- prefix and are passed using the ApiKey scheme.

Authorization: ApiKey sk-your_api_key
danger

Do NOT use API Keys in client-side code. API Keys grant full access to your workspace and must never be embedded in frontend applications — including JavaScript bundles, mobile apps, or any code that runs on the user's device. Attackers can easily extract keys from client-side code and use them to read, modify, or delete your workspace resources.

For client-side authentication, use JWT Tokens instead.

Quick Example

curl -X GET "https://{workspace_id}.firetell.app/api/v1/phone-numbers" \
-H "Authorization: ApiKey sk-your_api_key"

Getting Your API Key

  1. Log in to the Firetell Console
  2. Select your workspace
  3. Navigate to SettingsAPI Keys
  4. Click Create API Key
  5. Enter a descriptive name
  6. Copy the generated key (starts with sk-)
caution

Your API Key is only shown once at creation time. Store it securely — you will not be able to retrieve it again. If lost, delete the key and create a new one.

tip

Each workspace can have up to 100 API keys. Use descriptive titles like "Production Server", "Staging", or "CRM Integration" to organize your keys.

Code Examples

cURL

curl -X GET "https://{workspace_id}.firetell.app/api/v1/phone-numbers" \
-H "Authorization: ApiKey sk-your_api_key" \
-H "Content-Type: application/json"

Node.js

const response = await fetch(
"https://{workspace_id}.firetell.app/api/v1/phone-numbers",
{
headers: {
Authorization: "ApiKey sk-your_api_key",
"Content-Type": "application/json",
},
},
);
const data = await response.json();

Python

import requests

response = requests.get(
'https://{workspace_id}.firetell.app/api/v1/phone-numbers',
headers={
'Authorization': 'ApiKey sk-your_api_key',
'Content-Type': 'application/json',
},
)
data = response.json()

JWT Authentication (Client-side)

Use JWT tokens to authenticate client-side requests from your web or mobile application. Your backend signs JWTs using the API Key secret (sk-...) with the HS256 algorithm.

Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

How It Works

  1. Your backend signs a JWT using your API Key secret (sk-...) with HS256
  2. Your backend returns the JWT to the client application
  3. The client includes the JWT in all API requests
┌──────────┐ ┌──────────────┐
│ Client │──(1)──▶ │ Your Backend │
│ (Web / │ │ Signs JWT │
│ Mobile) │◀──(2)── │ with sk-... │
│ │ └──────────────┘
│ │
│ │──(3)──────────────────────────▶ Firetell API
│ │ Authorization: (Bearer JWT)
└──────────┘
  1. Client requests a token from your backend
  2. Your backend signs a JWT locally using the API Key secret and returns it
  3. Client calls Firetell API directly with Bearer <jwt>

JWT Claims

ClaimDescriptionExample
issAPI Key SIDsid-your_api_key_sid
subSubject identifier (see Audience Types below)agent_123 or user_abc
audAudience type: agent-api or client-apiagent-api
expExpiration timestamp24 hours from now
domainWorkspace domain (custom claim)yourcompany.firetell.app
call_flow_idVisual Call Flow ID (custom claim, required for client-api)cf_abc123xyz789000

Audience Types

The aud claim determines what type of identity the token represents. Firetell supports two distinct identities:

Audiencesub requirementUse case
agent-apiMust be the username of an existing, active agent in your workspaceCall center agents, support reps
client-apiCan be any identifier you define (e.g. user ID, phone number, email)End-user clients, in-app calling

Agent API vs Client API

Understanding the difference between these two identities is key to building the right integration.

Agent API (agent-api)

Agents are managed users created by workspace admins via Console or the Agents API. They represent real people in your organization (support reps, sales agents, operators).

FeatureDetails
Created byWorkspace admin (Console or API)
UsernameFixed, unique within workspace
QuantityLimited by your workspace plan
PSTN calls✅ Outbound and inbound via phone numbers
Call routing✅ Queues, IVR, team-based routing
Internal calls✅ Agent ↔ Agent, Agent ↔ Client
Call Center Portal✅ Web, iOS, Android app
Presence✅ Online/offline/busy state
Teams✅ Assigned to teams for routing
info

Agent Limits

The number of agents you can create depends on your workspace plan. To view your current limits: ConsoleWorkspace SettingsLimits.

Need more agents? Upgrade your plan or contact enterprise@firetell.com.

note

Device Session Limit

For agents logging in via the official portal endpoint (/auth/login), each agent is allowed a maximum of 5 concurrent active device sessions (e.g., 1 browser, 1 mobile app, 1 desktop app, etc.).

If an agent logs in on a 6th device, the oldest session is automatically evicted (logged out) to enforce limits.

Note: If your backend signs JWT tokens manually (custom integration) without providing a device_id claim, this 5-device limit check is bypassed.

Client API (client-api)

Clients are dynamic identities — your backend signs a JWT with any sub value you choose. No pre-registration needed. Clients are designed for in-app, internal VoIP calling between your users.

FeatureDetails
Created byYour backend signs JWT with any username
UsernameAny identifier (user ID, phone, email, session)
QuantityUnlimited tokens (limit on active connections)
PSTN calls❌ Internal VoIP only
Call routing❌ Direct calls only
Internal calls✅ Client ↔ Client, Client ↔ Agent
Call Center Portal❌ Integrates into your own app
Presence✅ Online/offline state
Teams❌ Not applicable
caution

Concurrent Connection Limit While you can generate and sign unlimited client JWT tokens (client-api), there is a default workspace limit of 1,000 concurrent active WebSocket signaling connections.

If your application requires higher concurrent limits, please contact enterprise@firetell.com to increase the limit for your workspace.

Use Case Examples

ScenarioIdentityFlow
Ride-hailingclient-apiDriver app ↔ Customer app (in-app VoIP)
E-commerce supportBothCustomer (client-api) → Call center agent (agent-api)
Telemedicineclient-apiPatient app ↔ Doctor app
Customer supportagent-apiInbound PSTN call → IVR → Agent
Sales outreachagent-apiAgent → Outbound PSTN call to lead
In-app callingclient-apiUser A ↔ User B within your app
┌─────────────────────────────────────────────────────────┐
│ Your Application │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Client API │ ◄── VoIP ──► │ Client API │ │
│ │ (Driver) │ │ (Customer) │ │
│ └──────────────┘ └──────┬───────┘ │
│ │ │
│ VoIP │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Agent API │ │
│ │ (Support) │ │
│ └──────┬───────┘ │
│ │ │
└──────────────────────────────────────────┼───────────────┘

PSTN │

┌─────────────┐
│ Phone │
│ Network │
└─────────────┘

Quick Examples

Agent API token

const jwt = require("jsonwebtoken");

const token = jwt.sign(
{ domain: "yourcompany.firetell.app" },
"sk-your_api_key_secret",
{
algorithm: "HS256",
expiresIn: "24h",
issuer: "sid-your_api_key_sid",
subject: "agent_123", // Must be an existing, active agent username
audience: "agent-api",
},
);

Client API token

const jwt = require("jsonwebtoken");

const token = jwt.sign(
{
domain: "yourcompany.firetell.app",
call_flow_id: "cf_your_call_flow_id", // Required for client-api to route calls to a Call Flow
},
"sk-your_api_key_secret",
{
algorithm: "HS256",
expiresIn: "24h",
issuer: "sid-your_api_key_sid",
subject: "user_abc", // Any custom identifier you define
audience: "client-api",
},
);

For detailed examples in Python, PHP, and more, see the Client Authentication guide.

tip

JWT tokens are designed for client-side usage and expire after a short period. Always sign tokens on your backend and pass them to the client — never expose your API Key secret to client-side code.


Workspace Scope

Both API keys and JWT tokens are scoped to a single workspace. The workspace is determined by the subdomain in the request URL:

https://{workspace_id}.firetell.app/api/v1/...
^^^^^^^^^^^^^^
workspace scope

You cannot access resources from other workspaces with a single key or token.


Choosing the Right Method

API Key (ApiKey)JWT Token (Bearer)
Where to useBackend / serverFrontend / client
LifetimeLong-lived (until revoked)Short-lived (expires)
SecurityMust be kept secretSafe to send to client
Access levelFull workspace accessScoped by JWT claims
ExampleREST API integrations, webhooks, cron jobsWebRTC, real-time apps
warning

Never expose API Keys in client-side code. API keys grant full access to your workspace. Use JWT tokens for any code that runs in the browser or on mobile devices.

tip

Use separate API keys for each authentication flow. Create one key for server-to-server API calls (ApiKey scheme) and a different key for signing client JWT tokens (Bearer scheme). This makes it easy to identify which flow is affected if a key is compromised, and you can revoke a single key without disrupting the other.


Rate Limiting

API requests are rate-limited to protect service quality:

TierRequests per minute
Default100
Auth10
Heavy30
EnterpriseCustom

When rate limited, you'll receive a 429 Too Many Requests response with a Retry-After header. Implement exponential backoff in your retry logic.

See Rate Limiting for full details.


Error Responses

Missing Authorization Header

{
"statusCode": 401,
"message": "Missing Authorization header"
}

Unsupported Scheme

{
"statusCode": 401,
"message": "Unsupported authorization scheme \"Basic\". Use \"Bearer\" or \"ApiKey\""
}

Invalid API Key

{
"statusCode": 401,
"message": "Invalid API Key"
}

Invalid or Expired JWT

{
"statusCode": 401,
"message": "Unauthorized"
}

Security Best Practices

  • Never expose API keys in client-side code — Use them only on your backend server
  • Use JWT tokens for clients — Generate short-lived tokens for browser and mobile apps
  • Rotate keys regularly — Delete old keys and create new ones periodically
  • Use separate keys per environment — Different keys for development, staging, and production
  • Store secrets securely — Use environment variables or a secret manager, never hardcode in source code

Next Steps