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 UUID
  • customer_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

  1. Keep secret keys server-side — Use backend minting, never expose secret keys
  2. Use short TTLs for sensitive apps — 1 hour is reasonable for high-security apps
  3. Handle expiration gracefully — Implement token refresh before expiry
  4. Log token issuance — Track which users get tokens for auditing

Next Steps