Endpoint Reference
Endpoint reference
All endpoints live under https://www.sway.events/api/v1 and are scoped to the crew that owns the API key. All are read-only except POST /v1/booking-requests.
| # | Endpoint | Scope |
|---|---|---|
| 1 | GET /v1/me | — |
| 2 | GET /v1/crew | read:profile |
| 3 | GET /v1/artists | read:artists |
| 4 | GET /v1/artists/{id} | read:artists |
| 5 | GET /v1/artists/{id}/events | read:artists + read:events |
| 6 | GET /v1/promoters | read:promoters |
| 7 | GET /v1/promoters/{id} | read:promoters |
| 8 | GET /v1/promoters/{id}/events | read:promoters + read:events |
| 9 | GET /v1/events | read:events |
| 10 | GET /v1/events/{id} | read:events |
| 11 | GET /v1/events/{id}/ticket-tiers | read:events |
| 12 | GET /v1/venues/{id} | read:venues |
| 13 | POST /v1/booking-requests | write:bookings |
List endpoints (/v1/artists, /v1/promoters, /v1/events, and the two event sub-feeds) use the standard { data, pagination } envelope and cursor pagination — see Pagination & filtering. Every single-resource endpoint, plus POST /v1/booking-requests, returns the resource object directly — no data wrapper.
Key & crew
GET /v1/me
Scope: none. Key introspection — the "is my key alive" probe. Returns the identified key (id, scopes, rate limits) and its crew.
{
"key": {
"id": "3f9a1c02-7b45-4c8e-9d21-0a1b2c3d4e5f",
"scopes": ["read:profile", "read:artists", "read:promoters", "read:events", "read:venues"],
"rate_limit": { "per_minute": 120, "per_day": 20000 }
},
"crew": { "id": "a2628d53-4f21-4c1e-9b7d-1a2b3c4d5e6f", "name": "Insomnia", "slug": "insomnia" }
}
GET /v1/crew
Scope: read:profile. The crew's profile plus a summary of its managed pages, nested under pages as arrays of ids.
{
"id": "a2628d53-4f21-4c1e-9b7d-1a2b3c4d5e6f",
"name": "Insomnia",
"slug": "insomnia",
"pages": {
"artists": [245, 512],
"promoters": [697]
}
}
Artists
GET /v1/artists
Scope: read:artists. The roster — all artists managed by your crew, as full representations. Sorted by name ascending. Roster artists are returned even while unpublished.
Query parameters: cursor, limit (1–100, default 25).
{
"data": [
{
"id": 245,
"name": "KROMATIEK",
"image_url": "https://assets.sway.events/artists/245/cover.webp",
"description": "Ghent-based techno artist…",
"genres": ["Techno", "Hard Groove"],
"links": {
"spotify": "https://open.spotify.com/artist/…",
"instagram": "https://instagram.com/kromatiek"
},
"is_verified": true,
"managed": true,
"contact_emails": [{ "type": "booking", "value": "[email protected]" }]
}
],
"pagination": { "next_cursor": "eyJrIjoiS1JPTUFUSUVLIiwiaWQiOjI0NX0", "has_more": true, "limit": 25 }
}
Contact emails live in the dedicated contact_emails array (managed tier only); links never contains an email key. Foreign (public-tier) artists have no contact_emails.
GET /v1/artists/{id}
Scope: read:artists. Full representation of one managed artist, returned directly (no envelope) — same shape as a roster entry above. Foreign artists (lineup guests) return 404 — they only appear inline in event lineups.
GET /v1/artists/{id}/events
Scope: read:artists and read:events (both required). The artist's gig history and calendar: published events where the artist is a confirmed lineup member. Each item is an event summary carrying a light venue reference ({ id, name } or null).
Query parameters: status (upcoming | past | all, default upcoming), cursor, limit. This feed does not accept from/to or expand.
Promoters
GET /v1/promoters
Scope: read:promoters. All promoters managed by your crew, full representations. Same envelope and parameters as /v1/artists.
GET /v1/promoters/{id}
Scope: read:promoters. Full representation of one managed, published promoter, returned directly (no envelope). Managed only — otherwise 404.
GET /v1/promoters/{id}/events
Scope: read:promoters and read:events (both required). The events feed of one promoter — the main feed for a partner website. Each event carries a light venue reference ({ id, name } or null) by default; use expand to embed more.
Query parameters: status (upcoming | past | all, default upcoming), from / to (ISO 8601), expand (any comma-separated subset of venue,lineup,ticket_tiers), cursor, limit. expand=venue upgrades the venue reference to the full public-tier venue.
Events
GET /v1/events
Scope: read:events. Union feed: events of your managed promoters plus published events featuring your roster artists. Each item is an event summary with a light venue reference ({ id, name } or null).
Query parameters: promoter_id, artist_id, status (default upcoming), from / to (ISO 8601), cursor, limit. This feed does not support expand — passing it returns 400 validation_error. Use /v1/events/{id} or /v1/promoters/{id}/events for expanded data.
GET /v1/events/{id}
Scope: read:events. One published event in your crew's graph, returned directly (no envelope). venue (full public tier) and lineup are always embedded; genres are always present. Add ?expand=ticket_tiers to also include the ticket tiers.
Query parameters: expand — accepts a comma-separated subset of venue,lineup,ticket_tiers (venue and lineup are already embedded, so only ticket_tiers adds anything).
Lineup entries carry the artist DTO plus stage, start_time, end_time and an artist_id, and include the managed flag: your own artists come with the full representation (incl. contact_emails), foreign guests appear at the public tier only. Custom (non-linked) acts appear as placeholder entries with artist_id: null.
{
"id": 4521,
"title": "Overload",
"description": "…",
"starts_at": "2026-09-12T22:00:00Z",
"ends_at": "2026-09-13T06:00:00Z",
"timezone": "Europe/Brussels",
"image_url": "https://assets.sway.events/events/4521/cover.webp",
"type": "club",
"page_url": "https://www.sway.events/event/4521",
"venue": {
"id": 88,
"name": "Jungle Bar",
"image_url": "…",
"description": "…",
"location": { "address": "Nieuwewandeling 2, Ghent" },
"genres": [],
"links": null
},
"lineup": [
{ "stage": "Main", "start_time": "23:00", "end_time": "01:00", "artist_id": 245, "id": 245, "name": "KROMATIEK", "image_url": "…", "description": "…", "genres": ["Techno"], "links": { "spotify": "…" }, "is_verified": true, "managed": true, "contact_emails": [{ "type": "booking", "value": "[email protected]" }] },
{ "stage": null, "start_time": null, "end_time": null, "artist_id": 1042, "id": 1042, "name": "CE$AR", "image_url": "…", "description": null, "genres": ["House"], "links": null, "is_verified": false, "managed": false }
],
"genres": ["Techno"]
}
GET /v1/events/{id}/ticket-tiers
Scope: read:events. The event's ticket tiers: name, description, price, status, sale windows and a checkout_url deep link to the Sway checkout. No stock counts, no orders, no buyer data. This is a small, fixed list — it is wrapped in { "data": [ … ] } but has no pagination object and no cursor.
{
"data": [
{
"id": "301",
"name": "Early Bird",
"description": "Limited first release",
"price": 15.0,
"currency": "EUR",
"status": "sold_out",
"sale_start": "2026-06-01T10:00:00Z",
"sale_end": "2026-07-01T10:00:00Z",
"max_per_order": 4,
"checkout_url": "https://www.sway.events/event/4521?ref=api"
},
{
"id": "302",
"name": "Regular",
"description": null,
"price": 20.0,
"currency": "EUR",
"status": "on_sale",
"sale_start": "2026-07-01T10:00:00Z",
"sale_end": "2026-09-12T22:00:00Z",
"max_per_order": 6,
"checkout_url": "https://www.sway.events/event/4521?ref=api"
}
]
}
status is derived server-side and is one of on_sale, scheduled, sold_out, off_sale. currency defaults to EUR.
Venues
GET /v1/venues/{id}
Scope: read:venues. Public tier only, returned directly (no envelope): id, name, image_url, description, location (object — address plus any geo data, or null), genres, links (null when empty). Venues are reachable only when they host a published event in your crew's graph — otherwise 404.
{
"id": 88,
"name": "Jungle Bar",
"image_url": "https://assets.sway.events/venues/88/cover.webp",
"description": "…",
"location": { "address": "Nieuwewandeling 2, Ghent" },
"genres": [],
"links": null
}
Booking requests
POST /v1/booking-requests
Scope: write:bookings (opt-in at key creation). Submits a booking request from a partner site into the crew's booking pipeline and triggers a notification. This endpoint is rate-limited tighter than the read endpoints (10 requests / minute, per IP).
Request body — a flat JSON object:
| Field | Type | Required | Notes |
|---|---|---|---|
artist_ids | number[] | yes | Non-empty, at most 50 ids, each a managed roster artist of your crew |
contact_email | string | yes | Valid email, ≤ 320 chars |
contact_name | string | no | ≤ 200 chars |
contact_phone | string | no | ≤ 200 chars |
event_name | string | no | ≤ 200 chars |
event_date | string | no | ISO date YYYY-MM-DD |
venue | string | no | ≤ 200 chars |
city | string | no | ≤ 200 chars |
fee_offer | string | no | Free-form, ≤ 200 chars |
capacity | string | no | Free-form, ≤ 200 chars |
ticket_price | string | no | Free-form, ≤ 200 chars |
organization | string | no | ≤ 200 chars |
{
"artist_ids": [245],
"contact_email": "[email protected]",
"contact_name": "Jane Doe",
"contact_phone": "+32 470 00 00 00",
"event_name": "Warehouse Night",
"event_date": "2026-11-21",
"venue": "Fuse",
"city": "Brussels",
"fee_offer": "800 EUR",
"capacity": "1200",
"ticket_price": "20 EUR",
"organization": "Nightlife BV"
}
Response 201 Created — returned directly, no envelope:
{
"id": "9f2c1a7e-4d3b-4e21-8c7a-1b2c3d4e5f60",
"status": "new",
"created_at": "2026-07-03T14:00:00Z"
}
Invalid bodies return 422 validation_error (with an errors array). Any artist_ids that are not part of your crew's roster are rejected with 422 and listed under errors[].invalid_ids.

