Keys & Billing API
Create API Key
POST /v1/keysRequest Body
{
"name": "Production Key",
"expiresInDays": 90
}| Field | Type | Default | Description |
|---|---|---|---|
name | string | "Default" | Key name (1-100 chars) |
expiresInDays | number | - | Days until expiry (1-365). No expiry if omitted. |
Response 201
{
"id": "key_abc123",
"key": "plabs_sk_live_abc123...",
"name": "Production Key",
"expiresAt": "2026-06-21T00:00:00Z",
"message": "Save this key - it will not be shown again."
}DANGER
The raw API key is only returned once. Store it immediately in a secure location.
List Keys
GET /v1/keys?limit=20&cursor=key_xyzResponse 200
{
"data": [
{
"id": "key_abc123",
"name": "Production Key",
"prefix": "plabs_sk_live_abc1...",
"createdAt": "2026-03-21T00:00:00Z",
"expiresAt": "2026-06-21T00:00:00Z",
"lastUsedAt": "2026-03-21T12:00:00Z"
}
],
"nextCursor": null,
"hasMore": false
}The raw key value is never returned in list responses. Only the prefix is shown.
Revoke Key
DELETE /v1/keys/:idResponse 204
No content. The key is immediately invalidated.
Rotate Key
POST /v1/keys/:id/rotateCreates a new key and revokes the old one atomically.
Response 200
{
"id": "key_new123",
"key": "plabs_sk_live_new123...",
"name": "Production Key",
"message": "Save this key - it will not be shown again."
}Get Usage
GET /v1/usageReflects a call as soon as that call's response has returned — the API waits for the usage write before replying, so there is no polling delay.
breakdown reports each modality in the unit it is billed in: characters for TTS, minutes of audio for STT, tokens for LLM, queries for RAG.
Response 200
{
"tier": "pro",
"period": { "start": "2026-09-01T00:00:00.000Z", "end": "2026-09-30T23:59:59.999Z" },
"credits": {
"used": 12500,
"included": 200000,
"carryover": 0,
"limit": 200000,
"remaining": 187500,
"overageAllowed": true,
"overageRate": 0.0008,
"overageCredits": 0,
"overageCost": 0
},
"breakdown": {
"sttMinutes": 2000,
"ttsCharacters": 8000,
"ragQueries": 500,
"llmTokens": 2000
},
"requestCount": 3420
}A metered endpoint returns X-Credits-Used, X-Credits-Limit and X-Credits-Remaining when the call was charged against your credits. A call that runs on your own provider key is not charged and carries X-Usage-Bypassed: byok instead of the three credit headers. Every response carries X-Request-Id, which is the trace id for that call.
Get Subscription
GET /v1/billing/subscriptionResponse 200
{
"tier": "pro",
"tierDisplay": "Pro ($99/mo)",
"credits": {
"used": 12500,
"limit": 200000,
"remaining": 187500
},
"plan": {
"monthlyCredits": 200000,
"overageRate": 0.0008,
"carryoverMonths": 1
},
"stripeCustomerId": "cus_abc123",
"tierExpiresAt": "2026-04-21T00:00:00Z"
}Create Checkout Session
Redirect the user to Stripe Checkout to subscribe or upgrade.
POST /v1/billing/checkoutRequest Body
{
"tier": "pro",
"successUrl": "https://yourapp.com/billing/success",
"cancelUrl": "https://yourapp.com/billing/cancel"
}| Field | Type | Required | Description |
|---|---|---|---|
tier | string | yes | starter, pro, or scale |
successUrl | string | yes | Redirect URL on successful payment |
cancelUrl | string | yes | Redirect URL on cancellation |
Response 200
{
"url": "https://checkout.stripe.com/c/pay/...",
"sessionId": "cs_live_abc123"
}Billing Portal
Open the Stripe billing portal for subscription management, invoices, and payment methods.
POST /v1/billing/portalResponse 200
{
"url": "https://billing.stripe.com/p/session/..."
}