Skip to content

API authentication

How to authenticate requests to the SUPERWISE Chat API. This is a reference: pick the mechanism that matches the surface you’re calling, then copy the example.

SUPERWISE Chat exposes two API surfaces, each with its own authentication:

SurfaceBase pathAuthenticates withUse it for
Product API/v1/*Authorization: Bearer <JWT>Conversations, knowledge, memory, admin, and every tenant-scoped resource
OpenAI-compatible API/openai/v1/*Authorization: Bearer swk_<key>Drop-in OpenAI client integrations against a published chat endpoint
Embed widget/v1/embed/*X-Embed-Key: <key>The chat bubble embedded on a public website
Inbound webhooks/v1/webhooks/{channel_id}X-Webhook-Signature (HMAC)Posting external alerts into a conversation

Every request — authenticated or not — is tagged with an x-request-id (generated if you don’t send one) and echoed back in error responses. Include it in support reports.

EnvironmentBase URL
Productionhttps://api.superwise-chat.company.com
Local development (Docker Compose)http://localhost:3080
Local development (bare Node)http://localhost:3000

All product routes are mounted under the /v1 prefix. There is no /v2.

Every endpoint under /v1/* requires a signed JSON Web Token issued by your identity provider (Frontegg or Auth0). Send it as a bearer token:

GET /v1/me HTTP/1.1
Host: api.superwise-chat.company.com
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...

What the token resolves to on the server:

Claim → resolved valueUsed for
Tenant IDPins every database query to your tenant (row-level isolation)
User IDAttributes the request and scopes per-user resources
RolesEvaluated against RBAC capabilities for each endpoint

A request with a missing or malformed Authorization header is rejected before it reaches any handler. The token’s audience is verified in production to prevent a token issued for another service from being replayed against Chat.

JWTs are issued by your identity provider, not by SUPERWISE Chat. In a browser session the web app obtains and refreshes the token for you. For a service or script, request a token from your Frontegg/Auth0 tenant using your provider’s standard OAuth 2.0 client-credentials or login flow, then present it as shown above. Tokens expire; refresh them per your provider’s lifetime.

For local development and tests, the server can run with AUTH_PROVIDER=local, which bypasses JWT verification and resolves identity from request headers (x-tenant-id, x-user-id, x-user-roles), falling back to environment defaults (DEV_TENANT_ID, DEV_USER_ID, and optional DEV_USER_ROLES) when a header is absent.

2. swk_ API keys — the OpenAI-compatible API

Section titled “2. swk_ API keys — the OpenAI-compatible API”

The OpenAI-compatible surface (/openai/v1/chat/completions, /openai/v1/models) lets you point an existing OpenAI client library at a SUPERWISE Chat endpoint. It authenticates with a tenant API key beginning with the swk_ prefix, passed as a standard bearer token.

POST /openai/v1/chat/completions HTTP/1.1
Host: api.superwise-chat.company.com
Authorization: Bearer swk_a1b2c3d4_0123456789abcdef0123456789abcdef
Content-Type: application/json
PropertyValue
Formatswk_<8-char-tenant-slug>_<32 hex chars>
VisibleOnce, at creation. The full key is never returned again.
StoredAs a SHA-256 hash. Only the prefix (swk_ + 8 chars) is kept in cleartext.
ScopesA non-empty list, set at creation
ExpiryOptional expires_at timestamp
RevocationSoft revoke — the key is marked revoked and stops validating immediately

Because only a hash is stored, a lost key cannot be recovered. Issue a new one and revoke the old.

Managing API keys requires the rbac.manage capability (a tenant administrator role).

Returns metadata only — never the full key value.

GET /v1/tenant/api-keys
Authorization: Bearer <admin JWT>
{
"keys": [
{
"id": "f0e9d8c7-...",
"key_prefix": "swk_a1b2c3d4",
"description": "Reporting integration",
"scopes": ["chat.completions"],
"expires_at": null,
"is_revoked": false,
"created_at": "2026-06-01T12:00:00.000Z",
"last_used_at": "2026-06-12T09:30:00.000Z"
}
]
}

scopes is required and must be a non-empty array. An Idempotency-Key header is required so a retried create never mints a duplicate key.

POST /v1/tenant/api-keys
Authorization: Bearer <admin JWT>
Idempotency-Key: 5b9c2a14-...
Content-Type: application/json
{
"description": "Reporting integration",
"scopes": ["chat.completions"],
"expires_at": "2026-12-31T00:00:00.000Z"
}

The response includes the full key under keythis is the only time it is shown. Copy it immediately and store it in your secret manager.

{
"id": "f0e9d8c7-...",
"key_prefix": "swk_a1b2c3d4",
"description": "Reporting integration",
"scopes": ["chat.completions"],
"expires_at": "2026-12-31T00:00:00.000Z",
"is_revoked": false,
"created_at": "2026-06-13T10:00:00.000Z",
"last_used_at": null,
"key": "swk_a1b2c3d4_0123456789abcdef0123456789abcdef"
}

Soft-revokes by id (the UUID, not the key value). Idempotent — revoking an already-revoked or unknown key returns 404.

DELETE /v1/tenant/api-keys/{id}
Authorization: Bearer <admin JWT>

Returns 204 No Content on success.

MethodPathCapabilityReturns
GET/v1/tenant/api-keysrbac.manageKey metadata (no secret)
POST/v1/tenant/api-keysrbac.manageCreated key including the full secret, once
DELETE/v1/tenant/api-keys/{id}rbac.manage204 (soft revoke)

The model field selects a published chat endpoint in your tenant (an endpoint exposed under a slug), not a raw model name. The endpoint must be enabled, or the call returns 404 with code: model_not_found.

Terminal window
curl https://api.superwise-chat.company.com/openai/v1/chat/completions \
-H "Authorization: Bearer swk_a1b2c3d4_0123456789abcdef0123456789abcdef" \
-H "Content-Type: application/json" \
-d '{
"model": "support-assistant",
"messages": [{"role": "user", "content": "What is your refund policy?"}],
"stream": false
}'

To discover the endpoints your key can address:

Terminal window
curl https://api.superwise-chat.company.com/openai/v1/models \
-H "Authorization: Bearer swk_a1b2c3d4_0123456789abcdef0123456789abcdef"

The embeddable chat bubble (/v1/embed/*) authenticates with a per-tenant embed key in the X-Embed-Key header. Because the widget runs on customer websites, this surface allows cross-origin requests.

POST /v1/embed/sessions HTTP/1.1
X-Embed-Key: <tenant embed key>
Idempotency-Key: 7c1a...
Content-Type: application/json

An invalid or revoked embed key returns 401. Creating a session requires an Idempotency-Key. The embed key is configured per tenant by an administrator; it is not the same as an swk_ API key.

Posting an external alert into a conversation (POST /v1/webhooks/{channel_id}) is authenticated by an HMAC signature rather than a token. When you register a channel you receive a secret once; sign the raw request body with it and send the result in X-Webhook-Signature.

POST /v1/webhooks/{channel_id} HTTP/1.1
X-Webhook-Signature: <hmac-sha256-hex of the raw body>
Content-Type: application/json

A missing or invalid signature returns 401. See the webhooks guide (linked below) for the full registration flow and signing details.

StatusMeaningCommon cause
400Bad requestMalformed body, or scopes empty on key create
401UnauthenticatedMissing/invalid JWT, swk_ key, embed key, or webhook signature; expired key
403ForbiddenAuthenticated, but lacks the required capability (e.g. rbac.manage)
404Not foundResource missing, or it belongs to another tenant; unknown OpenAI endpoint slug
429Rate limitedOver the per-tenant or per-key limit; retry after X-RateLimit-Reset

The Product API returns errors as problem+json ({ type, title, status, detail, request_id }) at the framework layer; some handlers return a flatter { error, message }. The OpenAI-compatible surface returns errors in OpenAI’s shape: { "error": { "message": "...", "type": "invalid_request_error", "code": "invalid_api_key" } }.

  • Keep keys secret. Treat swk_ keys, embed keys, and webhook secrets like passwords. Store them in a secret manager, never in client-side code or version control.
  • Rotate on a schedule and revoke immediately on suspected compromise. A revoked swk_ key stops validating right away.
  • One token type per surface. A JWT never works on /openai/v1; an swk_ key never works on /v1.
  • Rate limits apply per surface. The OpenAI-compatible API is limited per key; the Product API per tenant. Watch X-RateLimit-Remaining and X-RateLimit-Reset.