Authentication

API keys, scopes, rate limits and the error format of the Sway Public API.

Every request to the Sway Public API is authenticated with an API key sent as a Bearer token:

curl https://www.sway.events/api/v1/artists \
  -H "Authorization: Bearer sway_sk_YOUR_KEY"

Keys start with the sway_sk_ prefix. The key identifies your crew — there is no tenant parameter anywhere in the API.

Keep your key server-side. Only call the API from your own backend. Never ship the key to a browser, a mobile app or any client-side code — anyone who can read your pages could extract it and read your data.

Key lifecycle

Keys are managed in Crew admin → API (Studio and Roster plans).

ActionBehaviour
CreateChoose a name, scopes and an optional expiry (30, 90 or 365 days, or never). The full key is displayed once — copy it immediately; afterwards only the prefix and last 4 characters are shown
RevokeImmediate and irreversible. Revoked keys receive 401 key_revoked on every request
ExpireOnce expires_at passes, requests receive 401 key_expired. Create a new key to continue
RotateCreate a new key, deploy it, then revoke the old one

If your crew's subscription lapses, all keys stop working with 403 subscription_required until the subscription is active again.


Scopes

Scopes are chosen at key creation. Read scopes gate resources; field-level visibility is determined by ownership (managed vs public), not by scopes.

ScopeGrants
read:profileGET /v1/me, GET /v1/crew
read:artistsRoster, artist detail, artist events
read:promotersManaged promoters and their events
read:eventsEvent detail, lineups, embedded venues
read:venuesVenue detail (public tier)
write:bookingsPOST /v1/booking-requests (opt-in at key creation)
write:checkoutPOST /v1/checkout-sessions — create paid ticket checkout sessions (opt-in)
write:checkout:freeAdditionally mint €0 / 100%-off ticket orders via POST /v1/checkout-sessions (higher-trust, opt-in)

The default template grants all read:* scopes and no write scope. A request without the required scope returns 403 missing_scope.


Rate limits

Each key has two limits — a per-minute burst window and a per-day sustained window — enforced per key. The defaults depend on your plan:

PlanBurst (per minute)Sustained (per day)
Studio12020,000
Roster300100,000

Every authenticated response includes the current state (the most constrained of the two windows):

X-RateLimit-Limit: 120
X-RateLimit-Remaining: 118
X-RateLimit-Reset: 1751551260

When a limit is exceeded, the API returns 429 with a Retry-After header (seconds to wait). Back off and retry after that delay.

The X-RateLimit-* headers are not sent on authentication-failure responses (401 invalid_key, 401 key_expired, 401 key_revoked) — they only appear once a valid key has been identified.
With sensible caching (see Website integration) a partner website stays far below the default limits. If you need higher limits, contact us — they are tunable per key.

Errors

All 4xx/5xx responses use RFC 9457 application/problem+json, with a stable code field you can branch on:

{
  "type": "https://www.sway.events/en/docs/api/errors#missing_scope",
  "title": "Missing Scope",
  "status": 403,
  "detail": "This API key does not have the required scope.",
  "instance": "/api/v1/events/4521",
  "code": "missing_scope"
}
codeHTTP statusMeaning
invalid_key401Key is malformed or unknown
key_expired401Key is past its expires_at
key_revoked401Key was revoked
subscription_required403Crew subscription no longer includes API access
missing_scope403Key lacks the scope required by this endpoint
rate_limited429Rate limit exceeded — check Retry-After
not_found404Resource does not exist or is outside your crew's graph
validation_error400 / 422Invalid query parameter (400) or request body (422)
invalid_cursor400Pagination cursor is malformed or stale
internal_error500Something went wrong on our side — safe to retry

Beyond the standard RFC 9457 members (type, title, status, detail, instance), every problem carries the machine-readable code above. validation_error responses also include an errors array of { "param", "message" } objects.

404 not_found is deliberately used for both missing and inaccessible resources — the API never confirms the existence of data outside your crew's graph.