Skip to main content

Overview

Client Tokens allow you to call Limitry APIs directly from browsers and mobile apps without exposing your API key. They are short-lived, scoped tokens created by your backend.
Client tokens use the /client API endpoints, which are separate from the server-side /v1 endpoints.

How It Works

  1. User visits your app — Your frontend needs to check usage or display quota information
  2. Your backend creates a token — Using your API key, call POST /v1/client-tokens with publicMetadata and serverContext
  3. Token sent to browser — Your backend returns the token to the frontend
  4. Browser calls Client API — Use the token to call /client/limits/check or /client/events/summary

Creating Client Tokens

Create tokens from your backend using your API key:
import Limitry from '@limitry/sdk';

const limitry = new Limitry();

// Create a client token for the current customer
const { token } = await limitry.clientTokens.create({
  // Public metadata - exposed via GET /client/token
  publicMetadata: {
    customerId: 'cust_123',
    plan: 'pro'
  },
  // Server context - only accessible to handlers, never exposed to client
  serverContext: {
    internalId: 'int_456',
    creditLimit: 1000
  },
  ttlSeconds: 3600 // 1 hour (default). Max: 86400 (24 hours)
});

// Return token to your frontend
res.json({ token });

Payload: publicMetadata and serverContext

Tokens support two payloads:
TypeDescriptionAccessible To
publicMetadataPublic dataClient (via GET /client/token) and handlers
serverContextPrivate dataHandlers only — never exposed to client
Public metadata (publicMetadata) — Use for data the client needs to see:
FieldDescription
customerIdRequired. The customer to check usage for
planCustomer’s subscription tier (for UI display)
Server context (serverContext) — Use for sensitive server-side data:
FieldDescription
internalIdInternal database ID
creditLimitCredit limit (for enforcement)
permissionsDetailed permission flags
Both payloads are trusted and cannot be tampered with by the client. Use serverContext for any data you don’t want exposed to browsers. The customerId in the public metadata determines whose usage is returned.

Using Client Tokens

In the Browser

Once you have a token, use it to call the Client API:
// Fetch token from your backend
const { token } = await fetch('/api/auth/limitry-token').then(r => r.json());

// Check limits before making a request
const response = await fetch('https://api.limitry.com/client/limits/check', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  }
});

const { allowed, remaining } = await response.json();

if (!allowed) {
  showRateLimitMessage();
}

Displaying Usage to Users

A common use case is showing users their current usage:
// Get events summary for the customer
const response = await fetch('https://api.limitry.com/client/events/summary', {
  headers: {
    'Authorization': `Bearer ${token}`
  }
});

const summary = await response.json();
// Display usage based on summary.usage.totalEvents and summary.usage.values

With the Client SDK

import { LimitryClient } from '@limitry/client';

const client = new LimitryClient({ clientToken: token });

// Check if action is allowed
const result = await client.checkLimits();
if (result.allowed) {
  // Proceed with the operation
}

// Record an event
await client.recordEvent({
  eventType: 'api.call',
  values: { count: 1 }
});

// Get events summary
const summary = await client.getEventsSummary('day');

Client API Endpoints

Client tokens can only access these endpoints:
EndpointDescription
GET /client/tokenRetrieve the token (projectId + publicMetadata)
POST /client/limits/checkCheck limits for the customer
POST /client/events/recordRecord an event
GET /client/events/summaryGet events summary for the customer
Client tokens cannot access management endpoints like creating limits, viewing other customers, or modifying meters.

Token Lifecycle

Expiration

Client tokens expire after the specified duration (default: 1 hour). When a token expires, the client receives a 401 Unauthorized error and should request a new token from your backend.

Revocation

You can revoke a token before it expires:
await limitry.clientTokens.revoke('ct_abc123');

Best Practices

Use the default 1-hour expiration or shorter. This limits the window if a token is compromised.
Don’t pre-generate tokens. Create them when the user needs to check usage or limits.
The customerId in context determines whose usage is returned. Always set this to the authenticated user’s customer ID.
Always authenticate users on your backend before creating a client token for them.

Security Model

AspectAPI KeyClient Token
Where to useServer onlyBrowser/mobile
LifespanUntil revokedShort-lived (hours)
PermissionsFull project accessClient API only
Created byDashboardYour backend via API
ContainsProject IDProject ID + customerId

Use Cases

Usage Dashboard Widget

Show users their current usage in your app:
const summary = await client.getEventsSummary('month');

return (
  <UsageCard>
    <h3>API Usage</h3>
    <p>Total Events: {summary.usage.totalEvents}</p>
    <p>Values: {JSON.stringify(summary.usage.values)}</p>
  </UsageCard>
);

Pre-flight Limit Check

Check before expensive operations:
const result = await client.checkLimits();

if (!result.allowed) {
  const exceededLimit = result.limits.find(l => l.exceeded);
  showMessage(`Limit exceeded: ${exceededLimit?.name}. Resets at ${new Date(exceededLimit?.reset * 1000)}`);
  return;
}

// Proceed with the operation
await generateImage();

// Record the event
await client.recordEvent({
  eventType: 'image.generated',
  values: { count: 1 }
});

Next Steps