Skip to main content

Overview

Client tokens allow your frontend applications to call Limitry APIs directly without exposing your API key. They are short-lived, scoped tokens created by your backend.

Create a Client Token

Generate a token for a specific customer:
import Limitry from '@limitry/sdk';

const client = new Limitry();

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

console.log(`Token: ${result.token}`);

Payload: publicMetadata and serverContext

Tokens support two payloads:
const result = await client.clientTokens.create({
  // Public metadata - client can read via GET /client/token
  publicMetadata: {
    customerId: "cust_123",  // Required: determines whose usage is returned
    plan: "pro",             // Optional: for UI display
    features: ["chat", "api"] // Optional: custom data
  },

  // Server context - never exposed to client
  serverContext: {
    internalId: "int_456",   // Internal references
    creditLimit: 1000,       // Sensitive limits
    permissions: ["read"]    // Access control
  }
});
TypeDescriptionAccessible To
publicMetadataPublic dataClient (via GET /client/token) and your handlers
serverContextPrivate dataYour handlers only - never exposed to client

Token Expiration

Set how long the token is valid:
// Short-lived token (recommended)
const result = await client.clientTokens.create({
  publicMetadata: { customerId: "cust_123" },
  ttlSeconds: 3600  // 1 hour
});

// Longer-lived token (use sparingly)
const result = await client.clientTokens.create({
  publicMetadata: { customerId: "cust_123" },
  ttlSeconds: 86400  // 24 hours (maximum)
});
Shorter TTLs are more secure. Use the default 1 hour unless you have a specific need for longer tokens.

Backend Endpoint Example

Create an endpoint that generates tokens for authenticated users:

Express

import express from 'express';
import Limitry from '@limitry/sdk';

const app = express();
const client = new Limitry();

app.post('/api/limitry-token', async (req, res) => {
  // 1. Authenticate the user (your auth logic)
  const user = await getAuthenticatedUser(req);
  if (!user) {
    return res.status(401).json({ error: 'Unauthorized' });
  }

  // 2. Create a client token for this user's customer
  const result = await client.clientTokens.create({
    publicMetadata: {
      customerId: user.customerId,
      plan: user.plan
    },
    serverContext: {
      userId: user.id
    },
    ttlSeconds: 3600
  });

  // 3. Return the token to the frontend
  res.json({ token: result.token });
});

Next.js API Route

// app/api/limitry-token/route.ts
import { NextResponse } from 'next/server';
import Limitry from '@limitry/sdk';
import { getServerSession } from 'next-auth';

const client = new Limitry();

export async function POST() {
  const session = await getServerSession();

  if (!session?.user) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }

  const result = await client.clientTokens.create({
    publicMetadata: {
      customerId: session.user.customerId,
      plan: session.user.plan
    },
    ttlSeconds: 3600
  });

  return NextResponse.json({ token: result.token });
}

Hono

import { Hono } from 'hono';
import Limitry from '@limitry/sdk';

const app = new Hono();
const client = new Limitry();

app.post('/api/limitry-token', async (c) => {
  const user = c.get('user'); // From your auth middleware

  if (!user) {
    return c.json({ error: 'Unauthorized' }, 401);
  }

  const result = await client.clientTokens.create({
    publicMetadata: {
      customerId: user.customerId,
      plan: user.plan
    },
    ttlSeconds: 3600
  });

  return c.json({ token: result.token });
});

Frontend Usage

Once your backend returns a token, use it in the browser:
// Fetch token from your backend
const { token } = await fetch('/api/limitry-token', {
  method: 'POST'
}).then(r => r.json());

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

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

if (!allowed) {
  showUpgradePrompt();
}

What Clients Can Do

Once the frontend has a token, it can call these Client API 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 usage summary
Client tokens cannot access management endpoints like creating limits, viewing other customers, or modifying meters.

Best Practices

  1. Always authenticate users first - Create tokens only for authenticated users
  2. Keep TTLs short - Use 1 hour or less when possible
  3. Use serverContext for sensitive data - Never put sensitive info in public metadata
  4. Create tokens on-demand - Don’t pre-generate or cache tokens