Authentication
Every Cobuntu API request authenticates with an API key in the
X-API-Key header. There's no OAuth flow yet (planned for v2 — see
Versioning below).
curl https://api.cobuntu.com/api/v1/communities/my-community/events \
-H "X-API-Key: pk_live_..."Two key types
Per community, you can generate two flavors of keys:
| Type | Prefix | Scope cap | Use from |
|---|---|---|---|
| Publishable | pk_live_… | READ_PUBLIC only | Browser, server, anywhere |
| Secret | sk_live_… | Any scope (incl. write + admin) | Server only — never ship in browser bundles |
Stripe's pk_* / sk_* model, on purpose — the mental model
should transfer directly. If you've used Stripe API keys before,
you know what to do.
Publishable keys
- Auto-provisioned per community via
GET /api/communities/{tag}/publishable-key(no auth required, the response IS the key). - Browser-safe — meant to be embedded in client-side JS, widgets, mobile apps.
- Capped at
READ_PUBLICscope: list events / articles / products / members / segments, read public details. No write access ever. - Rate limit: 100 req/s per key.
Secret keys
- Generated in cobuntu-admin → Integrations → API Keys (admin permissions required).
- Server-only. The key is shown once at creation time — store it in a secret manager (Vercel env, AWS Secrets Manager, etc.). If lost, revoke + regenerate.
- Can carry any scope:
READ_PUBLIC,WRITE_MEMBERS,WRITE_SALES,WRITE_BROADCASTS,ADMIN. - Pick the narrowest scope set that works for your use case. A webhook receiver that just calls
application.approveonly needsWRITE_MEMBERS, notADMIN. - Rate limit: 50 req/s per key.
Scopes
Five scopes determine what a key can do:
| Scope | Grants |
|---|---|
READ_PUBLIC | List/get public-readable resources: events, articles, products, members, atlas hotspots, segments (the public list + form schema) |
WRITE_MEMBERS | Submit segment forms, accept rules, kick/ban members, approve/reject applications |
WRITE_SALES | RSVP for free events, future checkout flows for paid events |
WRITE_BROADCASTS | Send one-shot email broadcasts (rate-limited 5 per 24h per community) |
ADMIN | All of the above + admin-only operations like editing segment pricing |
ADMIN satisfies every other scope's check — an admin key can hit any endpoint a narrower key could. Use it sparingly; it bypasses every guardrail.
Key rotation
When (not if) a key leaks:
- cobuntu-admin → Integrations → API Keys → Revoke the leaked key. Effective immediately — all subsequent requests with that key return 401.
- Generate a new key with the same scopes. Copy it.
- Update your secret manager / env vars with the new key.
- Redeploy / restart any service holding the old key.
There's no overlap window for rotation — when you revoke, the old key is dead. Plan a deploy with the new key first, then revoke.
Common 401 / 403 mistakes
401 API key required — the X-API-Key header is missing or empty. Some HTTP clients drop custom headers when following redirects; check that.
401 Invalid API key — the key string is wrong (typo, truncated, expired). Compare against what's in cobuntu-admin.
403 API key missing required scope: WRITE_MEMBERS — the key exists and is valid, but doesn't carry the scope this endpoint needs. The response body includes grantedScopes so you can see what the key DOES carry. Either generate a key with the needed scope or use an ADMIN key.
403 API key does not have access to this community — the key belongs to a different community than the URL's :communityTag. Each key is scoped to one community; cross-community calls are blocked.
Buyer identity headers
Some endpoints behave differently when the caller can identify the buyer on whose behalf the request is being made. Member pricing, attendance lookups, buyer self-service (cancel / refund / leave) — all of these need to attribute the action to a specific community member.
The API key alone is not a buyer identity. It's your community-scoped credential; every authenticated buyer hits the same key. To attribute a request to a specific buyer, forward one of two additional headers:
X-Cobuntu-Auth-Token
The value of the cobuntu_auth_<tag> cookie set by Cobuntu's login flow. Use this when your customer apex (belaescala.com, foodieslx.com, etc.) is hosted as a reverse-proxy under Cobuntu's infrastructure and the buyer has logged in through the standard /login round-trip — the cookie sits on the apex host, your server-side code reads document.cookie, and you forward the value as the header.
The backend verifies the JWT and checks for an ACCEPTED membership in the URL's community before trusting it. Without that membership check, an authed member of community A could be silently treated as a buyer on community B's checkout; the bind keeps community boundaries intact.
Silent on failure — invalid / expired / cross-community tokens fall through to anonymous. Member pricing returns null instead of the discount; buyer self-service endpoints return 401.
X-Cobuntu-Member-Token
The SSO-minted member token from Cobuntu's session-bridge handshake. This is the path for fully off-apex integrations (a Lovable / Webflow / Vite SPA hosted on your-own-domain.com with no shared cookie surface). The flow:
- Your app calls
https://<community-tag>.cobuntu.com/sso/member-check?return=<your-url>when the buyer arrives. - Cobuntu round-trips the buyer through SSO and redirects back with a URL fragment:
your-url#cobuntu_session=<token>. - Your client-side code captures the fragment, persists the token in
sessionStorage, and forwards it asX-Cobuntu-Member-Tokenon every authed call until the buyer logs out.
The token's claims include the community id it was minted for — calls against any other community get the silent-anonymous fallback.
Token lifetime is currently 1 hour. Re-handshake when expired (the buyer is bounced through SSO again, fragment captured again).
Bela-escala-hub's cobuntuApi.ts (opens in a new tab) is the canonical reference integration — its captureMemberTokenFromUrl + headers() helper is what every off-apex SPA does in practice.
Which header, when
| Integration type | Cookie reachable? | Use which |
|---|---|---|
| Customer apex reverse-proxied through Cobuntu | yes (document.cookie) | X-Cobuntu-Auth-Token |
Customer apex with cobuntu.com SSO subdomain | yes (post-login redirect) | X-Cobuntu-Auth-Token |
| Fully off-apex SPA (Vite, Webflow, Lovable) | no | X-Cobuntu-Member-Token (SSO handshake) |
| Server-side only (no buyer in the loop) | n/a | Neither — request is anonymous, member pricing won't apply |
You can forward both; the backend tries X-Cobuntu-Auth-Token first, then falls back to X-Cobuntu-Member-Token. Same anonymous-fallback semantics on either failure.
Guest tokens — different mechanism
Guests (email-only, no Cobuntu account) don't have a member identity. For buyer self-service (cancel, refund) on guest attendances, the buyer identifies themselves with a signed MagicLink token that Cobuntu emails them at registration time. See Magic-link tokens for guests in the events reference.
Authorization: Bearer fallback
The legacy Authorization: Bearer <key> header also works, for compatibility with libraries that auto-add it (axios, supertest, some webhook SDKs):
curl https://api.cobuntu.com/api/v1/communities/my-community/events \
-H "Authorization: Bearer pk_live_..."Both header names accept the same key. Prefer X-API-Key for new code — it's the documented contract.
Versioning
API keys are forever-stable across /api/v1/*. Even when /api/v2/* ships (a future major version), your v1 keys keep working against v1 indefinitely — both versions coexist for at least 12 months after v2 GA.
Future plans (v2, not landing yet):
- OAuth 2.0 flow for "Sign in with Cobuntu" + third-party apps
- Per-user tokens (today's keys are per-community, not per-user)
- Token introspection endpoint