SwaySway

Endpoint Reference

Complete reference of all Sway Public API v1 endpoints.

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.

#EndpointScope
1GET /v1/me
2GET /v1/crewread:profile
3GET /v1/artistsread:artists
4GET /v1/artists/{id}read:artists
5GET /v1/artists/{id}/eventsread:artists + read:events
6GET /v1/promotersread:promoters
7GET /v1/promoters/{id}read:promoters
8GET /v1/promoters/{id}/eventsread:promoters + read:events
9GET /v1/eventsread:events
10GET /v1/events/{id}read:events
11GET /v1/events/{id}/ticket-tiersread:events
12GET /v1/venues/{id}read:venues
13POST /v1/booking-requestswrite: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:

FieldTypeRequiredNotes
artist_idsnumber[]yesNon-empty, at most 50 ids, each a managed roster artist of your crew
contact_emailstringyesValid email, ≤ 320 chars
contact_namestringno≤ 200 chars
contact_phonestringno≤ 200 chars
event_namestringno≤ 200 chars
event_datestringnoISO date YYYY-MM-DD
venuestringno≤ 200 chars
citystringno≤ 200 chars
fee_offerstringnoFree-form, ≤ 200 chars
capacitystringnoFree-form, ≤ 200 chars
ticket_pricestringnoFree-form, ≤ 200 chars
organizationstringno≤ 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.