Customer Tokens
Customer tokens are short-lived bearer tokens that scope API access to a specific customer. They enable multi-tenant applications where customers make requests from frontends or mobile apps, with tier limits applied when the customer is subscribed.
When to Use Customer Tokens
Use customer tokens when:
- Customers need to call the AI API from your frontend
- Building mobile apps with AI features
- You want usage tracked and limited per customer
- You need per-customer tracking (tiered or tierless)
Use secret keys instead when:
- Making server-side API calls from your backend
- Running batch jobs or background processing
- Requests aren’t attributable to a specific customer
Token Minting (Backend Required)
Customer tokens are minted by your backend using a secret key. This is the supported flow for client apps.
sequenceDiagram
participant Client as Browser/Mobile
participant Backend as Your Backend
participant MR as ModelRelay
Client->>Backend: 1. Request token
Backend->>MR: 2. Mint token (secret key)
MR-->>Backend: Customer token
Backend-->>Client: 3. Return token
Client->>MR: 4. API request (bearer token)
MR-->>Client: Response
Backend Minting
Your backend mints a token with POST /api/v1/auth/customer-token, authenticating with a secret key in the X-ModelRelay-Api-Key header. Project scope is derived from the secret key. Do not include project_id in the request body—requests that include it are rejected.
Important: The customer must exist before minting a token. Minting for an unknown customer returns 403. Create the customer first with PUT /api/v1/customers (an idempotent upsert by external_id; see Customer Billing), for example when the user signs up.
curl -X POST https://api.modelrelay.ai/api/v1/auth/customer-token \
-H "X-ModelRelay-Api-Key: mr_sk_..." \
-H "Content-Type: application/json" \
-d '{
"customer_external_id": "user_42"
}'
{
"token": "eyJhbGciOi...",
"expires_at": "2026-10-16T12:00:00Z",
"expires_in": 604800,
"project_id": "…",
"customer_id": "…",
"customer_external_id": "user_42",
"tier_code": "free"
}
Return token and expires_at to your frontend.
Note: For managed billing projects, a customer without a subscription is assigned a tier when the first token is minted. Pass a non-paid tier_code to choose it; omit it to assign the project’s default Free tier. Paid tiers require checkout. Existing customers keep their current tier and tier_code is ignored. BYOB projects handle billing externally and never need tier_code.
Identifying Customers
Provide exactly one of:
customer_id— ModelRelay’s internal UUIDcustomer_external_id— Your own user identifier
Using customer_external_id is recommended since it maps to your user system.
Token Lifetime
| Setting | Default | Maximum |
|---|---|---|
| TTL | 7 days | 30 days |
Override the default with ttl_seconds:
{
"customer_external_id": "user_42",
"ttl_seconds": 3600
}
Shorter TTLs are more secure but require more frequent token refreshes.
Using Tokens
On the frontend, send the token as a bearer token:
const response = await fetch("https://api.modelrelay.ai/api/v1/responses", {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "claude-sonnet-5-5",
input: [{ role: "user", content: "Hello!" }],
}),
});
Refreshing Tokens
Expose an endpoint on your backend that mints a token for the signed-in user, and have your frontend call it before the current token’s expires_at:
// Backend: mint a token for the signed-in user
app.get("/api/token", async (req, res) => {
const r = await fetch("https://api.modelrelay.ai/api/v1/auth/customer-token", {
method: "POST",
headers: {
"X-ModelRelay-Api-Key": process.env.MODELRELAY_SECRET_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({ customer_external_id: req.user.id }),
});
const { token, expires_at } = await r.json();
res.json({ token, expires_at });
});
Token Response Fields
| Field | Type | Description |
|---|---|---|
token |
string | The JWT bearer token |
expires_at |
string | When the token expires (RFC 3339) |
expires_in |
number | Seconds until expiration |
project_id |
string | Project the token is scoped to |
customer_id |
string | Internal customer UUID |
customer_external_id |
string | Your customer identifier |
billing_profile_id |
string? | Billing profile UUID (managed billing only) |
tier_code |
string? | Customer’s tier, e.g. free or pro (managed billing with a subscription only) |
Security Considerations
Token Storage
- Store tokens in memory or short-lived browser storage (sessionStorage)
- Avoid localStorage for sensitive tokens
- Never expose secret keys to the frontend
Token Validation
Tokens are validated on every request:
- Signature verification (tamper-proof)
- Expiration check
- Customer and project scope enforcement
- Tier limits applied automatically
Best Practices
- Keep secret keys server-side — Use backend minting, never expose secret keys
- Use short TTLs for sensitive apps — 1 hour is reasonable for high-security apps
- Handle expiration gracefully — Implement token refresh before expiry
- Log token issuance — Track which users get tokens for auditing
Next Steps
- Authentication — API key types overview
- First Request — Make your first API call
- Streaming — Real-time response streaming