Authentication
AudienceGPT supports three authentication methods to cover dashboard users, server-to-server integrations, and client-side embedded widgets. Every API request must include valid credentials via one of these methods; unauthenticated requests receive a 401 Unauthorized response.
Authentication Methods
1. Clerk Sessions (Dashboard)
Browser-based authentication for dashboard users. Clerk manages session cookies automatically when users sign in through the AudienceGPT web interface.
- Transport: HTTP-only session cookie (set by Clerk)
- Use case: All dashboard interactions, admin operations, credential management
- Org scoping: The active Clerk organization determines the
orgIdfor all queries - Role-based permissions: Clerk org roles map to application roles (owner, admin, member, viewer) with granular permissions
Clerk sessions are required for operations that manage credentials, such as creating connections or managing API keys. API keys cannot perform these operations.
2. API Keys (txadv_ prefix)
Self-managed API keys for server-to-server integrations. Each key is scoped to an organization and can be restricted to specific permission scopes.
- Prefix:
txadv_ - Transport:
Authorization: Bearer txadv_...header - Max keys per org: 25
- Expiration: Optional expiration date (ISO 8601)
- Revocation: Immediate via the
/api/keysendpoint
curl -X POST https://app.audiencegpt.com/api/classify \
-H "Authorization: Bearer txadv_a8Kz3mN9pQ2wX..." \
-H "Content-Type: application/json" \
-d '{"messages": [{"role": "user", "content": "Classify: Tesla Model 3 buyers"}]}'
3. SDK Publishable Keys (pk_live_ / pk_test_ prefix)
Client-side keys for embedding AudienceGPT classification in consumer-facing applications. These keys are safe to expose in browser JavaScript because they are scoped to specific operations.
- Prefixes:
pk_live_(production),pk_test_(testing) - Transport:
Authorization: Bearer pk_live_...header - CORS: SDK endpoints return
Access-Control-Allow-Origin: *headers - Routes: All
/api/sdk/*endpoints accept SDK keys
const response = await fetch("https://app.audiencegpt.com/api/sdk/classify", {
method: "POST",
headers: {
"Authorization": "Bearer pk_live_x9Kz3mN9pQ2wX...",
"Content-Type": "application/json",
},
body: JSON.stringify({
messages: [{ role: "user", content: "Classify: organic skincare" }],
}),
});
Authorization Scopes
API keys and SDK keys can be restricted to specific scopes. When creating a key, you can specify which scopes to grant. If no scopes are specified, all scopes are granted by default.
| Scope | Description | Endpoints |
|---|---|---|
classify | Classify topics, analyze briefs, check duplicates | /api/classify, /api/analyze-brief, /api/topics/generate-matrix |
topics:read | Read topics, stats, facets, history, catalog | /api/topics (GET), /api/topics/stats, /api/topics/facets, /api/topics/catalog |
topics:write | Create, update, delete topics; run imports and reclassify | /api/topics (POST/DELETE), /api/import, /api/topics/reclassify |
export | Export topics as CSV or JSON | /api/export |
sync | Manage connections, run syncs | /api/connections, /api/connections/*/sync/* |
activations | Manage segment activations, push to DSPs | /api/activations, /api/connections/*/push/* |
mappings:read | Read platform ID mappings | /api/sdk/mappings |
API Key Management
Create an API Key
Requires a Clerk session with api_keys:manage permission.
POST /api/keys
Request body:
{
"name": "Production Integration",
"scopes": ["classify", "topics:read", "topics:write"],
"expiresAt": "2027-01-01T00:00:00Z"
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Human-readable name (max 100 characters) |
scopes | string[] | No | Permission scopes (defaults to all scopes) |
expiresAt | string | No | ISO 8601 expiration date (must be in the future) |
Response (201):
{
"record": {
"id": "key_01hy...",
"orgId": "org_2abc...",
"createdBy": "user_2xyz...",
"name": "Production Integration",
"keyPrefix": "txadv_a8Kz3m",
"scopes": ["classify", "topics:read", "topics:write"],
"expiresAt": "2027-01-01T00:00:00.000Z",
"lastUsedAt": null,
"revokedAt": null,
"createdAt": "2026-02-25T10:00:00.000Z"
},
"plaintext": "txadv_a8Kz3mN9pQ2wXyZ5bC7dE..."
}
The plaintext key is only returned once at creation time. Store it securely -- it cannot be retrieved again.
List API Keys
GET /api/keys
Response (200):
[
{
"id": "key_01hy...",
"orgId": "org_2abc...",
"createdBy": "user_2xyz...",
"name": "Production Integration",
"keyPrefix": "txadv_a8Kz3m",
"scopes": ["classify", "topics:read", "topics:write"],
"expiresAt": "2027-01-01T00:00:00.000Z",
"lastUsedAt": "2026-02-25T12:00:00.000Z",
"revokedAt": null,
"createdAt": "2026-02-25T10:00:00.000Z"
}
]
Revoke an API Key
DELETE /api/keys
Request body:
{
"id": "key_01hy..."
}
Response (200):
{
"revoked": true
}
SDK Key Management
Create an SDK Key
POST /api/sdk-keys
Request body:
{
"name": "Website Widget",
"mode": "live",
"scopes": ["classify", "topics:read"]
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Human-readable name (max 100 characters) |
mode | string | No | "live" (default) or "test" |
scopes | string[] | No | Permission scopes (defaults to all scopes) |
Response (201):
{
"record": {
"id": "sdk_01hy...",
"orgId": "org_2abc...",
"name": "Website Widget",
"keyPrefix": "pk_live_",
"scopes": ["classify", "topics:read"],
"revokedAt": null,
"createdAt": "2026-02-25T10:00:00.000Z"
},
"plaintext": "pk_live_x9Kz3mN9pQ2wXyZ5bC..."
}
List SDK Keys
GET /api/sdk-keys
Revoke an SDK Key
DELETE /api/sdk-keys
Request body:
{
"id": "sdk_01hy..."
}
Auth Resolution Order
When a request arrives, the authentication system resolves credentials in this order:
- Check
Authorizationheader forBearer txadv_...-- if present, hash the key and look up in theapi_keystable - Check
Authorizationheader forBearer pk_...-- SDK routes resolve from thesdk_keystable - Fall back to Clerk session -- check for a valid Clerk session cookie with an active organization
If none of these succeed, the request is rejected with 401 Unauthorized.
The optional X-Workspace-Id header lets you scope requests to a specific workspace within your organization. Pass it alongside any authentication method.
Error Responses
401 Unauthorized
Returned when no valid credentials are provided or the key is expired/revoked.
{
"error": "Unauthorized"
}
403 Forbidden
Returned when credentials are valid but the key lacks the required scope.
{
"error": "Forbidden"
}
Scope Insufficient (API Key)
When an API key is valid but lacks a required scope, the system returns 401 (the scope check failure is opaque to prevent information leakage about key validity).
TypeScript Example
// Server-side: API key authentication
const API_KEY = process.env.AUDIENCEGPT_API_KEY; // txadv_...
async function classifyTopic(topicName: string) {
const response = await fetch("https://app.audiencegpt.com/api/classify", {
method: "POST",
headers: {
"Authorization": `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
messages: [
{ role: "user", content: `Classify: ${topicName}` },
],
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error);
}
return response.json();
}
Next Steps
- Classify API -- Use your API key to classify topics
- SDK Integration -- Embed classification in client-side apps
- Topics API -- Manage your topic library
- Error Codes -- Complete error reference