Authentication
Authentication
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.
Key lifecycle
Keys are managed in Crew admin → API (Studio and Roster plans).
| Action | Behaviour |
|---|---|
| Create | Choose 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 |
| Revoke | Immediate and irreversible. Revoked keys receive 401 key_revoked on every request |
| Expire | Once expires_at passes, requests receive 401 key_expired. Create a new key to continue |
| Rotate | Create 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.
| Scope | Grants |
|---|---|
read:profile | GET /v1/me, GET /v1/crew |
read:artists | Roster, artist detail, artist events |
read:promoters | Managed promoters and their events |
read:events | Event detail, lineups, embedded venues |
read:venues | Venue detail (public tier) |
write:bookings | POST /v1/booking-requests (opt-in at key creation) |
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:
| Plan | Burst (per minute) | Sustained (per day) |
|---|---|---|
| Studio | 120 | 20,000 |
| Roster | 300 | 100,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.
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.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"
}
code | HTTP status | Meaning |
|---|---|---|
invalid_key | 401 | Key is malformed or unknown |
key_expired | 401 | Key is past its expires_at |
key_revoked | 401 | Key was revoked |
subscription_required | 403 | Crew subscription no longer includes API access |
missing_scope | 403 | Key lacks the scope required by this endpoint |
rate_limited | 429 | Rate limit exceeded — check Retry-After |
not_found | 404 | Resource does not exist or is outside your crew's graph |
validation_error | 400 / 422 | Invalid query parameter (400) or request body (422) |
invalid_cursor | 400 | Pagination cursor is malformed or stale |
internal_error | 500 | Something 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.
