Subscription API
Endpoints for managing your account profile, generating API keys, and initiating Stripe checkout sessions for subscription plans and credit pack top-ups. All endpoints on this page require a Cognito JWT except where noted.
Plans and credits
The credit allocation per plan:
| Plan | Credits on sign-up / renewal | Price |
|---|---|---|
| free | 10 (one-time on account creation) | Free |
| starter | 8 per month | $8/month |
| pro | 20 per month | $20/month |
| business | 40 per seat per month | $40/seat/month |
| credit-pack (top-up) | 5 credits per pack | $5 per pack |
GET /api/account/me
/api/account/me
JWT required
Returns the authenticated user's account profile, credit balance, current plan, and a list of their API key prefixes (not full keys).
Response (200 OK)
{
"user_sub": "cognito-sub-uuid",
"email": "user@example.com",
"plan": "starter",
"credits": 6,
"api_keys": [
{
"key_prefix": "tbo-ab12",
"created_at": "2026-03-01T10:00:00Z"
}
]
}
Error responses
| Status | Condition |
|---|---|
| 401 | Missing or invalid JWT |
| 404 | Account record not found (user has not completed sign-up trigger) |
POST /api/account/apikey
/api/account/apikey
JWT required
Generates a new tbo- prefixed API key for the authenticated user. The full key is returned only in this response; it cannot be retrieved again. The key is stored as a SHA-256 hash in DynamoDB.
Request body
No request body required. Send an empty JSON object or omit the body.
Response (200 OK)
{
"api_key": "tbo-a1b2c3d4e5f6...",
"key_prefix": "tbo-a1b2",
"created_at": "2026-03-31T12:00:00Z"
}
Copy the full API key from this response immediately. It is shown once and cannot be retrieved. If lost, generate a new key.
POST /api/checkout
/api/checkout
JWT required
Creates a Stripe Checkout Session for subscribing to a plan. Returns a Stripe checkout URL. Redirect the user to this URL to complete payment.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
plan | string | Yes | One of: starter, pro, business |
Response (200 OK)
{
"checkout_url": "https://checkout.stripe.com/c/pay/...",
"session_id": "cs_..."
}
Error responses
| Status | Condition |
|---|---|
| 400 | Invalid or missing plan |
| 401 | Missing or invalid JWT |
POST /api/topup
/api/topup
JWT required
Creates a Stripe Checkout Session for purchasing a credit pack top-up. Each credit pack costs $5 and adds 5 credits to the account. Returns a Stripe checkout URL.
Request body
No fields required. The top-up amount is fixed at one credit pack per session. Send an empty JSON object.
Response (200 OK)
{
"checkout_url": "https://checkout.stripe.com/c/pay/...",
"session_id": "cs_..."
}
POST /api/stripe-webhook
/api/stripe-webhook
HMAC-SHA256 webhook signature
Stripe webhook receiver. Verifies the webhook signature using HMAC-SHA256 with a 5-minute replay protection window. Handles the following Stripe events:
checkout.session.completed— credit account after successful paymentinvoice.paid— reset credits on monthly renewalcustomer.subscription.updated— sync plan changescustomer.subscription.deleted— downgrade to free plan
This endpoint is called by Stripe, not by users or CI pipelines. Idempotency is enforced via DynamoDB: each Stripe event ID is claimed atomically before processing.
Do not call this endpoint directly. Stripe will call it when subscription events occur.