Authentication
Two auth modes. One identity model.
Bearer tokens for server-to-server traffic, Clerk session tokens for browser apps, and the rotation patterns Link AI uses internally to keep credentials short-lived without breaking integrations.
Link AI exposes two authentication schemes. They share a workspace identity model, so any permission you grant in one is honoured by the other. Pick the scheme that matches where the request originates.
| Scheme | Where to use | Credential lifetime |
|---|---|---|
Bearer token | Server-to-server. CLI scripts, cron jobs, Zapier-style integrations. | Long-lived. Rotate every 90 days. |
Clerk session token | Browser apps acting on behalf of a logged-in user. | Short-lived (60s). Auto-refreshed by Clerk SDK. |
Bearer tokens
Every server-to-server request carries an Authorization: Bearer <token> header. Tokens are minted from the workspace dashboard and scoped to a single workspace. There is no “account” tier above the workspace boundary — if you need to touch two workspaces, you mint two tokens.
curl https://api.linkaiil.com/v1/voice/agents \
-H "Authorization: Bearer $LINKAI_TOKEN"Token prefixes
lnk_live_— production traffic againstapi.linkaiil.com.lnk_test_— staging traffic againststaging.api.linkaiil.com. Identical surface, isolated data, no real-world side effects (no calls dialled, no emails sent).
Treat both as bearer secrets. Link AI scans the public surface of GitHub for accidentally committed lnk_live_ values once a day and revokes any match automatically.
Scopes
Each token can be narrowed to a subset of permissions. Defaults cover everything the workspace is licenced for; tighten when the integration only needs read access.
| Scope | Grants |
|---|---|
voice:read | List agents, calls, transcripts. |
voice:write | Place calls, mutate agents, update prompts. |
mailer:read | Read campaigns, leads, generated emails. |
mailer:write | Push leads, kick off research, queue sends. |
webhooks:write | Create + rotate webhook endpoints. |
Clerk session tokens
Browser apps that already use Clerk for end-user auth can hit the Link AI API directly using the short-lived session token. The platform validates the token against the workspace’s configured Clerk instance and resolves the caller to a real member (with that member’s role + scopes).
import { useAuth } from "@clerk/nextjs";
export function CallButton({ to }: { to: string }) {
const { getToken } = useAuth();
async function placeCall() {
const token = await getToken({ template: "linkai" });
await fetch("https://api.linkaiil.com/v1/voice/calls", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ agent_id: "agt_5fd1a02b", to }),
});
}
return <button onClick={placeCall}>Call</button>;
}The template: "linkai" argument tells Clerk to issue a JWT that Link AI knows how to verify — configure that template once in your Clerk dashboard, then forget about it.
Rotating a Bearer token without downtime
Link AI supports two active tokens per workspace specifically so rotation is a no-downtime operation. The dance is:
- Mint a new token. Dashboard -> Settings -> Developers -> Create token. Pick a clear label (“prod-2026-q2”).
- Roll out the new token. Deploy it to every running service. Confirm
/v1/whoamireturns 200 against both the old and new credential before touching anything destructive. - Revoke the old token. Click revoke in the dashboard. Any straggler request will fail with 401 within one propagation cycle (under a minute).
Error responses
Auth failures return a consistent shape. The code field is stable across versions; the human-readable message is not.
{
"error": {
"code": "invalid_token",
"message": "The provided Bearer token is malformed or revoked.",
"request_id": "req_01HFE9X..."
}
}invalid_token— malformed, expired, or revoked credential.missing_scope— token valid but lacks the scope required by the endpoint.workspace_disabled— workspace is suspended for billing or trust-and-safety reasons. Contact office@linkaiil.com.