API ReferenceGoing live
Going live
The pre-flight checklist before flipping from brainerce_test_* to brainerce_* in production. Skip steps at your own risk.
Before your first real customer transaction, walk this list end-to-end. Each item exists because someone shipped without it and paid for it later.
1. Keys and secrets
- Rotated the test key. Make sure no
brainerce_test_*key is hard-coded anywhere — search your repo and CI/CD secret stores forbrainerce_test_before deploy. - Issued a live key with minimum scopes. Don't ship a wildcard. Pick exactly the scopes the integration needs (Resource locations).
- Stored the live key in a secret manager, not in
.envchecked into git. Doppler / 1Password / AWS SM / Vault — pick one. - Set an IP allowlist on the key (if your integration runs from fixed IPs). Lock down at the key, not the firewall — keys leak more than networks do.
2. Webhooks
- Subscribed to the events you actually need — not all of them. Each event adds a delivery your endpoint has to handle correctly. See the webhook event catalogue.
- Verification is in place — signature + replay window + constant-time compare. See Verify a webhook signature.
- Idempotency on your side — store
envelope.idand reject duplicates. Any non-2xx response is retried, not just 5xx: a400,404or409from your handler is retried the full 5 attempts and counts toward the circuit breaker exactly like a timeout. If you want a delivery dropped rather than retried, answer2xxand discard it yourself. - Reply fast. The dispatcher has a 10-second timeout. Reply with 2xx in under 2 seconds and queue the actual work async.
- You have a plan for the circuit breaker, because self-healing is slow and nothing resends for you. Ten failed delivery attempts — roughly two consecutive failing events, since each event is tried 5 times — open the circuit. It half-opens an hour later and lets the next event (plus any arriving in the few seconds before its result lands) through as a probe: a
2xxresumes delivery, anything else re-opens it for another hour, and becausefailureCountis not reset, one failed probe is enough. Events that happen meanwhile are recorded as Not sent in the endpoint's event log (up to 500 per endpoint, kept 7 days) but are never replayed automatically: once the endpoint works, resend them from the event log or withPOST /stores/{storeId}/webhook-subscriptions/{id}/replay-missed(25 per call, oldest first). A failed event (five attempts used) is not queued again either; resend it withPOST .../redeliver. Alert oncircuitOpen: trueand onmissedCount(see §9) and treat it as a page, not a warning — waiting for the probe costs you an hour with nothing sent, and a Not sent backlog older than 7 days is no longer counted or replayed in bulk (the rows stay in the event log, where you can still resend them withPOST .../redeliver). See Resending events. - Resends are safe on your side. A resent event keeps its original event id and carries
X-Brainerce-Redelivery: true; dedupe on the id in your own inbox, and on a business key (the order id) wherever a third-party API is called, because event-id dedupe protects only your own inbox. - Tested with the dashboard "Send test event" button — confirmed signature verification passes against a real Brainerce-signed payload. Note this sends a fresh test event; to re-send a past delivery, use Resend on that row of the event log (test events themselves cannot be resent). On an endpoint with custom headers or a body template a test is a real call to the destination, so the API answers
400unless you sendconfirmLiveCall: true; usePOST .../previewto see the body without sending.
3. Idempotency on mutations
- Every
POST/PATCH/DELETEretry includes anIdempotency-Key. Otherwise a network blip can double-charge, double-ship, or double-cancel. See Idempotency. - Idempotency keys are deterministic per logical operation — same key for same retry, different key for different orders.
-
POST /v1/checkout/{id}/completealways carries a key. It is required there — without one the call is a400, before the handler runs. - You have checked the unsupported list. Sixteen mutating
/v1/*routes ignore the header silently, includingPOST /v1/orders/{id}/shipments/app-label, which buys a real shipping label and bills your carrier account on every retry. Read Idempotency → Routes that do NOT support it and guard those calls yourself.
4. Rate limits
- You know your key's tier. A
brainerce_*key is on the per-key tiers — FREE 60, PRO 500, GROWTH 2000, ENTERPRISE 10000 req/min. (The 100 / 500 / 1000 numbers are marketplace-app installation tiers and do not apply to an API key.) - You have accounted for the global per-IP ceiling on top of that — 60 req/min and 1000 req/hour per IP apply to every request regardless of tier, and some storefront routes cap far lower. See Rate limits.
- You handle
429 Too Many Requestswith theRetry-Afterheader — don't hot-loop. NoteX-RateLimit-Resetis seconds remaining, not a Unix timestamp. - Burst protection on your side — if a CSV import wakes up 10,000 jobs, batch them so you stay under your tier. There is no burst grace; the bucket rejects at exactly the limit.
5. Inventory + stock
- Verify the stock the live store really holds. A test key and a live key act on the same store data (a test key is not a sandbox), so there is no separate test inventory to carry over, but a product created without a stock quantity has none and cannot be bought until you set one.
- Decided on
trackingModeper product.TRACKED(default) blocks oversells;UNLIMITEDaccepts any order (digital products, print on demand);DISABLEDmakes the product impossible to purchase. Get this wrong and you either oversell or never sell.
6. Payments
- Payment provider is in live mode — in the dashboard the provider's app (Apps → Installed) has Mode set to Live, not Test, and the sales channel itself is in
LIVEmode. - At least one full live transaction succeeded end-to-end before launch — your test, with a real card, $1 (you can refund).
- Refund flow tested in live mode — the provider-side refund settles and the refund on the order reaches
CAPTURED. - Webhook on
payment.failedwrites to your CRM / alerts. Failed payments are the #1 silent failure mode in production.
7. Email
- Email sending domain (DKIM/SPF) is verified in Brainerce email settings.
- Transactional templates customized — order-confirmation, shipping-notification, password-reset have your branding (not the default).
- From address is your domain, not
[email protected]. - Sent a test email to yourself for every event type your store will trigger.
8. Storefront
- The sales channel's domain is your production domain. Set it under Channels → your channel → Settings. A LIVE channel matches the request
Originagainst this field (host equality or a subdomain) and against the channel's "Additional allowed origins" list (exact origins, at most 5: use it for a preview URL you keep building from), so until the domain is right, browsers will get a 403 on every storefront call. An allowed origin never replaces the domain: a LIVE channel with no domain refuses every request. Note a LIVE channel also requires anOriginheader. Server code (SSR, Route Handlers, background jobs) sends none by default, so it is refused until you passoriginwhen you construct the client, derived from the incoming request so it matches the channel'sdomain; see Origin rules. Do not swap in an adminbrainerce_*key to get around it. - CSP headers in your storefront allow Brainerce + your payment provider domains. A strict CSP blocks the payment iframe silently, so build it with
buildStorefrontCsp({ nonce, apiOrigin })frombrainerce: itsframe-srccovers every payment host plus your store's API origin. If product descriptions use video embeds, also addhttps://www.youtube.com,https://www.youtube-nocookie.com, andhttps://player.vimeo.comtoframe-src, or the embeds render blank. - Cookie domain is the production domain (not
localhostor staging). - Custom domain SSL is provisioned and HSTS is set — Brainerce requires HTTPS on
webhookUrland OAuth callbacks. - On Vercel, the Vercel function region is pinned next to the Brainerce API. The default function region is
iad1(Washington, D.C.) and adds roughly 300 to 450 ms to every call a function makes to the API. For a store served from Europe set{ "regions": ["fra1"] }invercel.jsonor Project Settings → Functions → Function Region, then redeploy. (This is Vercel's setting, not a commerce region.) Public reads (products, categories) may call the API straight from the browser instead of through your own proxy. -
cartTokenis redacted from your logs. Guest cart writes carry the cart's session token as thecartTokenquery parameter, which is a credential for that one cart. Strip it in CDN, proxy and APM logs, including the Vercel function logs of a Backend-For-Frontend, and make sure any proxy of yours forwards the query string. See Cart ownership proof. - A
403 CART_ACCESS_DENIEDdoes not log the shopper out. It only means the guest cart's proof was missing; the SDK sends it for you. - You ran the behaviour check on a phone viewport.
node verify-storefront.mjs --url https://your-shop.example --viewport 390x844 --slow(fromhttps://brainerce.com/verify-storefront.mjs; needs Playwright) drives the real storefront and checks header navigation without a page reload, no "empty cart" flash, the loading and error states, quick taps, checkout waiting for a pending update, floating widgets not covering cart or checkout controls, and autocomplete. It never submits an order. Fix every FAIL before launch.
9. Observability
- Logs from your integration record the endpoint, and on errors the
timestampandpathfrom the error body. There is no request-id response header — neitherX-Request-IdnorX-Brainerce-Request-Idis set by the API, so generate your own correlation id client-side and log it alongside those two fields. That is what lets support find the request. - You have an alert on 5xx rate from Brainerce. If your integration starts seeing 5%+ 5xx, something is wrong (yours, ours, or upstream).
- Webhook circuit-breaker state is monitored. If your endpoint opens the circuit, you stop receiving events — silently. Check
GET /stores/{storeId}/webhook-subscriptions/{id}periodically forcircuitOpen: trueand for a growingmissedCount(events waiting as Not sent, kept 7 days), and alert. - A dashboard chart of API key usage exists (your side) — sudden spikes/drops are the first sign of a compromised key or a broken cron.
10. Data + GDPR
- Customer data export wired — for "deliver my data" requests under GDPR / CCPA.
GET /api/v1/customers/{id},GET /api/v1/customers/{id}/addressesandGET /api/v1/customers/{id}/orderscover the profile, addresses and order history. - Customer deletion has an owner. The
/v1API has no customer delete route. A customer is erased from the dashboard (Customers) or with the admin MCP tooldelete_customer: the customer row, addresses, saved payment tokens, closed inquiries, assistant chats and similar are removed, and email logs and consent records lose the address. Orders are not anonymised yet, so it is refused with409for any customer who has an order, an active recurring payment schedule, a paid loyalty membership that is still billing, a recorded loyalty membership charge or an open inquiry. The response body lists every blocker indetails.blockers. Check your own deletion procedure before live requests come in. - Marketing consent flag is respected —
customer.acceptsMarketing: falseshould never receive a marketing email. - Privacy policy + terms-of-service URLs in store settings point at live, signed-off legal pages.
11. Versioning
- You're calling
/api/v1/*paths, not internal/api/{module}ones. Internal paths can change without notice;/api/v1/*carries the versioning guarantee. - Someone owns reading the Changelog before each SDK bump. There is no deprecation response header to automate against —
X-Brainerce-Deprecationis not emitted — so the changelog and the dashboard banner are the whole early-warning system.
12. Rollback plan
- You can roll your storefront back to the previous Brainerce SDK version within 5 minutes — pinned to a major in package.json, prior version cached.
- You can disable a webhook subscription without redeploying — DELETE the subscription via the API, or toggle it in the dashboard.
- You can revoke a leaked API key in under 60 seconds — practiced once before launch.
13. Day 1 verification
After the first hour of live traffic, confirm:
- First real
order.createdarrived at your webhook and was processed - First real
payment.succeededsettled in the payment-provider dashboard - New shoppers are reaching your CRM.
customer.createdfires for a merchant-created customer and for a storefront, email-verified or OAuth signup. It does not fire for a guest checkout — those shoppers arrive onorder.created/checkout.completed, which carry the enrichedcustomer(best-effort: whendata.orderis missing, fetch the order byorderId). Confirm your handler is an upsert keyed oncustomerId: a guest who later registers produces acustomer.createdfor a customer you already have. See the event catalogue. - Your 5xx rate is < 1%
- Your webhook delivery success rate (in Brainerce dashboard) is > 99%
If any of these are red, your launch is degraded — fix before pushing more traffic.
Related
- Quickstart — first authenticated request
- Authentication — API keys, scopes, channel origins
- Idempotency — the retry-safe pattern
- Rate limits — your tier + recommended client behavior
- Verify a webhook signature — required reading
- Resource locations — which namespace each resource lives in
Pagination
How list endpoints page, sort, and filter results.
MCP server
The two Brainerce MCP (Model Context Protocol) servers. The public read-only docs server for coding agents (tools, endpoints, rate limits, env), and the Admin MCP for running a store (addresses, tool counts, which client uses which address).