Authentication
Bearer API keys, anti-abuse, and signup flows
API key format
API keys are 32-character base64url tokens prefixed bcapi_ (43 characters
total). Pass via the Authorization header on every request:
Authorization: Bearer bcapi_<32-char-base64url-token>Keys are hashed server-side with HMAC-SHA-256 + server pepper. The plaintext is shown only once at signup or key creation — store it in your secrets manager immediately. Lost keys cannot be recovered, only revoked + replaced.
Two signup flows
BuildCalc API supports both human and AI-agent signup. Both require a payment method on file (anti-abuse — see below).
Programmatic flow (AI agents)
POST /v1/account/signup
Content-Type: application/json
{
"email": "[email protected]",
"payment_method_id": "pm_..." ← Stripe PaymentMethod ID
}No Turnstile required. Stripe's fraud-detection on the card-on-file is the anti-abuse layer — duplicate / fraudulent cards are rejected at customer creation time.
Browser flow (humans)
POST /v1/account/signup
Content-Type: application/json
{
"email": "[email protected]",
"turnstile_token": "0....", ← Cloudflare Turnstile token
"setup_intent_id": "seti_..." ← Stripe SetupIntent ID
}Use Cloudflare Turnstile (free) + Stripe Elements to create the SetupIntent in the browser. Both layers required for the browser flow.
Why payment method on file from day 1
Even on the Free tier (1000 calls/mo, 10 RPM), every signup attaches a Stripe customer with a verified payment method. This blocks the bulk-signup-abuse vector without rate-limiting good-faith AI agents.
Upgrade triggers automatic Stripe billing — no second card-collection step.
Tiers + limits
| Tier | Monthly quota | RPM limit | Burst | Monthly price | Overage |
|---|---|---|---|---|---|
| Free | 1,000 calls | 10 | 20 | $0 | Hard cap (429s past quota) |
| Starter | 25,000 calls | 60 | 120 | $49 | $0.04 / call past quota |
| Growth | 250,000 calls | 300 | 600 | $249 | $0.02 / call past quota |
| Enterprise | Custom (default 10M) | Custom (default 2,000) | Custom | $1,500+ | Negotiated |
Pricing is set in Stripe; numbers above mirror the live Stripe products on the BuildCalc API account (TEST mode today; LIVE mode at LLC + banking formation completion).
Live tier + usage — see Usage stats below.
Idempotency
Mutating endpoints (signup, key rotation) accept an Idempotency-Key header
per the IETF draft. Retry with the same key returns the cached response,
making mid-network-drop retries safe.
POST /v1/account/signup
Idempotency-Key: 5f8a2c3e-...Errors
All errors are RFC 7807 problem+json:
{
"type": "https://docs.buildcalcapi.dev/errors/401",
"title": "Unauthorized",
"status": 401,
"detail": "Missing or invalid Authorization header. Use 'Bearer bcapi_...'.",
"instance": "/v1/calc/concrete/yards",
"request_id": "..."
}Self-service billing
curl -X POST https://api.buildcalcapi.dev/v1/account/portal \
-H "Authorization: Bearer bcapi_..." \
-d '{"return_url": "https://example.com/dashboard"}'Returns a Stripe Customer Portal session URL where the user can update card, view invoices, change plan, or cancel. No card data ever touches our servers.
Account management
All endpoints below take the calling key's Bearer token and act on the
customer (identified by owner_email on the key). Use them from scripts,
the mini-dashboard at /dashboard, or whatever client you wire up.
Usage stats
GET /v1/account/usage
curl https://api.buildcalcapi.dev/v1/account/usage \
-H "Authorization: Bearer bcapi_..."{
"api_key_prefix": "bcapi_abcd",
"tier_id": "starter",
"period_start": "2026-05-01T00:00:00+00:00",
"period_end": "2026-06-01T00:00:00+00:00",
"requests_used": 4218,
"requests_overage": 0
}The current calendar month is the billing period. requests_overage counts
calls past the tier's monthly quota — billed at the per-call overage rate
on the next Stripe invoice.
List your API keys
GET /v1/account/api-keys
curl https://api.buildcalcapi.dev/v1/account/api-keys \
-H "Authorization: Bearer bcapi_..."{
"keys": [
{
"id": "9b1c…",
"key_prefix": "bcapi_abcd",
"tier_id": "starter",
"created_at": "2026-05-12T18:04:21.117892+00:00",
"revoked_at": null,
"last_used_at": "2026-05-18T16:01:09.482371+00:00"
}
],
"total": 1
}Only metadata is returned — the plaintext token is never recoverable after signup or key creation. Sort order is most-recent-first.
Create another API key
POST /v1/account/api-keys
curl -X POST https://api.buildcalcapi.dev/v1/account/api-keys \
-H "Authorization: Bearer bcapi_..." \
-H "Idempotency-Key: $(uuidgen)"{
"api_key": "bcapi_<32-char-base64url>",
"key_prefix": "bcapi_xyz1",
"tier": "starter",
"message": "Save your API key now. It cannot be retrieved later."
}The new key inherits the calling customer's tier and Stripe subscription
— usage on it counts against the same monthly quota. The plaintext is
shown once; store it immediately. The endpoint is Idempotency-Key-
aware (recommended) so retries don't create duplicate keys.
Revoke an API key
DELETE /v1/account/api-keys/{key_id}
curl -X DELETE \
https://api.buildcalcapi.dev/v1/account/api-keys/9b1c0e6a-… \
-H "Authorization: Bearer bcapi_..." \
-H "Idempotency-Key: $(uuidgen)"{ "status": "revoked", "key_id": "9b1c0e6a-…" }Soft-revoke — sets revoked_at on the row, future requests return 401.
Owner-only: revoking someone else's key returns 404. Replays via the same
Idempotency-Key return the cached response. A key id can be found via
GET /v1/account/api-keys above.