> ## Documentation Index
> Fetch the complete documentation index at: https://docs.billingos.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Session tokens

> Create and manage session tokens for authenticating customers.

## createSessionToken

Create a session token to authenticate a customer with the React SDK.

```typescript theme={null}
const { sessionToken, expiresAt } = await billing.createSessionToken({
  externalUserId: "user_123",
  email: "user@example.com", // recommended
  expiresIn: 3600,
});
```

### Parameters

| Name                     | Type                  | Required            | Description                                                                                                                                    |
| ------------------------ | --------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `externalUserId`         | `string`              | Yes                 | Your user's unique ID from your database                                                                                                       |
| `email`                  | `string`              | No, but recommended | Your user's email. Lets BillingOS lazy-bind imported Stripe customers on first session. See [Migrating from Stripe](/guides/stripe-migration). |
| `externalOrganizationId` | `string`              | No                  | Organization ID for B2B scenarios                                                                                                              |
| `expiresIn`              | `number`              | No                  | Token lifetime in seconds (60–86400, default: 3600)                                                                                            |
| `allowedOperations`      | `string[]`            | No                  | Scope the token to specific operations                                                                                                         |
| `metadata`               | `Record<string, any>` | No                  | Additional metadata (IP, user agent, etc.)                                                                                                     |

### Response

```typescript theme={null}
{
  sessionToken: "bos_session_test_abc123...",
  expiresAt: Date,        // Token expiration timestamp
  unresolvedCustomers?: number  // Count of imported customers still awaiting bind
}
```

The `unresolvedCustomers` field is populated when you have imported customers from Stripe that haven't been bound yet. The SDK uses it to surface a one-time `console.warn` if you're issuing tokens without `email`.

## revokeSessionToken

Revoke a previously created session token.

```typescript theme={null}
await billing.revokeSessionToken("token_id_here");
```

## Token format

Session tokens are prefixed based on your API key environment:

| API key     | Token prefix         | Routes to      |
| ----------- | -------------------- | -------------- |
| `sk_test_*` | `bos_session_test_*` | Sandbox API    |
| `sk_live_*` | `bos_session_live_*` | Production API |

The React SDK reads this prefix and routes requests to the correct API automatically.

## Next.js example

```typescript app/api/billingos-session/route.ts theme={null}
import { BillingOS } from "@billingos/node";
import { getServerSession } from "next-auth";

const billing = new BillingOS({
  secretKey: process.env.BILLINGOS_SECRET_KEY!,
});

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

  if (!session?.user?.id) {
    return Response.json({ error: "Unauthorized" }, { status: 401 });
  }

  const { sessionToken, expiresAt } = await billing.createSessionToken({
    externalUserId: session.user.id,
    email: session.user.email, // recommended
    expiresIn: 3600,
  });

  return Response.json({ sessionToken, expiresAt });
}
```

## Security notes

* Tokens are short-lived (default: 1 hour)
* Each token is scoped to a single customer
* Tokens are verified on every API call
* Expired tokens are automatically rejected
* **Always authenticate the user** before creating a token
