Endpoint-referentie
Alle endpoints leven onder https://www.sway.events/api/v1 en zijn beperkt tot de crew die eigenaar is van de API-sleutel, meegestuurd als bearer-token:
curl https://www.sway.events/api/v1/artists \
-H "Authorization: Bearer sway_sk_YOUR_KEY"
Lijst-endpoints geven de standaardenvelop { data, pagination } terug, met cursorpaginering; elk endpoint voor één bron geeft het object direct terug, zonder data-omhulsel. Zie Paginering en filters voor cursors, filters en het expand-mechanisme.
Elke 4xx- of 5xx-respons is een RFC 9457-probleem (application/problem+json) met een stabiel veld code. Zie Authenticatie voor de levenscyclus van een sleutel, scopes, rate limits en de volledige foutentabel.
Deze pagina documenteert de 80 routes die de eigen data van een crew gebruiken. De MCP-server en webhooks zijn aparte manieren om dezelfde data te leveren en hebben hun eigen pagina's; zie de laatste sectie.
Sleutel en crew
GET /v1/me
Introspectie van de sleutel: de test "leeft mijn sleutel nog?". Geeft de herkende sleutel terug (id, type, scopes, rate limit en werklimieten, geregistreerde websites) en zijn crew.
Geen scope nodig. Publishable keys: nee. Nooit gecachet (het antwoord is sleutelspecifiek en moet altijd actueel zijn).
{
"key": {
"id": "3f9a1c02-7b45-4c8e-9d21-0a1b2c3d4e5f",
"type": "secret",
"scopes": ["read:profile", "read:artists", "read:promoters", "read:events", "read:venues", "read:content"],
"rate_limit": { "per_minute": 120, "per_day": 20000 },
"limits": {
"requests_per_minute": 2400,
"crew_work_per_minute": 600,
"crew_work_per_day": 120000,
"bytes_per_day": 5368709120
},
"websites": []
},
"crew": { "id": "a2628d53-4f21-4c1e-9b7d-1a2b3c4d5e6f", "name": "Insomnia", "slug": "insomnia" }
}
rate_limit is het eigen werkbudget van de sleutel (wat een cache miss kost); limits zijn de bredere plafonds die beschreven staan op de pagina Authenticatie. Geen route-specifieke fouten naast de standaard authenticatiefouten.
GET /v1/usage
Wat de aanroepende sleutel op dit moment van zijn limieten heeft gebruikt: werk deze minuut en vandaag, het verzoekplafond, vandaag geserveerde bytes, en of de sleutel bevroren is na een ongewoon patroon van verzoeken.
Geen scope nodig. Publishable keys: nee. Nooit gecachet; het uitlezen ervan kost nooit werk (kost 0).
{
"key": { "id": "3f9a1c02-7b45-4c8e-9d21-0a1b2c3d4e5f", "type": "secret" },
"plan": "studio",
"work": {
"minute": { "limit": 120, "used": 12, "remaining": 108, "reset_seconds": 41 },
"day": { "limit": 20000, "used": 340, "remaining": 19660, "reset_seconds": 61200 }
},
"crew_work": {
"minute": { "limit": 600, "used": 12, "remaining": 588, "reset_seconds": 41 },
"day": { "limit": 120000, "used": 340, "remaining": 119660, "reset_seconds": 61200 }
},
"requests": {
"minute": { "limit": 2400, "used": 15, "remaining": 2385, "reset_seconds": 41 }
},
"bytes": { "today": 1048576, "limit": 5368709120 },
"frozen": false
}
work is het eigen budget van de sleutel; crew_work is hetzelfde budget, samengevoegd over alle sleutels van de crew. Geen route-specifieke fouten.
GET /v1/audit-log
De laatste aanroepen die de sleutel deed, nieuwste eerst: tijd, methode, pad, status, adres van de aanroeper, cache-uitkomst en duur. Zeven dagen bewaard, hoogstens 1.000 items.
Geen scope nodig. Publishable keys: nee. Nooit gecachet (privacy: no-store).
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
limit | geheel getal, 1 tot 1.000 | 100 | Hoeveel items teruggeven |
{
"data": [
{
"at": "2026-09-26T12:00:03.000Z",
"method": "GET",
"path": "/api/v1/events/4521",
"status": 200,
"ip": "203.0.113.7",
"request_id": "9f2c1a7e-4d3b-4e21-8c7a-1b2c3d4e5f60",
"cache": "hit",
"ms": 4
}
],
"count": 1
}
ip is het waargenomen adres van de aanroepende sleutel zelf. cache is hit, miss, stale of null wanneer de route niet cachebaar is.
Fouten: validation_error (400) wanneer limit buiten bereik ligt.
POST /v1/keys/rotate
Vervangt de aanroepende sleutel door een nieuwe: dezelfde naam, type, scopes, limieten en websites. De oude sleutel blijft werken tijdens een respijtperiode (zodat een partner opnieuw kan deployen zonder onderbreking), en verloopt daarna vanzelf.
Scope write:keys (opt-in). Publishable keys: nee. Nooit gecachet. Neemt geen Idempotency-Key: het antwoord draagt het nieuwe secret, en Sway bewaart nooit een antwoord dat een secret draagt, dus er is niets om aan een retry terug te geven.
| Veld | Type | Verplicht | Opmerkingen |
|---|---|---|---|
grace_hours | number | nee | Geheel getal, 1 tot 168, standaard 24: hoe lang de oude sleutel nog antwoordt |
{
"key": "sway_sk_ab12...",
"record": {
"id": "7c5e2b41-...",
"name": "Storefront key",
"key_prefix": "sway_sk_ab12",
"last4": "wxyz",
"key_type": "secret",
"scopes": ["read:artists", "read:events"],
"storefront_origins": [],
"created_at": "2026-09-26T12:00:00.000Z",
"expires_at": null,
"rotated_from_id": "3f9a1c02-7b45-4c8e-9d21-0a1b2c3d4e5f"
},
"previous": { "id": "3f9a1c02-7b45-4c8e-9d21-0a1b2c3d4e5f", "expires_at": "2026-09-27T12:00:00.000Z" }
}
Het volledige nieuwe secret (key) wordt één keer getoond, in dit antwoord, net als bij het aanmaken: bewaar het meteen.
Fouten: validation_error (400, foute body of grace_hours), invalid_key (401, de sleutel was al weg), conflict (409, deze sleutel heeft al een opvolger: roteer in plaats daarvan de sleutel die hem verving), rate_limited (429, een sleutel mag maar één keer per uur roteren).
GET /v1/crew
Het profiel van de crew plus de id's van de pagina's die hij beheert.
Scope read:profile. Publishable keys: ja. 300 s gecachet.
{
"id": "a2628d53-4f21-4c1e-9b7d-1a2b3c4d5e6f",
"name": "Insomnia",
"slug": "insomnia",
"pages": { "artists": [245, 512], "promoters": [697] }
}
Geen route-specifieke fouten.
GET /v1/crew/pages
De pagina's die de crew beheert (artiesten, promotors, locaties), elk met zijn naam en of hij gepubliceerd is. In tegenstelling tot elke andere route wordt hier ook een conceptpagina genoemd: het is de eigen lijst van de crew.
Scope read:profile. Publishable keys: nee. 300 s gecachet.
{
"data": [
{ "type": "artist", "id": 245, "name": "KROMATIEK", "image_url": "https://assets.sway.events/artists/245/cover.webp", "is_published": true, "page_url": "https://www.sway.events/artist/245" },
{ "type": "promoter", "id": 697, "name": "Insomnia Nights", "image_url": null, "is_published": false, "page_url": null }
]
}
image_url en page_url zijn null zolang de pagina ongepubliceerd blijft. Geen route-specifieke fouten.
GET /v1/genres
De genretaxonomie: stabiele id's en namen, gesorteerd op naam. Dit zijn de id's die de filters genre= van GET /v1/artists, GET /v1/events en GET /v1/events/search verwachten.
Geen scope nodig. Publishable keys: ja. 3600 s gecachet.
{
"data": [
{ "id": 12, "name": "Hard Groove" },
{ "id": 45, "name": "Techno" }
]
}
Geen route-specifieke fouten.
Discovery
Deze vier routes hebben helemaal geen API-sleutel nodig: ze beschrijven de API zelf. Elk is begrensd tot 60 verzoeken per minuut per adres van de aanroeper, en antwoordt daarboven met 429 rate_limited.
GET /v1/openapi.json
Deze API als een OpenAPI 3.1-document, gegenereerd uit dezelfde lijst routes waarop de API draait, zodat het nooit een route beschrijft die niet bestaat of er een mist die wel bestaat.
Geen sleutel nodig. 3600 s gecachet.
Geen route-specifieke fouten naast de limiet per adres hierboven.
GET /v1/scopes
Elke scope die een sleutel kan dragen: wat hij toestaat, of een publishable key hem mag dragen, of alleen de crew-eigenaar hem mag toekennen, en de routes die hij opent.
Geen sleutel nodig. 3600 s gecachet.
{
"data": [
{
"scope": "read:events",
"group": "read",
"default": true,
"publishable": true,
"owner_only": false,
"summary": "Read published events, their lineups, days, tickets on sale and availability.",
"routes": ["GET /v1/events", "GET /v1/events/:id", "GET /v1/events/:id/ticket-tiers"]
},
{
"scope": "write:checkout:free",
"group": "write",
"default": false,
"publishable": false,
"owner_only": true,
"summary": "Issue free (comp) orders. The crew owner grants it.",
"routes": ["POST /v1/checkout-sessions"]
}
]
}
Het echte antwoord somt alle zeventien scopes op, en elke route die elk van hen opent.
GET /v1/changelog
Wat er veranderde in de API, nieuwste eerst, elke datum met de routes die die dag zijn uitgebracht.
Geen sleutel nodig. 3600 s gecachet.
{
"data": [
{
"date": "2026-08-01",
"changes": ["Stripe checkout sessions for tickets, and newsletter sign-up."],
"routes": ["POST /v1/checkout-sessions", "POST /v1/newsletter-signup"]
}
]
}
GET /v1/status
Of de API en waar hij van afhangt antwoorden: de database, betalingen (Stripe) en e-mail, elk ok of down, hoogstens één keer per interval getest zodat de route zelf nooit belasting wordt. Het geheel is ok alleen wanneer elk onderdeel dat is.
Geen sleutel nodig. Nooit gecachet.
{
"status": "ok",
"api_version": "v1",
"time": "2026-09-26T12:00:00.000Z",
"components": { "database": "ok", "payments": "ok", "email": "ok" }
}
Nooit een latency-cijfer, een versie of een foutmelding: alleen ok of down.
Artiesten
Elke route hieronder aanvaardt een publishable key.
GET /v1/artists
De roster: elke artiest die de crew beheert, op naam, oplopend. Roster-artiesten komen ook terug terwijl ze ongepubliceerd zijn, aangezien de roster de eigen data van de crew is.
Scope read:artists. 300 s gecachet.
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
q | tekst, 2 tot 100 tekens | geen | Naam bevat, tekstueel vergeleken |
genre | kommalijst van genre-id's, hoogstens 10 | geen | Elk van deze genres |
updated_since | ISO 8601-datum of datum-tijd | geen | Gewijzigd op of na dit moment |
ids | kommalijst van id's, hoogstens 50 | geen | Alleen deze artiesten |
limit | geheel getal, 1 tot 100 | 25 | Paginagrootte |
cursor | ondoorzichtige string | geen | Uit de next_cursor van een vorige pagina |
{
"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/xyz", "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 is alleen voor beheerd niveau en verschijnt nooit binnen links. Fouten: validation_error (400, foute q, genre, updated_since, ids of limit), invalid_cursor (400).
GET /v1/artists/{id}
Eén artiest van de roster, volledige weergave, direct teruggegeven. Een externe artiest (een gast in de line-up die niet door de crew wordt beheerd) is op deze manier niet op te vragen.
Scope read:artists. 300 s gecachet.
Dezelfde vorm als een roster-item hierboven. Fouten: not_found (404, misvormd id, onbekend id, of een artiest die de crew niet beheert).
GET /v1/artists/{id}/events
De optredenhistorie en agenda van de artiest: gepubliceerde evenementen waar de artiest een bevestigd line-uplid is. Elk item draagt een lichte venue-verwijzing.
Scopes read:artists en read:events (allebei verplicht). 120 s gecachet.
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
status | upcoming, past, all | upcoming | Welke evenementen op te nemen |
limit | geheel getal, 1 tot 100 | 25 | Paginagrootte |
cursor | ondoorzichtige string | geen | Uit een vorige pagina |
Deze feed aanvaardt geen from, to of expand.
{
"data": [
{
"id": 4521,
"title": "Overload",
"description": "A night of hard groove.",
"starts_at": "2026-09-12T20:00:00.000Z",
"ends_at": "2026-09-13T04:00:00.000Z",
"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" }
}
],
"pagination": { "next_cursor": null, "has_more": false, "limit": 25 }
}
Fouten: not_found (404, misvormd id of artiest die de crew niet beheert), validation_error (400, foute status), invalid_cursor (400).
GET /v1/artists/{id}/ics
De aankomende data van de artiest als een iCalendar-feed (text/calendar) om op te abonneren. Hoogstens 100 evenementen, RFC 5545, regels gevouwen op 75 octetten, tijden in UTC. GET /v1/promoters/{id}/ics en GET /v1/events/{id}/ics, verderop, zijn dezelfde feed voor de evenementen van een promotor en voor één evenement.
Scopes read:artists en read:events (allebei verplicht). 300 s gecachet.
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Sway//Sway API v1//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:KROMATIEK
BEGIN:VEVENT
UID:[email protected]
DTSTAMP:20260926T120000Z
DTSTART:20260912T200000Z
DTEND:20260913T040000Z
SUMMARY:Overload
LOCATION:Jungle Bar\, Ghent
URL:https://www.sway.events/event/4521
END:VEVENT
END:VCALENDAR
Het bestand heet artist-{id}.ics (Content-Disposition: inline). Fouten: not_found (404, misvormd id, of de artiest wordt niet beheerd of is niet gepubliceerd).
GET /v1/artists/{id}/presskits
De publieke perskits van de artiest, de standaardkit eerst. Private kits en concepten blijven hier buiten beschouwing; zie GET /v1/presskits voor de volledige eigen lijst van de crew.
Scopes read:artists en read:content (allebei verplicht). 300 s gecachet.
{
"artist_id": 245,
"data": [
{
"id": "1b2c3d4e-5f60-4a1b-9c2d-3e4f5a6b7c8d",
"artist_id": 245,
"title": "KROMATIEK 2026 EPK",
"status": "public",
"protected": false,
"is_default": true,
"updated_at": "2026-09-01T10:00:00.000Z",
"url": "https://www.sway.events/artist/245/presskit/1b2c3d4e-5f60-4a1b-9c2d-3e4f5a6b7c8d"
}
]
}
Fouten: not_found (404, misvormd id of artiest die de crew niet beheert).
Promotors
Elke route hieronder aanvaardt een publishable key.
GET /v1/promoters
Elke promotor die de crew beheert, volledige weergave, gesorteerd op naam.
Scope read:promoters. 300 s gecachet.
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
q | tekst, 2 tot 100 tekens | geen | Naam bevat |
ids | kommalijst van id's, hoogstens 50 | geen | Alleen deze promotors |
limit | geheel getal, 1 tot 100 | 25 | Paginagrootte |
cursor | ondoorzichtige string | geen | Uit een vorige pagina |
Dezelfde envelop en itemvorm als GET /v1/artists (promotorvelden in plaats van artiestvelden; geen genrefilter). Fouten: validation_error (400), invalid_cursor (400).
GET /v1/promoters/{id}
Eén beheerde, gepubliceerde promotor, volledige weergave, direct teruggegeven.
Scope read:promoters. 300 s gecachet.
Fouten: not_found (404, misvormd id of promotor die de crew niet beheert).
GET /v1/promoters/{id}/events
Gepubliceerde evenementen van een beheerde promotor: de hoofdfeed waarop een partnersite wordt gebouwd.
Scopes read:promoters en read:events (allebei verplicht). 60 s gecachet.
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
status | upcoming, past, all | upcoming | Welke evenementen |
from / to | ISO 8601-datum of datum-tijd | geen | Beginnend op of na / op of vóór |
expand | kommalijst van venue, lineup, ticket_tiers | geen | Gerelateerde bronnen insluiten |
limit | geheel getal, 1 tot 100 | 25 | Paginagrootte |
cursor | ondoorzichtige string | geen | Uit een vorige pagina |
{
"data": [
{
"id": 4521,
"title": "Overload",
"description": "A night of hard groove.",
"starts_at": "2026-09-12T20:00:00.000Z",
"ends_at": "2026-09-13T04:00:00.000Z",
"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" }
}
],
"pagination": { "next_cursor": null, "has_more": false, "limit": 25 }
}
venue is standaard een lichte verwijzing { id, name }; expand=venue maakt er het volledige object op publiek niveau van, en expand=lineup / expand=ticket_tiers voegen die arrays aan elk item toe (dezelfde vormen als op GET /v1/events/{id}). Fouten: validation_error (400, foute status, from, to of expand), invalid_cursor (400), not_found (404, misvormd id of promotor die de crew niet beheert).
GET /v1/promoters/{id}/ics
De aankomende evenementen van de promotor als een iCalendar-feed, dezelfde vorm als GET /v1/artists/{id}/ics (zie Artiesten), gedownload als promoter-{id}.ics.
Scopes read:promoters en read:events (allebei verplicht). 300 s gecachet.
Fouten: not_found (404, misvormd id of promotor die de crew niet beheert).
GET /v1/promoters/{id}/venues
De locaties waar de gepubliceerde evenementen van de promotor plaatsvinden, meest gebruikte eerst.
Scopes read:promoters en read:venues (allebei verplicht). 300 s gecachet.
{
"data": [
{
"id": 88,
"name": "Jungle Bar",
"image_url": "https://assets.sway.events/venues/88/cover.webp",
"description": "A cellar club in Ghent.",
"location": { "address": "Nieuwewandeling 2, Ghent" },
"genres": [],
"links": null,
"capacity": { "max": 300, "layouts": { "standing": 300, "seated": 120 } },
"event_count": 14
}
]
}
Fouten: not_found (404, misvormd id of promotor die de crew niet beheert).
GET /v1/promoters/{id}/artists
De artiesten die de promotor heeft geboekt op zijn gepubliceerde evenementen, meest geboekt eerst. Roster-artiesten komen op volledig niveau, de rest op publiek niveau.
Scopes read:promoters en read:artists (allebei verplicht). 300 s gecachet.
{
"data": [
{ "id": 245, "name": "KROMATIEK", "image_url": "https://assets.sway.events/artists/245/cover.webp", "description": "Ghent-based techno artist.", "genres": ["Techno"], "links": null, "is_verified": true, "managed": true, "contact_emails": [], "booking_count": 6 },
{ "id": 1042, "name": "CE$AR", "image_url": null, "description": null, "genres": ["House"], "links": null, "is_verified": false, "managed": false, "booking_count": 2 }
]
}
booking_count telt evenementen, geen sets: een dubbele boeking op dezelfde avond telt nog steeds één keer. Fouten: not_found (404, misvormd id of promotor die de crew niet beheert).
Evenementen
start_time en end_time op een line-up-item, en elke tijd binnen GET /v1/events/{id}/days en GET /v1/events/{id}/timetable, blijven RFC 3339 met de eigen UTC-offset van het evenement, bijvoorbeeld 22:00:00+02:00 in plaats van 22:00:00+00:00: de cijfers zijn precies wat de organisator typte, en het moment is het juiste. Ze zijn null zolang de organisator de timetable uit laat staan (event-days.ts, apiSetTime).GET /v1/events/{id}/days volgt de dagen die de organisator heeft opgegeven in de instellingen voor festivaldagen, of behandelt het hele evenement als één dag wanneer er geen zijn opgegeven; unscheduled bevat sets zonder tijd, of die buiten elke opgegeven dag vallen. GET /v1/events/{id}/timetable volgt de eigen stagevolgorde van de organisator, niet-opgegeven stages daarna alfabetisch, en zet sets zonder stage achteraan.Elke route hieronder aanvaardt een publishable key.
GET /v1/events
De samengevoegde feed van de graaf van de crew: de evenementen van zijn promotors, de bevestigde optredens van zijn roster, en de agenda van de locaties die hij beheert. Elk item is een lichte samenvatting met een venue-verwijzing.
Scope read:events. 60 s gecachet.
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
status | upcoming, past, all | upcoming | Welke evenementen |
from / to | ISO 8601-datum of datum-tijd | geen | Datumvenster |
promoter_id | positief geheel getal | geen | Eén beheerde promotor |
artist_id | positief geheel getal | geen | Eén roster-artiest |
venue_id | positief geheel getal | geen | Eén locatie van de graaf |
genre | kommalijst van genre-id's, hoogstens 10 | geen | Elk van deze genres |
city | tekst, 1 tot 100 tekens | geen | Exacte stadsnaam |
country | ISO 3166-1 alpha-2 | geen | Landcode |
near | lat,lng in decimale graden | geen | Middelpunt van een straalzoekopdracht |
radius_km | getal, 1 tot 500 | 25 | Straal rond near (heeft near nodig) |
updated_since | ISO 8601-datum of datum-tijd | geen | Gewijzigd op of na dit moment |
has_tickets | true, false | geen | Of het evenement een tickettype heeft |
ids | kommalijst van id's, hoogstens 50 | geen | Alleen deze evenementen |
limit | geheel getal, 1 tot 100 | 25 | Paginagrootte |
cursor | ondoorzichtige string | geen | Uit een vorige pagina |
Deze feed ondersteunt geen expand: meesturen geeft validation_error (400) terug. Gebruik GET /v1/events/{id} of GET /v1/promoters/{id}/events voor uitgebreide data.
{
"data": [
{
"id": 4521,
"title": "Overload",
"description": "A night of hard groove.",
"starts_at": "2026-09-12T20:00:00.000Z",
"ends_at": "2026-09-13T04:00:00.000Z",
"timezone": "Europe/Brussels",
"image_url": "https://assets.sway.events/events/4521/cover.webp",
"type": "club",
"page_url": "https://www.sway.events/event/4521",
"updated_at": "2026-09-10T09:00:00.000Z",
"venue": { "id": 88, "name": "Jungle Bar" }
}
],
"pagination": { "next_cursor": "eyJrIjoiMjAyNi0wOS0xMlQyMDowMDowMC4wMDBaIiwiaWQiOjQ1MjF9", "has_more": false, "limit": 25 }
}
Fouten: validation_error (400, expand meegestuurd, foute filterwaarde, of radius_km zonder near), invalid_cursor (400), not_found (404, promoter_id of artist_id noemt een pagina die de crew niet beheert).
GET /v1/events/search
Dezelfde feed als GET /v1/events, gefilterd op evenementen waarvan de titel, beschrijving of bevestigde line-up de zoektekst bevat.
Scope read:events. 60 s gecachet.
Elke filter van GET /v1/events, plus:
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
q | tekst, 2 tot 100 tekens | verplicht | Tekstueel vergeleken met titel, beschrijving en line-up |
Dezelfde envelop als GET /v1/events. Fouten: validation_error (400, q ontbreekt of heeft de verkeerde lengte, of een van de gedeelde filters), invalid_cursor (400), not_found (404, promoter_id of artist_id buiten de graaf).
GET /v1/events/{id}
Eén gepubliceerd evenement van de graaf van de crew, direct teruggegeven. venue (volledig publiek niveau) en lineup zijn altijd ingesloten; genres is er altijd.
Scope read:events. 60 s gecachet.
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
expand | ticket_tiers | geen | venue en lineup zijn al ingesloten, dus dit is de enige waarde die iets toevoegt |
Wanneer expand=ticket_tiers aanwezig is, draagt het antwoord ook een object ticket_fee: { "percent": number, "fixed": number, "applies_to": "ticket" | "order" }, de servicekosten voor de ontvanger van dit evenement, in EUR. Het is hetzelfde object als GET /v1/events/{id}/fees, dat uitlegt hoe je ze toepast.
{
"id": 4521,
"title": "Overload",
"description": "A night of hard groove.",
"starts_at": "2026-09-12T20:00:00.000Z",
"ends_at": "2026-09-13T04:00:00.000Z",
"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": "https://assets.sway.events/venues/88/cover.webp",
"description": "A cellar club in Ghent.",
"location": { "address": "Nieuwewandeling 2, Ghent" },
"genres": [],
"links": null
},
"lineup": [
{
"stage": "Main", "start_time": "2026-09-12T23:00:00+02:00", "end_time": "2026-09-13T01:00:00+02:00",
"artist_id": 245, "id": 245, "name": "KROMATIEK", "image_url": "https://assets.sway.events/artists/245/cover.webp",
"description": "Ghent-based techno artist.", "genres": ["Techno"], "links": { "spotify": "https://open.spotify.com/artist/xyz" },
"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": null, "description": null,
"genres": ["House"], "links": null, "is_verified": false, "managed": false
}
],
"genres": ["Techno"]
}
Line-up-items dragen de eigen DTO van de artiest plus stage, start_time, end_time en artist_id: roster-artiesten komen op volledig niveau (met contact_emails), externe gasten op publiek niveau. Een aangepast, niet-gekoppeld act verschijnt als een placeholder-item met artist_id: null en zijn getypte naam onder name. Het tweede line-up-item hierboven heeft start_time/end_time: null omdat die set geen tijd geregistreerd heeft, niet omdat de timetable uit staat; zie de notitie boven de sectie.
Fouten: validation_error (400, onbekende waarde voor expand), not_found (404, misvormd id, ongepubliceerd evenement, of een evenement buiten de graaf van de crew).
GET /v1/events/{id}/ticket-tiers
De tickettypes van het evenement: naam, beschrijving, prijs, status, verkoopperiode en een deeplink checkout_url naar de Sway-checkout. Geen voorraadaantallen, geen bestellingen, geen kopersdata. Een kleine, vaste lijst: verpakt in { "data": [...] } maar zonder pagination en zonder cursor.
Scope read:events. 30 s gecachet.
{
"data": [
{
"id": "301", "name": "Early Bird", "description": "Limited first release", "price": 15.0, "currency": "EUR",
"fee_amount": 0.75, "price_with_fee": 15.75, "fee_applies_to": "ticket", "status": "sold_out", "sale_start": "2026-06-01T10:00:00.000Z", "sale_end": "2026-07-01T10:00:00.000Z",
"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",
"fee_amount": 0.9, "price_with_fee": 20.9, "fee_applies_to": "ticket",
"sale_start": "2026-07-01T10:00:00.000Z", "sale_end": "2026-09-12T20:00:00.000Z",
"max_per_order": 6, "checkout_url": "https://www.sway.events/event/4521?ref=api"
}
]
}
status wordt server-side afgeleid: on_sale, scheduled, sold_out of off_sale. currency is standaard EUR. Fouten: not_found (404).
fee_amount zijn de servicekosten op één ticket en price_with_fee de totaalprijs die de koper betaalt (price plus fee_amount), volgens het kostenmodel van de uitbetaalde promoter, dezelfde cijfers als de evenementpagina en de publieke MCP. Toon eerst price_with_fee en fee_amount als servicekosten. Bij het oude model per bestelling (fee_applies_to: "order") zijn beide null: de kosten hangen af van de hele winkelwagen, zie GET /v1/events/{id}/fees. Gratis tickettypes hebben een fee_amount van 0.
GET /v1/events/{id}/availability
Of er nu al gekocht kan worden: in verkoop, gepland, uitverkocht of voorbij, per tickettype en voor het hele evenement, met een vlag "bijna uitverkocht". Nooit een voorraadaantal.
Scope read:events. 30 s gecachet.
{
"event_id": 4521,
"status": "on_sale",
"next_sale_start": null,
"tiers": [
{ "id": "301", "name": "Early Bird", "status": "sold_out", "few_left": false, "sale_start": "2026-06-01T10:00:00.000Z", "sale_end": "2026-07-01T10:00:00.000Z" },
{ "id": "302", "name": "Regular", "status": "on_sale", "few_left": true, "sale_start": "2026-07-01T10:00:00.000Z", "sale_end": "2026-09-12T20:00:00.000Z" }
]
}
few_left wordt gezet zodra de resterende voorraad van een tickettype op of onder een tiende van zijn beginvoorraad zit (minimum 5), en alleen terwijl het on_sale is. De eigen status van het evenement kan no_tickets zijn wanneer het evenement helemaal geen tickettype heeft. Fouten: not_found (404).
GET /v1/events/{id}/fees
De servicekosten die een koper betaalt op de tickets van dit evenement, volgens het kostenmodel van de ontvangende promotor: standaard een percentage van de prijs van elk betaald ticket plus een vast bedrag per ticket.
Scope read:events. 300 s gecachet.
{ "event_id": 4521, "percent": 0.03, "fixed": 0.3, "applies_to": "ticket" }
Met applies_to: "ticket" draagt elk betaald ticket round(price * percent + fixed) afgerond op de cent (een bundel telt als één ticket, een gratis ticket draagt niets), en total = subtotal + de som van die kosten. Sommige promotors behouden een ouder model, applies_to: "order": total = subtotal + subtotal * percent + fixed, één keer per betaalde bestelling. Hoe dan ook komt het resultaat overeen met het totaal dat de Stripe-checkout in rekening brengt. Valt terug op het standaardtarief per ticket wanneer de ontvanger niet bepaald kan worden, in plaats van te falen. Fouten: not_found (404).
GET /v1/events/{id}/days
De dagen die de organisator heeft opgegeven in de instellingen voor festivaldagen van het evenement, elk met de sets die er beginnen; of het evenement als één enkele dag wanneer er geen zijn opgegeven.
Scope read:events. 60 s gecachet.
{
"event_id": 4521,
"timezone": "Europe/Brussels",
"timetable_published": true,
"data": [
{
"name": "Friday",
"date": "2026-09-12",
"starts_at": "2026-09-12T20:00:00+02:00",
"ends_at": "2026-09-13T06:00:00+02:00",
"slots": [
{ "name": "KROMATIEK", "artist_id": 245, "artists": [{ "id": 245, "name": "KROMATIEK", "managed": true }], "stage": "Main", "start_time": "2026-09-12T23:00:00+02:00", "end_time": "2026-09-13T01:00:00+02:00" }
]
}
],
"unscheduled": []
}
unscheduled bevat sets zonder tijd, of die buiten elke opgegeven dag vallen. Met de timetable uitgeschakeld is timetable_published false en komt elke dag met een leeg slots-array. Een b2b-set is één slot met meerdere artists; name is de aangepaste naam van de organisator wanneer die is ingesteld, anders de artiesten samengevoegd met " B2B ". Fouten: not_found (404).
GET /v1/events/{id}/timetable
De sets met tijd, per stage: de stages in de eigen, opgegeven volgorde van de organisator (de rest alfabetisch, de sets zonder stage als laatste), elke stage op volgorde van optreden.
Scope read:events. 60 s gecachet.
{
"event_id": 4521,
"timezone": "Europe/Brussels",
"published": true,
"stages": [
{
"stage": "Main",
"slots": [
{ "name": "KROMATIEK", "artist_id": 245, "artists": [{ "id": 245, "name": "KROMATIEK", "managed": true }], "stage": "Main", "start_time": "2026-09-12T23:00:00+02:00", "end_time": "2026-09-13T01:00:00+02:00" }
]
}
]
}
Een set zonder tijd staat niet op een timetable en wordt volledig weggelaten (hij kan nog wel verschijnen in GET /v1/events/{id}/days, onder unscheduled). Met de timetable uitgeschakeld is published false en is stages leeg. Fouten: not_found (404).
GET /v1/events/{id}/ics
Het evenement als een iCalendar-feed, dezelfde vorm als GET /v1/artists/{id}/ics (zie Artiesten), voor een knop "toevoegen aan agenda". Gedownload als event-{id}.ics.
Scope read:events. 300 s gecachet.
Fouten: not_found (404, misvormd id, ongepubliceerd evenement of buiten de graaf van de crew, of het evenement heeft geen startdatum).
GET /v1/events/{id}/schema-org
Het evenement als schema.org JSON-LD (MusicEvent), klaar om ongewijzigd in te voegen in het <script type="application/ld+json"> van een partnerpagina, voor zoekmachines.
Scope read:events. 300 s gecachet.
{
"@context": "https://schema.org",
"@type": "MusicEvent",
"name": "Overload",
"url": "https://www.sway.events/event/4521",
"eventStatus": "https://schema.org/EventScheduled",
"eventAttendanceMode": "https://schema.org/OfflineEventAttendanceMode",
"description": "A night of hard groove.",
"startDate": "2026-09-12T20:00:00.000Z",
"endDate": "2026-09-13T04:00:00.000Z",
"image": ["https://assets.sway.events/events/4521/cover.webp"],
"location": {
"@type": "Place",
"name": "Jungle Bar",
"address": { "@type": "PostalAddress", "streetAddress": "Nieuwewandeling 2, Ghent", "addressLocality": "Ghent", "addressCountry": "BE" }
},
"performer": [{ "@type": "PerformingGroup", "name": "KROMATIEK" }, { "@type": "PerformingGroup", "name": "CE$AR" }],
"organizer": { "@type": "Organization", "name": "Insomnia Nights", "url": "https://www.sway.events/promoter/697" },
"offers": [{ "@type": "Offer", "name": "Regular", "price": 20.0, "priceCurrency": "EUR", "availability": "https://schema.org/InStock", "url": "https://www.sway.events/event/4521?ref=api", "validFrom": "2026-07-01T10:00:00.000Z" }]
}
performer wordt opgebouwd uit de sets van de timetable (niet de ruwe line-up), dus het noemt elke naam één keer en volgt dezelfde regel "timetable uit" als de routes hierboven. Fouten: not_found (404).
GET /v1/events/{id}/gallery
De publieke fotoalbums van het evenement, elk met de foto's waarvan het uploaden voltooid is (de eerste 200) en hoeveel het er in totaal bevat.
Scope read:events. 300 s gecachet.
{
"event_id": 4521,
"data": [
{
"id": 12, "name": "Warm-up", "description": null,
"photos": [{ "id": 501, "url": "https://assets.sway.events/events/4521/gallery/501.webp", "width": 1600, "height": 1067 }],
"photo_count": 84
}
]
}
Private albums en foto's die nog aan het uploaden zijn, verschijnen nooit. Fouten: not_found (404).
GET /v1/events/{id}/partners
De partners van de promotors en locaties van het evenement, in weergavevolgorde: dezelfde vorm als GET /v1/partners (zie Content), verpakt onder { "event_id": 4521, "data": [...] }.
Scopes read:events en read:content (allebei verplicht). 300 s gecachet.
Fouten: not_found (404, evenement ongepubliceerd of buiten de graaf van de crew).
GET /v1/events/{id}/news
Het gepubliceerde nieuws van het evenement, nieuwste eerst, als markdown en als opgeschoonde HTML: dezelfde vorm als GET /v1/news (zie Content), verpakt onder event_id.
Scopes read:events en read:content (allebei verplicht). 120 s gecachet.
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
limit | geheel getal, 1 tot 100 | 25 | Paginagrootte |
cursor | ondoorzichtige string | geen | Uit een vorige pagina |
Fouten: not_found (404, evenement ongepubliceerd of buiten de graaf van de crew), invalid_cursor (400).
GET /v1/events/{id}/presales
De voorverkopen van het evenement die geen concept zijn, precies zoals de publieke voorverkooppagina ze toont: teaser, registratievenster, of de registratie nu open is.
Scope read:events. 60 s gecachet.
{
"event_id": 4521,
"data": [
{
"token": "f4c8b1a2-...", "status": "open", "registration_open": true,
"registration_opens_at": "2026-08-01T09:00:00.000Z", "registration_closes_at": "2026-09-05T23:59:00.000Z",
"featured": true, "featured_mode": "homepage",
"teaser": { "title": "Early access", "subtitle": "First 100 only", "image_url": null, "description": "Register for a chance at the first release." },
"url": "https://www.sway.events/presale/f4c8b1a2-..."
}
]
}
De producten, plafonds, selectieregel, promotor en mailinglijst achter een voorverkoop worden nooit blootgegeven. Fouten: not_found (404).
Locaties
Elke route hieronder aanvaardt een publishable key.
GET /v1/venues
De locaties van de graaf van de crew: de locaties die hij beheert (managed: true) en de locaties die zijn gepubliceerde evenementen hosten, publiek niveau, op naam.
Scope read:venues. 300 s gecachet.
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
q | tekst, 2 tot 100 tekens | geen | Naam bevat |
ids | kommalijst van id's, hoogstens 50 | geen | Alleen deze locaties |
limit | geheel getal, 1 tot 100 | 25 | Paginagrootte |
cursor | ondoorzichtige string | geen | Uit een vorige pagina |
{
"data": [
{
"id": 88, "name": "Jungle Bar", "image_url": "https://assets.sway.events/venues/88/cover.webp",
"description": "A cellar club in Ghent.", "location": { "address": "Nieuwewandeling 2, Ghent" },
"genres": [], "links": null,
"capacity": { "max": 300, "layouts": { "standing": 300, "seated": 120 } },
"managed": true
}
],
"pagination": { "next_cursor": null, "has_more": false, "limit": 25 }
}
Fouten: validation_error (400), invalid_cursor (400).
GET /v1/venues/{id}
Eén locatie van de graaf van de crew, publiek niveau, met zijn capaciteit, direct teruggegeven. Alleen bereikbaar wanneer de crew de locatie beheert of ze een gepubliceerd evenement van de graaf host.
Scope read:venues. 300 s gecachet.
Dezelfde itemvorm als hierboven (met managed). Fouten: not_found (404).
GET /v1/venues/{id}/events
De agenda van de locatie: elk gepubliceerd evenement van de graaf van de crew dat er speelt (allemaal wanneer de crew de locatie beheert). Dezelfde filters als GET /v1/events, zonder de pagina-/artiest-/locatiefilters.
Scopes read:venues en read:events (allebei verplicht). 60 s gecachet.
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
status | upcoming, past, all | upcoming | Welke evenementen |
from / to | ISO 8601-datum of datum-tijd | geen | Datumvenster |
limit | geheel getal, 1 tot 100 | 25 | Paginagrootte |
cursor | ondoorzichtige string | geen | Uit een vorige pagina |
Dezelfde envelop en itemvorm als GET /v1/events. Fouten: not_found (404, misvormd id of locatie buiten de graaf), validation_error (400), invalid_cursor (400).
GET /v1/venues/{id}/capacity
Hoeveel mensen de locatie herbergt per zaalopstelling (staand, zittend, theater, cabaret, banket, cocktail, klaslokaal), en het grootste cijfer: opstellingen zijn alternatieve indelingen van dezelfde zaal, nooit zones die optellen.
Scope read:venues. 300 s gecachet.
{ "venue_id": 88, "max": 300, "layouts": { "standing": 300, "seated": 120 } }
max en layouts zijn null en {} wanneer de locatie geen capaciteit opgeeft. Fouten: not_found (404).
Content
Elke route hieronder aanvaardt een publishable key.
GET /v1/news
Het gepubliceerde nieuws van één pagina die de crew beheert (een promotor, een locatie of een artiest), nieuwste eerst, als markdown en als opgeschoonde HTML. Een bericht dat voor later gepland staat, blijft buiten beeld tot zijn uur. GET /v1/events/{id}/news (zie Evenementen) is dezelfde feed voor één evenement in plaats van een pagina.
Scope read:content. 120 s gecachet.
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
promoter_id / venue_id / artist_id | positief geheel getal | geen | Precies één, die een pagina noemt die de crew beheert |
limit | geheel getal, 1 tot 100 | 25 | Paginagrootte |
cursor | ondoorzichtige string | geen | Uit een vorige pagina |
{
"data": [
{
"id": 88, "title": "Lineup announced",
"body_markdown": "The full lineup is **out now**.",
"body_html": "<p>The full lineup is <strong>out now</strong>.</p>",
"hero_image_url": "https://assets.sway.events/news/88/hero.webp",
"published_at": "2026-08-20T09:00:00.000Z"
}
],
"pagination": { "next_cursor": null, "has_more": false, "limit": 25 }
}
Fouten: validation_error (400, niet precies één van promoter_id / venue_id / artist_id), invalid_cursor (400), not_found (404, de genoemde pagina wordt niet door de crew beheerd).
GET /v1/partners
De partners van één promotor of locatie die de crew beheert, in weergavevolgorde.
Scope read:content. 300 s gecachet.
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
promoter_id / venue_id | positief geheel getal | geen | Precies één, die een pagina noemt die de crew beheert |
{
"data": [
{ "id": 9, "name": "Redbull", "logo_url": "https://assets.sway.events/partners/9/logo.webp", "website_url": "https://www.redbull.com", "owner": { "type": "promoter", "id": 697 } }
]
}
Fouten: validation_error (400, niet precies één van promoter_id / venue_id), not_found (404, de genoemde pagina wordt niet door de crew beheerd).
GET /v1/presskits
De perskits van elke artiest die de crew beheert, met hun zichtbaarheid (publiek, privé, concept) en of een wachtwoord ze beschermt. Een publishable key ziet alleen de publieke; een secret key ziet alle drie de statussen.
Scope read:content. 120 s gecachet.
{
"data": [
{ "id": "1b2c3d4e-5f60-4a1b-9c2d-3e4f5a6b7c8d", "artist_id": 245, "title": "KROMATIEK 2026 EPK", "status": "public", "protected": false, "is_default": true, "updated_at": "2026-09-01T10:00:00.000Z", "url": "https://www.sway.events/artist/245/presskit/1b2c3d4e-5f60-4a1b-9c2d-3e4f5a6b7c8d" }
]
}
Geen route-specifieke fouten.
GET /v1/presskits/{id}
Een perskit precies zoals zijn eigen pagina hem toont: de artiest, de secties in de gekozen volgorde, hun teksten en bestanden. Een beveiligde kit wil zijn wachtwoord in de header Presskit-Password, van elke aanroeper, de beherende crew inbegrepen.
Scope read:content. Nooit gecachet (het antwoord hangt af van een header die de cache niet ziet).
curl https://www.sway.events/api/v1/presskits/1b2c3d4e-5f60-4a1b-9c2d-3e4f5a6b7c8d \
-H "Authorization: Bearer sway_sk_YOUR_KEY" \
-H "Presskit-Password: secret"
{
"id": "1b2c3d4e-5f60-4a1b-9c2d-3e4f5a6b7c8d",
"artist_id": 245,
"title": "KROMATIEK 2026 EPK",
"status": "public",
"protected": false,
"is_default": true,
"updated_at": "2026-09-01T10:00:00.000Z",
"url": "https://www.sway.events/artist/245/presskit/1b2c3d4e-5f60-4a1b-9c2d-3e4f5a6b7c8d",
"artist": { "id": 245, "name": "KROMATIEK", "image_url": "https://assets.sway.events/artists/245/cover.webp", "description": "Ghent-based techno artist.", "genres": ["Techno"], "links": null, "is_verified": true, "managed": true, "contact_emails": [] },
"sections": ["hero", "music", "bio", "photos", "contact"],
"style": { "accent_color": "#111111", "hero_image_url": null },
"bio_version": "short",
"bio_overrides": {},
"press_quotes": [],
"files": [{ "id": "a1b2...", "type": "photo", "url": "https://assets.sway.events/presskits/.../photo.webp", "filename": "kromatiek-1.webp", "size_bytes": 240811 }]
}
Een private kit opent alleen voor de secret key van de beherende crew; een concept is nooit bereikbaar. Fouten: not_found (404, misvormd id, kit niet gevonden, artiest niet beheerd, kit is een concept, of een private kit aangeroepen met het verkeerde sleuteltype), password_required (401, wachtwoord ontbreekt of is fout), rate_limited (429, hoogstens 10 wachtwoordpogingen per minuut per sleutel en kit, en per bezoekersadres wanneer aangeroepen met een publishable key).
GET /v1/forms
De formulieren van de crew en van de pagina's die hij beheert, concepten buiten beschouwing gelaten, elk met vermelding of het nu antwoorden aanneemt.
Scope read:content. 120 s gecachet.
{
"data": [
{
"slug": "backstage-crew", "title": "Join the backstage crew", "description": null,
"availability": "open", "opens_at": null, "closes_at": null,
"owner": { "type": "promoter", "id": 697 },
"url": "https://www.sway.events/f/backstage-crew"
}
]
}
availability is een van draft, scheduled, open, full, closed, empty (een gepubliceerd formulier zonder vraag). Fouten: geen naast authenticatie.
GET /v1/forms/{slug}
De vragen, het ontwerp en de beschikbaarheid van een formulier, om het op de partnersite weer te geven, precies zoals zijn eigen publieke pagina zou doen.
Scope read:content. 60 s gecachet.
{
"id": "9f2c1a7e-4d3b-4e21-8c7a-1b2c3d4e5f60",
"slug": "backstage-crew",
"title": "Join the backstage crew",
"description": null,
"availability": "open",
"opens_at": null,
"closes_at": null,
"captures_contact": true,
"definition_version": 3,
"settings": { "show_progress": true, "submit_label": null, "consent_text": null },
"steps": [{ "id": "s1", "fields": [{ "id": "email", "type": "email", "label": "Email", "required": true }] }],
"design": {},
"url": "https://www.sway.events/f/backstage-crew"
}
steps en design zijn de definitie van het formulier zoals de formulierbouwer ze opslaat, ongewijzigd doorgegeven: de antwoorden die je post naar POST /v1/forms/{slug}/submit zijn geïndexeerd op de vraag-id's binnen steps. captures_contact zegt of een in het formulier opgegeven adres in de contacten van de organisator terechtkomt.
Fouten: not_found (404, foute vorm van de slug, conceptformulier, of een formulier dat niet van de crew of een van zijn pagina's is).
Export
Geen van deze routes aanvaardt een publishable key; elk heeft read:export nodig plus de bijpassende leesscope. Nooit gecachet (no-store), en elk is begrensd tot één export per resource per sleutel per vijf minuten, waarna het antwoord rate_limited (429) is. Elk bestand is begrensd tot 10.000 regels en meldt met een header X-Export-Truncated: true|false of het is afgekapt.
GET /v1/export/events
GET /v1/export/artists
GET /v1/export/promoters
GET /v1/export/venues
De gepubliceerde catalogus van de crew, één resource tegelijk, als newline-delimited JSON (application/x-ndjson): één JSON-object per regel, geen envelop, geen paginering. Elke regel is precies de DTO die de bijpassende lijstroute aflevert (GET /v1/events, GET /v1/artists, GET /v1/promoters, GET /v1/venues), zodat een export nooit meer toont dan de API al doet.
Scopes read:export + respectievelijk read:events / read:artists / read:promoters / read:venues.
{"id":4521,"title":"Overload","starts_at":"2026-09-12T20:00:00.000Z", ..., "venue":{"id":88,"name":"Jungle Bar"}}
{"id":4522,"title":"Warehouse Night","starts_at":"2026-09-19T21:00:00.000Z", ..., "venue":null}
Het antwoord wordt gedownload als sway-events.ndjson, sway-artists.ndjson, sway-promoters.ndjson of sway-venues.ndjson (Content-Disposition: attachment). Fouten: rate_limited (429, er liep al een export van deze resource voor deze sleutel in de laatste vijf minuten).
Bookingaanvragen
POST /v1/booking-requests
Dient een bookingaanvraag in vanaf een partnersite in de bookingpijplijn van de crew en stelt de crew op de hoogte. Elke aangevraagde artiest moet een beheerde roster-artiest zijn.
Scope write:bookings (opt-in). Publishable keys: nee. Nooit gecachet. Neemt Idempotency-Key. Strenger begrensd dan reads: 10 verzoeken per minuut per bezoeker (client_ip), en 300 per dag per crew.
| Veld | Type | Verplicht | Opmerkingen |
|---|---|---|---|
artist_ids | number[] | ja | Niet leeg, hoogstens 50 id's, elk een beheerde roster-artiest |
contact_email | string | ja | Geldig e-mailadres, hoogstens 320 tekens |
contact_name | string | nee | Hoogstens 200 tekens |
contact_phone | string | nee | Hoogstens 200 tekens |
event_name | string | nee | Hoogstens 200 tekens |
event_date | string | nee | ISO-datum, YYYY-MM-DD |
venue | string | nee | Hoogstens 200 tekens |
city | string | nee | Hoogstens 200 tekens |
fee_offer | string | nee | Vrije tekst, hoogstens 200 tekens |
capacity | string | nee | Vrije tekst, hoogstens 200 tekens |
ticket_price | string | nee | Vrije tekst, hoogstens 200 tekens |
organization | string | nee | Hoogstens 200 tekens |
{
"artist_ids": [245],
"contact_email": "[email protected]",
"contact_name": "Jane Doe",
"event_name": "Warehouse Night",
"event_date": "2026-11-21",
"venue": "Fuse",
"city": "Brussels",
"fee_offer": "800 EUR"
}
Antwoord 201 Created, direct teruggegeven:
{ "id": "9f2c1a7e-4d3b-4e21-8c7a-1b2c3d4e5f60", "status": "new", "created_at": "2026-07-03T14:00:00.000Z" }
Fouten: validation_error (422, foute vorm van de body, of artist_ids noemt een id buiten de roster, vermeld onder errors[].invalid_ids), rate_limited (429, limiet per bezoeker of per crew per dag).
Publiek
Geen van deze routes aanvaardt een publishable key.
POST /v1/newsletter-signup
Voegt een e-mailadres toe aan de nieuwsbrief van een beheerde promotor als CRM-contact, met een AVG-toestemmingsregistratie.
Scope write:newsletter (opt-in). Nooit gecachet. Neemt Idempotency-Key. Begrensd tot 10 verzoeken per minuut per bezoeker (client_ip), en 500 inschrijvingen per dag per promotor.
| Veld | Type | Verplicht | Opmerkingen |
|---|---|---|---|
email | string | ja | Geldig e-mailadres, hoogstens 320 tekens |
promoter_id | number | ja | Een promotor die de crew beheert |
first_name / last_name | string | nee | Hoogstens 200 tekens |
locale | string | nee | Hoogstens 10 tekens |
country | string | nee | Hoogstens 2 tekens |
{ "email": "[email protected]", "promoter_id": 697, "first_name": "Jane" }
Antwoord 201 Created: { "status": "subscribed" }.
Fouten: validation_error (422, foute body, of promoter_id niet beheerd door de crew), rate_limited (429).
POST /v1/newsletter-unsubscribe
Haalt een e-mailadres van de nieuwsbrief van een beheerde promotor en van zijn mailinglijstprovider af: dezelfde CRM-status die elke latere synchronisatie respecteert.
Scope write:newsletter (opt-in). Nooit gecachet. Neemt Idempotency-Key. Begrensd tot 10 verzoeken per minuut per bezoeker (client_ip), en 500 per dag per promotor.
| Veld | Type | Verplicht | Opmerkingen |
|---|---|---|---|
email | string | ja | Geldig e-mailadres |
promoter_id | number | ja | Een promotor die de crew beheert |
Antwoord 200 OK: altijd { "status": "unsubscribed" }, ongeacht of het adres op de lijst stond: de route mag een aanroeper nooit vertellen wie geabonneerd is.
Fouten: validation_error (422, foute body, of promoter_id niet beheerd), rate_limited (429).
POST /v1/forms/{slug}/submit
Verstuurt de antwoorden van een formulier dat de partnersite weergaf vanuit GET /v1/forms/{slug}: gevalideerd tegen de opgeslagen definitie, opgeslagen in de CRM van de eigenaar wanneer het formulier een contact vastlegt, met api:form:{slug} geregistreerd als toestemmingsbron.
Scope write:forms (opt-in). Nooit gecachet. Neemt Idempotency-Key. Begrensd tot 60 inzendingen per minuut per sleutel en formulier, 5 per minuut per bezoekersadres (wanneer client_ip wordt meegestuurd), en 5.000 per dag per formulier.
| Veld | Type | Verplicht | Opmerkingen |
|---|---|---|---|
answers | object | ja | Geïndexeerd op veld-id, zoals de eigen definitie van het formulier ze noemt |
locale | string | nee | Tweeletterige taaltag, optioneel met een regio |
honeypot | string | nee | Een verborgen veld van het eigen formulier van de partner: staat er tekst in, dan wordt het antwoord stilzwijgend genegeerd |
client_ip | string | nee | Het adres van de bezoeker, alleen gebruikt om zijn inzendingen te tellen |
{ "answers": { "email": "[email protected]", "s1_q1": "Yes" } }
Antwoord 201 Created: { "status": "received", "redirect_url": null } (een ingevulde honeypot antwoordt exact hetzelfde, maar slaat niets op).
Fouten: not_found (404, foute slug, conceptformulier, of een formulier dat niet van de crew is), validation_error (422, misvormde body of antwoorden die de eigen validatie van het formulier niet doorstaan, onder errors[].param als answers.<field>), conflict (409, not_taking_answers wanneer het formulier momenteel niet open is, already_answered wanneer het formulier maar één antwoord per adres toestaat en dit adres al heeft geantwoord), rate_limited (429).
Checkout
Geen van deze routes aanvaardt een publishable key.
POST /v1/checkout-sessions
Maakt een Stripe hosted-checkoutsessie aan voor een publieke storefront en geeft zijn url terug. De koper wordt daarheen doorgestuurd, en komt daarna terug op de eigen pagina /success of /cancel van Sway, nooit op de site van de aanroeper; de afhandeling (bestelling, tickets, bevestigingsmail) is volledig voor rekening van Sway.
Scope write:checkout (opt-in); een winkelmandje met een totaal van precies nul heeft daarnaast write:checkout:free nodig. Nooit gecachet. Neemt geen Idempotency-Key: deze route houdt in plaats daarvan zijn eigen bewaking aan (idempotency_key in de body, hieronder). Begrensd tot 60 verzoeken per minuut per koper (client_ip), 600 per minuut per sleutel, 5.000 checkouts per dag per crew, en 30 betaalde (of 10 gratis) checkouts per dag per e-mailadres van de koper.
Alles wat gezaghebbend is voor geld en voorraad wordt server-side bepaald en kan nooit door de aanroeper worden aangeleverd of overschreven: de prijs, de valuta, het Stripe-account van de ontvanger, de servicekosten en de voorraadreservering. De crew van de sleutel moet de promotor beheren die het geld ontvangt, anders validation_error.
| Veld | Type | Verplicht | Opmerkingen |
|---|---|---|---|
event_id | number | ja | Moet gepubliceerd zijn en in de graaf van de crew liggen |
line_items | array | ja | 1 tot 20 items van { "tier_id": string, "quantity": number }; tier_id is een tier-id uit GET /v1/events/{id}/ticket-tiers, quantity 1 tot 50 |
buyer_email | string | ja | Geldig e-mailadres, hoogstens 320 tekens: waar de tickets heen gaan |
idempotency_key | string | nee | Een UUID per koopklik; een retry met dezelfde waarde geeft dezelfde sessie terug |
discount_id | string | nee | Een coupon-id voor het evenement, uit POST /v1/coupons/validate |
access_code | string | nee | Een voorverkoop- of toegangscode die een verborgen tickettype ontgrendelt |
reference | string | nee | Vrije tekst, hoogstens 64 tekens uit [A-Za-z0-9._:-], alleen weerspiegeld in analytics |
locale | string | nee | De taal van de koper (en, fr, nl...), gebruikt om de regel met servicekosten op de Stripe-betaalpagina te benoemen. Standaard de Accept-Language van het verzoek, daarna Engels |
marketing_consent | boolean | nee | Genegeerd op dit pad; toestemming beweerd door een API-sleutel wordt nooit vertrouwd voor CRM-inschrijving |
consent | object | nee | Booleans { analytics, marketing } plus version/at, alleen doorgestuurd naar de registratie van advertentie-attributie |
client_ip / client_user_agent / event_source_url | string | nee | Signalen aan koperszijde voor het matchen van advertentie-attributie, en client_ip om de checkouts van de koper te tellen. Nooit voor iets anders gebruikt |
Velden die met validation_error worden geweigerd als ze zijn meegestuurd, omdat elk ervan server-side wordt bepaald: amount / price / unit_amount, currency, elke ontvanger of stripe_account, application_fee_amount / fee, success_url / cancel_url / return_url, coupon / coupon_code / stripe_coupon_id, payment_method_types, user_id.
{
"event_id": 4521,
"line_items": [{ "tier_id": "8f14e45f-ceea-467a-9575-b2c45e4f2a11", "quantity": 2 }],
"buyer_email": "[email protected]",
"idempotency_key": "b1e2c3d4-5f60-4a1b-9c2d-3e4f5a6b7c8d"
}
Antwoord 200 OK, direct teruggegeven:
{ "url": "https://checkout.stripe.com/c/pay/cs_live_...", "checkout_id": "chk_9f2c1a7e..." }
checkout_id volgt alleen bij een betaalde sessie; een gratis (comp-)bestelling geeft alleen { "url": ... } terug, aangezien er geen Stripe-sessie is om achteraf te volgen.
Een betaalde checkout houdt zijn tickets, en één gebruik van zijn coupon en van zijn toegangscode, vast gedurende de 30 minuten van de sessie. Wat de koper niet betaalt, komt terug wanneer de sessie verloopt; tot dan antwoordt een code waarvan het laatste gebruik wordt vastgehouden met validation_error.
write:checkout:free nodig. Gratis en betaalde tickets kunnen niet in één bestelling worden gecombineerd.Fouten: missing_scope (403, geen write:checkout, of een gratis bestelling zonder write:checkout:free), not_found (404, evenement ongepubliceerd of buiten de graaf), validation_error (422, foute body, onbekend of niet beschikbaar tickettype, aantal boven max_per_order, gemengde gratis en betaalde regels, of de ontvanger niet beheerd door de crew), conflict (409, het betaalaccount van de promotor is nog niet klaar), rate_limited (429, controleer Retry-After), upstream_error (502, Stripe kon de sessie niet aanmaken).
GET /v1/checkout-sessions/{id}
Waar een checkout die deze crew opende staat, geadresseerd met de checkout_id die het aanmaken ervan teruggaf, nooit het Stripe-sessie-id: open (met zijn betaallink), voltooid of verlopen.
Scope write:checkout. Nooit gecachet (no-store).
{
"checkout_id": "chk_9f2c1a7e...",
"status": "open",
"payment_status": "unpaid",
"amount_total": 4552,
"currency": "eur",
"expires_at": "2026-09-26T13:00:00.000Z",
"reference": null,
"url": "https://checkout.stripe.com/c/pay/cs_live_..."
}
url is alleen aanwezig terwijl status open is. Fouten: not_found (404, misvormde handle, of een checkout die aan een andere crew toebehoort).
POST /v1/checkout-sessions/{id}/expire
Beëindigt een open checkout die deze crew opende en geeft zijn tickets meteen terug aan de voorraad, in plaats van te wachten op de eigen timer van Stripe. Idempotent: hem opnieuw aanroepen op een al verlopen checkout antwoordt gewoon met zijn huidige status.
Scope write:checkout. Nooit gecachet. Neemt Idempotency-Key.
Dezelfde antwoordvorm als GET /v1/checkout-sessions/{id}. Fouten: not_found (404, hetzelfde als hierboven), conflict (409, de checkout was al betaald: een terugbetaling verloopt in plaats daarvan via de organisator).
POST /v1/coupons/validate
Controleert een promocode vóór de checkout: de door te geven discount_id, zijn voorwaarden, en de totalen van het winkelmandje wanneer er een is meegestuurd, of waarom hij niet geldt. Antwoordt hoe dan ook 200: een geweigerde code is een antwoord, geen fout.
Scope write:checkout. Nooit gecachet. Neemt geen Idempotency-Key (writeClass: check): hij draait elke keer, tot 300 controles per minuut per sleutel, bovenop de gokgrenzen hieronder.
| Veld | Type | Verplicht | Opmerkingen |
|---|---|---|---|
event_id | number | ja | Moet een evenement zijn waarvan de crew de ontvanger beheert |
code | string | ja | 1 tot 64 afdrukbare tekens |
line_items | array | nee | Het winkelmandje van de checkout, dezelfde vorm als POST /v1/checkout-sessions |
client_ip | string | nee | Het adres van de koper, alleen gebruikt om zijn misses te tellen |
{ "event_id": 4521, "code": "EARLY10", "line_items": [{ "tier_id": "8f14e45f-ceea-467a-9575-b2c45e4f2a11", "quantity": 2 }] }
{
"valid": true, "code": "EARLY10", "discount_id": "f4c8b1a2-...",
"percentage": 10, "amount": null, "products_remaining": 4,
"totals": { "currency": "EUR", "subtotal": 5000, "discount": 500, "total": 4500 }
}
Een code die bij een ander evenement of een andere organisator hoort, of een die uitgeschakeld is, antwoorden allemaal ononderscheidbaar met { "valid": false, "code": "...", "reason": "not_found" }. Andere waarden voor reason: min_order (met min_order_amount), product_limit (met products_remaining), expired, usage_limit, not_open_here, not_applicable. Het Stripe-coupon-id verlaat het systeem nooit.
Fouten: validation_error (422, foute body), not_found (404, evenement ongepubliceerd of buiten de graaf), validation_error (422, ontvanger niet beheerd door de crew), rate_limited (429, het plafond aan controles per minuut, of de gokgrens hieronder).
POST /v1/access-codes/validate
Controleert een voorverkoop- of toegangscode: de verborgen tickettypes die hij ontgrendelt (nooit vermeld door GET /v1/events/{id}/ticket-tiers), of de organisator alleen die tickettypes wil tonen, en het eigen plafond per bestelling van de code, of waarom hij niet werkt.
Scope write:checkout. Nooit gecachet. Neemt geen Idempotency-Key (writeClass: check), hetzelfde plafond van 300 controles per minuut als coupons.
| Veld | Type | Verplicht | Opmerkingen |
|---|---|---|---|
event_id | number | ja | Moet een evenement zijn waarvan de crew de ontvanger beheert |
code | string | ja | 1 tot 64 afdrukbare tekens |
client_ip | string | nee | Het adres van de koper, alleen gebruikt om zijn misses te tellen |
{
"valid": true, "code": "VIP", "name": "Members", "exclusive": true, "max_per_order": 2,
"tiers": [{ "id": "8f14e45f-ceea-467a-9575-b2c45e4f2a11", "name": "Presale", "description": null, "price": 25.0, "currency": "EUR", "status": "on_sale", "sale_start": null, "sale_end": null, "max_per_order": 4, "checkout_url": "https://www.sway.events/event/4521?ref=api&code=VIP" }]
}
exclusive: true betekent dat de organisator alleen deze ontgrendelde tickettypes wil tonen zodra de code is ingevoerd. De eigen interne id's van de code verlaten het systeem nooit. Andere waarden voor reason bij weigering: not_found, inactive, not_started, ended, usage_limit.
Gokgrenzen (beide routes hierboven). Naast het algemene plafond aan controles per minuut wordt een onbekende code geteld per sleutel en evenement (300 missers per 10 minuten) en, wanneer de aanroeper client_ip meestuurt, ook per adres van de koper (10 missers per 15 minuten): voorbij een van beide grenzen is het antwoord rate_limited (429) nog vóór de code al is opgezocht.
Fouten: dezelfde als POST /v1/coupons/validate.
Shop
De drie leesroutes accepteren een publishable key; de offerte en de checkout niet.
De merch van de pagina's die je crew beheert, voor een eigen shop: de catalogus van een pagina, een product, wat een event verkoopt, de prijs van een winkelmand en een Stripe-checkout op de eigen rekening van de verkopende pagina. De koper betaalt bij Stripe en komt terug op de pagina's van Sway; Sway legt de bestelling vast, mailt koper en verkoper, en de verkoper regelt verzending, herroepingen en terugbetalingen vanuit het scherm Shop van de pagina.
Een pagina verkoopt zodra haar shop open is; daarvoor leest haar catalogus leeg. Prijzen zijn inclusief btw, in eurocent. Geen enkele route geeft een voorraad: een variant is available of niet.
GET /v1/shop/products
De gepubliceerde merch van een pagina van de crew, met de verkopersidentiteit die kopers moeten zien voor ze betalen. Event-exclusives staan er niet in: lees ze bij het event.
Scope read:shop. Publishable keys: ja. 30 s gecachet.
| Parameter | Type | Verplicht | Opmerkingen |
|---|---|---|---|
seller_type | string | ja | promoter, artist of venue |
seller_id | number | ja | Een pagina die de crew beheert |
{
"seller": {
"type": "promoter", "id": 697, "name": "Insomnia Nights", "image_url": null,
"legal_name": "Insomnia Nights SRL", "address": "Rue de la Loi 1, 1000 Brussels, BE",
"company_number": "BE0123456789", "contact_email": "[email protected]",
"vat_regime": "registered", "return_shipping_paid_by": "buyer"
},
"installments": { "provider": "stripe", "publishable_key": "pk_live_...", "stripe_account": "acct_1Abc...", "country": "BE", "methods": ["klarna"] },
"data": [
{
"id": "3f2c5e1a-7b4d-4c1e-9a2b-5d6e7f8a9b0c", "slug": "tour-hoodie-2026", "title": "Tour Hoodie 2026",
"description": "Heavyweight cotton.",
"images": [{ "url": "https://assets.sway.events/shop/hoodie.webp", "alt": null, "width": 1200, "height": 1200 }],
"options": ["Size"],
"variants": [{ "id": "9a1b7c2d-3e4f-4a5b-8c6d-7e8f9a0b1c2d", "options": ["M"], "price_cents": 4500, "available": true, "max_per_order": 20 }],
"from_price_cents": 4500, "currency": "EUR", "available": true,
"fulfilment_modes": ["delivery", "pickup_event"], "country_rule": "all", "countries": [], "exclusive": false,
"manufacturer": { "name": "Insomnia Nights SRL", "address": "Rue de la Loi 1, 1000 Brussels", "email": "[email protected]" },
"eu_responsible": null, "safety_info": "Wash at 30 degrees.", "preparation_days": 2, "preorder": null,
"seller": { "type": "promoter", "id": 697 }
}
]
}
Een kleine lijst: verpakt in { "data": [...] }, zonder pagination. Een pagina die de crew niet beheert, of waarvan de shop niet open is, antwoordt { "seller": null, "data": [] }. fulfilment_modes noemt delivery, pickup_event en pickup_location; country_rule is all, only of except, toegepast op countries. Fouten: validation_error (422, seller_type of seller_id ontbreekt of is ongeldig).
preorder is null, of { "status": "open", "ships_on": "2026-11-15", "ends_on": null } voor een product dat verkocht wordt voor het klaar is: verzending vanaf ships_on, pre-orders tot ends_on als die is ingesteld. status is closed zodra de pre-order voor de verzenddag sloot; de varianten geven dan available: false. Op de verzenddag verkoopt het product als elk ander en wordt preorder weer null.
installments is null, of het termijnbetalingsaanbod van Stripe op het account van de verkopende pagina. Als het er is, toon dan het Payment Method Messaging Element van Stripe met publishable_key en stripe_account (Stripe.js), nooit eigen tekst: reclame voor krediet in termijnen is gereglementeerd. methods somt op wat Checkout aanbiedt (klarna); country is dat van de verkoper, een standaard tot de koper een leveringsland kiest. Het product en de eventshop dragen hetzelfde veld.
GET /v1/shop/products/{id}
Een product voor zijn productpagina, direct teruggegeven, met seller als volledige verkopersidentiteit. Met event_id het product zoals dat event het verkoopt, exclusives inbegrepen.
Scope read:shop. Publishable keys: ja. 30 s gecachet.
| Parameter | Type | Verplicht | Opmerkingen |
|---|---|---|---|
event_id | number | nee | Een event uit de graaf van de crew waarvan de shop open is |
Fouten: not_found (404, onbekend of niet gepubliceerd product, een pagina die de crew niet beheert, een exclusive gevraagd zonder zijn event, of een event met een gesloten shop).
GET /v1/events/{id}/shop
Wat een event uit de graaf van de crew verkoopt: de producten van zijn betaalde promotor, alle of een selectie, exclusives inbegrepen, zolang de eventshop open is; en of kopers nog afhalen op het event kunnen kiezen.
Scope read:shop. Publishable keys: ja. 30 s gecachet.
{
"event_id": 4521,
"seller": { "type": "promoter", "id": 697, "name": "Insomnia Nights", "legal_name": "Insomnia Nights SRL" },
"pickup_at_event": { "open": true, "cutoff_at": "2026-10-10T20:00:00.000Z", "instructions": "Merch stand, left of the bar, from doors" },
"data": [{ "id": "3f2c5e1a-7b4d-4c1e-9a2b-5d6e7f8a9b0c", "title": "Tour Hoodie 2026", "exclusive": false }]
}
seller bevat de volledige verkopersidentiteit, zoals in de lijst hierboven. De lijst is leeg, met seller en pickup_at_event op null, zolang de eventshop gesloten is, of wanneer de betaalde promotor geen pagina van de crew is, omdat de checkout niet voor hem zou kunnen verkopen. Fouten: not_found (404, een niet gepubliceerd event of een buiten de graaf).
POST /v1/shop/quote
Berekent een winkelmand voor de checkout: de regels na de kortingscode, de verzendopties voor een manier en een land, de manieren en landen die de winkelmand toelaat, en het totaal. Er wordt niets gereserveerd.
Scope read:shop. Publishable keys: nee. Nooit gecachet. Beperkt tot 120 verzoeken per minuut per koper (client_ip).
| Veld | Type | Verplicht | Opmerkingen |
|---|---|---|---|
lines | array | ja | 1 tot 20 items { "variant_id": string, "quantity": number }, aantal 1 tot 20 |
mode | string | ja | delivery, pickup_event of pickup_location |
event_id | number | nee | Het event waar de winkelmand vandaan komt: het ontgrendelt zijn exclusives en afhalen op het event |
country | string | bij delivery | Tweeletterige code van het leverland |
coupon_code | string | nee | Een code van de verkopende pagina |
method_key | string | nee | De gekozen verzendoptie, uit shipping_options |
client_ip | string | nee | Het adres van de koper, om zijn verzoeken te tellen |
{
"currency": "EUR",
"lines": [{ "variant_id": "9a1b7c2d-3e4f-4a5b-8c6d-7e8f9a0b1c2d", "name": "Tour Hoodie 2026 · M", "quantity": 2, "unit_cents": 4500, "discount_cents": 900 }],
"subtotal_cents": 9000,
"discount_cents": 900,
"shipping_options": [
{ "key": "b1c2d3e4-f5a6-4b7c-8d9e-0f1a2b3c4d5e", "kind": "delivery", "name": "bpost, 2 to 4 days", "carrier": "bpost", "amount_cents": 590, "min_days": 2, "max_days": 4, "pickup_address": null, "instructions": null }
],
"selected_option": "b1c2d3e4-f5a6-4b7c-8d9e-0f1a2b3c4d5e",
"shipping_cents": 590,
"total_cents": 8690,
"available_modes": ["delivery", "pickup_event"],
"deliverable_countries": ["BE", "FR", "NL"],
"coupon": { "code": "TOUR10", "discount_cents": 900 },
"ships_on": null
}
ships_on is de verzenddag van de bestelling als de winkelmand een pre-order bevat, de laatste ervan; de koper ziet hem voor de betaling, ook op de Stripe-pagina. Voor een winkelmand op voorraad is hij null. not_ready_for_event weigert afhalen op het event voor een winkelmand die pas daarna verzonden wordt; preorder_closed draagt de variant_id waarvan de pre-order gesloten is.
Fouten: validation_error (422) met een reason: invalid_cart, invalid_mode, unavailable, out_of_stock, max_per_order, mixed_sellers, country_required, country_not_allowed, no_method, mode_not_allowed, pickup_closed, preorder_closed, not_ready_for_event, of een reden die begint met coupon_. max_per_order draagt variant_id en max; een geweigerde levering draagt available_modes en deliverable_countries. Verder conflict (409, reden not_ready: de pagina kan nog niet verkopen), not_found (404, een event buiten de graaf) en rate_limited (429).
POST /v1/shop/cart-check
Zegt welke regels van de winkelmand die een koper bewaart naar een product wijzen dat de shop heeft verlaten: offline gehaald, gearchiveerd of verwijderd, of een uitgeschakelde of verwijderde variant. Haal die regels uit de winkelmand. Een uitverkochte variant, een pagina die nog niet kan verkopen of een event waarvan de shop dicht is, houdt zijn regel: dat kan weer veranderen, en de offerte legt het uit. Een regel van een pagina die je crew niet beheert, komt ook terug.
Scope read:shop. Publishable keys: nee. Nooit gecachet. Beperkt tot 120 verzoeken per minuut per koper (client_ip).
| Veld | Type | Verplicht | Opmerkingen |
|---|---|---|---|
lines | array | ja | 1 tot 20 items { "variant_id": string, "product_id": string } |
client_ip | string | nee | Het adres van de koper, om zijn verzoeken te tellen |
{ "gone": ["9a1b7c2d-3e4f-4a5b-8c6d-7e8f9a0b1c2d"] }
Controleer de winkelmand wanneer de koper terugkomt op de site en wanneer de winkelmand opengaat.
Fouten: validation_error (422, een ontbrekende of foutieve regel) en rate_limited (429).
POST /v1/shop/checkout-sessions
Opent een gehoste Stripe-checkout voor merch van een pagina die de crew beheert, op de eigen Stripe-rekening van die pagina, en geeft de url terug. De koper betaalt daar en komt daarna op de bedankpagina van Sway en zijn bestelpagina, of op /cancel, nooit op de site van de aanroeper. Sway legt de bestelling vast, mailt koper en verkoper, en houdt zijn commissie in bij de verkoper.
Scope write:shop:checkout (opt-in). Publishable keys: nee. Nooit gecachet. Neemt geen Idempotency-Key aan: stuur idempotency_key in de body. Beperkt tot 60 verzoeken per minuut per koper (client_ip), 5000 checkouts per dag per crew en 30 per dag per koper-e-mail.
De body is die van de offerte, plus:
| Veld | Type | Verplicht | Opmerkingen |
|---|---|---|---|
buyer_email | string | ja | Waar de bevestiging en de bestellink naartoe gaan |
idempotency_key | string | nee | Een UUID per klik op Betalen; een nieuwe poging met dezelfde waarde geeft dezelfde sessie |
locale | string | nee | De taal van de koper voor Stripe en de e-mails: en, fr, de, es, it, nl of uk |
reference | string | nee | Vrij, hoogstens 64 tekens uit [A-Za-z0-9._:-], bewaard bij de bestelling |
Velden die met validation_error worden geweigerd, omdat elk aan de serverkant wordt bepaald: amount, price, unit_amount, unit_cents, price_cents, total_cents, shipping_cents, currency, seller_type, seller_id, payee, stripe_account, application_fee_amount, fee, commission, success_url, cancel_url, return_url, discount_id, stripe_coupon_id, user_id.
{
"lines": [{ "variant_id": "9a1b7c2d-3e4f-4a5b-8c6d-7e8f9a0b1c2d", "quantity": 2 }],
"mode": "delivery",
"country": "BE",
"coupon_code": "TOUR10",
"buyer_email": "[email protected]",
"idempotency_key": "b1e2c3d4-5f60-4a1b-9c2d-3e4f5a6b7c8d"
}
Antwoord 200 OK: { "url": "https://checkout.stripe.com/c/pay/cs_live_..." }
De voorraad wordt vastgehouden voor de 30 minuten van de sessie; wat de koper niet betaalt, komt terug wanneer de sessie verloopt. Een marketingtoestemming die de aanroeper meestuurt, wordt genegeerd: een API-sleutel schrijft een koper nooit in een CRM in.
Fouten: die van de offerte, plus validation_error voor een ongeldige buyer_email of reference, of voor producten van een pagina die de crew niet beheert; conflict (409, not_ready, of de voorraad veranderde onder de winkelmand); rate_limited (429, zie Retry-After); upstream_error (502, Stripe kon de sessie niet aanmaken).
Ambassadeurs
Het referralprogramma van de promotor, weergegeven op de eigen site van de partner in plaats van op sway.events. Geen van deze routes aanvaardt een publishable key: draai ze vanaf een server, nooit een browser. Er zijn drie inloggegevens in het spel: de API-sleutel sway_sk_... (welke crew er aanroept), een ledensessie amb_st_... die meereist in de header X-Ambassador-Session (welke ambassadeur is ingelogd, aangemaakt bij registratie of aanmelden, 8 uur geldig), en de eigen first-party cookie van de partner die een bezoeker aan die sessie koppelt.
GET /v1/ambassador-program
Alles wat een pagina "word ambassadeur" nodig heeft: de naam en beschrijving van het programma, de korting die het biedt, of het momenteel nieuwe mensen aanneemt, en de eigen woorden van de promotor voor XP, niveaus, quests en badges. Alleen publieke data, geen lid en geen ledenaantal.
Scope read:ambassadors. 120 s gecachet.
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
owner_type | promoter, venue | verplicht | Van wiens programma |
owner_id | positief geheel getal | verplicht | Het id van de pagina |
{
"ok": true,
"program": { "name": "Insomnia Ambassadors", "description": "Bring your friends, earn rewards." },
"owner": { "type": "promoter", "id": 697 },
"discount": { "percentage": 15 },
"signup": { "open": true, "seats_left": 42 }
}
Het antwoord herhaalt ook name, description, signup_open en gamification_enabled op het hoogste niveau, voor sites die op de eerste versie van de Insomnia-boilerplate zijn gebouwd. Lees de geneste velden: die beschrijft deze pagina.
Een eigenaar buiten de graaf van de crew antwoordt met dezelfde 404 als een eigenaar zonder programma: deze route mag nooit verraden welke promotors die de sleutel niet beheert er toevallig een draaien.
Fouten: validation_error (422, owner_type / owner_id ontbreekt of is misvormd: deze route dateert van vóór de 400-regel voor queryparameters en behoudt zijn antwoord), not_found (404).
GET /v1/ambassador-leaderboard
Het klassement van het programma, alleen wanneer de promotor het publiceert: rang, voornaam en initiaal van de achternaam, score. Een klassement op omzet geeft de volgorde, nooit de bedragen.
Scope read:ambassadors. 60 s gecachet.
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
owner_type | promoter, venue | verplicht | Van wiens programma |
owner_id | positief geheel getal | verplicht | Het id van de pagina |
limit | geheel getal, 1 tot 100 | 25 | Hoeveel rangen |
{
"metric": "tickets",
"data": [
{ "rank": 1, "name": "Melanie P.", "score": 42, "tier": { "name": "Gold", "color": "#f5c542" } },
{ "rank": 2, "name": "Tom D.", "score": 37, "tier": null }
]
}
metric is tickets, xp of revenue. Bij revenue is score null: de volgorde toont wie het meest verkocht, nooit hoeveel. tier is alleen gezet terwijl de niveaus van het programma aan staan.
Fouten: validation_error (400, owner_type / owner_id ontbreekt of is misvormd), not_found (404, geen programma, of het programma publiceert zijn klassement niet).
GET /v1/ambassador-rewards
De rewards waaraan leden hun credits besteden: kosten, wat er nog is, wanneer, en het niveau dat ze nodig hebben. Leeg terwijl credits uitgeschakeld zijn.
Scope read:ambassadors. 60 s gecachet.
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
owner_type | promoter, venue | verplicht | Van wiens programma |
owner_id | positief geheel getal | verplicht | Het id van de pagina |
{
"credits_enabled": true,
"label_singular": "credit",
"label_plural": "credits",
"data": [
{
"id": "7c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
"name": "Backstage tour",
"description": "Meet the crew before doors open.",
"image_url": null,
"cost": 50,
"stock_left": 8,
"max_per_member": 1,
"available_from": null,
"available_until": "2026-12-31T23:00:00+00:00",
"available": true,
"event": { "id": 4521, "title": "Insomnia Night: Autumn Opening" },
"min_tier": { "id": "2b3c4d5e-6f70-4812-9a3b-4c5d6e7f8091", "name": "Gold", "min_xp": 500 },
"claim_prompt": "Which night suits you?"
}
]
}
stock_left is null wanneer de reward geen voorraadlimiet heeft. available is false buiten zijn data of zodra hij op is. claim_prompt is de vraag die het lid beantwoordt bij het aanvragen (de answer van POST /v1/ambassador-claim).
Fouten: validation_error (400, owner_type / owner_id), not_found (404, geen programma).
GET /v1/ambassador-quests
De quests die leden nu kunnen aangaan: doel, data en rewards. De eigen voortgang van een ingelogd lid staat in GET /v1/ambassador-me, nooit hier.
Scope read:ambassadors. 60 s gecachet.
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
owner_type | promoter, venue | verplicht | Van wiens programma |
owner_id | positief geheel getal | verplicht | Het id van de pagina |
{
"enabled": true,
"quest_noun": "quest",
"xp_label": "XP",
"badge_noun": "badge",
"data": [
{
"id": "3d4e5f60-7182-4a93-b4c5-d6e7f8091a2b",
"name": "Bring five friends",
"description": null,
"image_url": null,
"metric": "tickets",
"scope": "event",
"threshold": 5,
"event": { "id": 4521, "title": "Insomnia Night: Autumn Opening" },
"starts_at": null,
"ends_at": "2026-10-03T20:00:00+00:00",
"xp_reward": 100,
"credit_reward": 20,
"badge": { "id": "4e5f6071-8293-4a4b-85c6-e7f8091a2b3c", "name": "Recruiter", "image_url": null, "icon": "users", "rarity": "silver" }
}
]
}
metric is waarvan het lid de threshold moet bereiken: orders, tickets, revenue_cents, credits_earned, reward_claimed, profile_complete of manual (de organisator vinkt het af). scope is lifetime (sinds het lid toetrad), event (op één evenement, of op eender welk evenement wanneer event null is) of window (tussen starts_at en ends_at). data is leeg terwijl gamification uit staat.
Fouten: validation_error (400, owner_type / owner_id), not_found (404, geen programma).
GET /v1/ambassadors
De leden van het programma voor de eigen tools van de promotor, nieuwste eerst: naam, e-mail, Instagram, code, status, verkopen, credits, XP en niveau. Nooit de telefoon, het toegangstoken of het Sway-account.
Scope read:ambassador-members (alleen de crew-eigenaar: alleen de eigenaar van de crew kent hem toe). Nooit gecachet (no-store).
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
owner_type | promoter, venue | verplicht | Van wiens programma |
owner_id | positief geheel getal | verplicht | Het id van de pagina |
q | tekst | geen | Matcht naam, e-mail, Instagram of code |
status | active, pending, suspended | geen | Filter op status |
limit | geheel getal, 1 tot 100 | 25 | Paginagrootte |
cursor | ondoorzichtige string | geen | Uit een vorige pagina |
{
"data": [
{
"id": "5f0c6a0e-2b1d-4c3e-9f8a-7b6c5d4e3f21", "first_name": "Melanie", "last_name": "Pauwels",
"email": "[email protected]", "instagram_handle": "mel", "locale": "nl", "status": "active", "code": "MELANPAU",
"sales": { "orders": 4, "tickets": 9, "revenue_cents": 27000 }, "credit_balance": 12, "xp": 340, "tier": "Gold",
"joined_at": "2026-09-01T00:00:00.000Z"
}
],
"pagination": { "next_cursor": null, "has_more": false, "limit": 25 }
}
Fouten: validation_error (400, owner_type / owner_id / status), invalid_cursor (400), not_found (404, geen programma voor deze eigenaar).
GET /v1/ambassadors/{id}/ledger
De credit-geschiedenis van één lid, nieuwste eerst, met zijn lopende saldo: wat elke verkoop, aanvraag, quest of handmatige toekenning toevoegde of afnam.
Scope read:ambassador-members. Nooit gecachet.
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
limit | geheel getal, 1 tot 100 | 25 | Paginagrootte |
cursor | ondoorzichtige string | geen | Uit een vorige pagina |
{
"member": { "id": "5f0c6a0e-2b1d-4c3e-9f8a-7b6c5d4e3f21", "first_name": "Melanie", "last_name": "Pauwels", "status": "active" },
"credits_enabled": true,
"balance": 12,
"data": [{ "id": "7a1b...", "amount": 3, "reason": "ticket_sale", "note": null, "created_at": "2026-09-20T18:00:00.000Z" }],
"pagination": { "next_cursor": null, "has_more": false, "limit": 25 }
}
De eigenaar die de crew moet beheren wordt gelezen uit het eigen programma van het lid, nooit uit het verzoek: een lid van een andere crew antwoordt met dezelfde 404 als een onbekend id. Fouten: not_found (404, misvormd id of lid buiten de programma's van de crew), invalid_cursor (400).
GET /v1/ambassador-stats
Hoe het programma ervoor staat: leden per status en het aandeel actieve leden dat verkoopt, de verkopen die zijn codes opbrachten (lifetime, en tussen from en to wanneer opgegeven), en de tien beste codes over dezelfde periode.
Scope read:ambassador-members. Nooit gecachet.
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
owner_type | promoter, venue | verplicht | Van wiens programma |
owner_id | positief geheel getal | verplicht | Het id van de pagina |
from / to | ISO 8601-datum of datum-tijd | geen | Periode, hoogstens 400 dagen uit elkaar, to na from |
{
"members": { "total": 12, "active": 8, "pending": 3, "suspended": 1, "selling": 3, "selling_rate": 0.375 },
"lifetime": { "orders": 20, "tickets": 41, "revenue_cents": 90000 },
"window": null,
"top_codes": []
}
Fouten: validation_error (400, owner_type / owner_id, of een periode die omgekeerd is of langer dan 400 dagen), not_found (404, geen programma).
POST /v1/ambassador-register
Iemand sluit zich aan bij het programma vanaf de eigen site van de partner. Geeft zijn code en een ledensessie terug, zodat de storefront meteen zijn pagina kan tonen.
Scope write:ambassadors (opt-in). Nooit gecachet. Neemt Idempotency-Key. Begrensd tot 30 registraties per minuut per bezoeker (client_ip, afgestemd op de gedeelde wifi van een locatie), en 300 per dag per programma.
| Veld | Type | Verplicht | Opmerkingen |
|---|---|---|---|
owner_type | string | ja | promoter of venue |
owner_id | number | ja | Het id van de pagina |
first_name / last_name | string | ja | Hoogstens 120 tekens |
email | string | ja | Geldig e-mailadres; de enige weg terug naar een verloren pagina |
phone | string | ja | Een echt telefoonnummer; de ontdubbelsleutel voor het programma |
locale | string | nee | Hoogstens 8 tekens |
{ "owner_type": "promoter", "owner_id": 697, "first_name": "Jane", "last_name": "Doe", "email": "[email protected]", "phone": "+32470000000" }
Antwoord: 201 bij een echt nieuw lid, 200 wanneer het al bestond:
{ "created": true, "member_id": "6b1d...", "code": "MELANPAU", "status": "active", "session": { "token": "amb_st_...", "expires_at": "2026-09-01T18:00:00.000Z" } }
Een telefoonnummer dat al is ingeschreven in dit programma wordt geweigerd, niet ingelogd: wie het nummer intypte is niet per se degene van wie het is.
Fouten: validation_error (422, velden ontbreken of zijn ongeldig, of een wegwerp-/geblokkeerd e-mailadres), not_found (404, eigenaar buiten de graaf van de crew), conflict (409, signup_closed tenzij de promotor publiek aanmelden heeft aangezet en een actieve storefront-uitnodiging nog quotum heeft, of already_registered voor een telefoon die al is ingeschreven), rate_limited (429).
POST /v1/ambassador-login
Mailt een lid een eenmalige inloglink die terugleidt naar de eigen site van de partner.
Scope write:ambassadors. Nooit gecachet. Neemt Idempotency-Key. Begrensd tot 8 per minuut per bezoeker (client_ip), en 5 per uur per e-mailadres voor het effectieve versturen.
| Veld | Type | Verplicht | Opmerkingen |
|---|---|---|---|
owner_type | string | ja | promoter of venue |
owner_id | number | ja | Het id van de pagina |
email | string | ja | Waarheen de link gestuurd wordt |
return_origin | string | ja | Een van de origins die op deze sleutel geregistreerd staan |
return_path | string | nee | Een relatief pad op die origin, standaard /ambassador |
Antwoord 202, altijd dezelfde body: { "status": "accepted" }. Een onbekend adres, een geschorst lid, een gesloten programma en een echte verzending zijn niet te onderscheiden: een inlogformulier dat anders antwoordt op een bekend adres zou een lidmaatschapsorakel zijn. return_origin en return_path worden opnieuw gevalideerd in SQL, dus er is geen manier om een open redirect te bouwen.
Fouten: validation_error (422, foute body, of return_origin is geen van de geregistreerde origins van de sleutel), rate_limited (429, per bezoeker of per e-mailadres).
POST /v1/ambassador-login-exchange
De landingspagina van de partner ontvangt ?amb_token=... en ruilt dat, server-side, in voor een ledensessie.
Scope write:ambassadors. Nooit gecachet. Neemt Idempotency-Key. Begrensd tot 20 pogingen per minuut per bezoeker (client_ip).
| Veld | Type | Verplicht | Opmerkingen |
|---|---|---|---|
token | string | ja | De waarde amb_lt_... uit de querystring |
{ "session": { "token": "amb_st_...", "expires_at": "2026-09-01T18:00:00.000Z" }, "return_url": "https://www.example.com/ambassador" }
Eenmalig bruikbaar: het token wordt verbruikt door dezelfde databaseupdate die het leest, zodat twee tikken in een mailclient die links prefetcht niet allebei kunnen slagen.
Fouten: invalid_key (401, misvormd, onbekend, verlopen of al gebruikt token, allemaal identiek), rate_limited (429).
GET /v1/ambassador-me
De eigen pagina van het ingelogde lid: code, verkopen, credits en rewards, plus XP, niveau, quests en badges wanneer de promotor gamification heeft aangezet.
Scope read:ambassadors, plus een header X-Ambassador-Session. Nooit gecachet.
{
"membership": {
"member": { "id": "0b7c9d1e-2f3a-4b5c-8d6e-7f8091a2b3c4", "first_name": "Melanie", "last_name": "Paulus", "status": "active", "code": "MELANPAU" },
"program": { "id": "5e6f7081-92a3-4b4c-95d6-e7f8091a2b3c", "name": "Insomnia Ambassadors", "description": null, "leaderboard_visible": true, "owner": { "id": 697, "type": "promoter", "name": "Insomnia", "image_url": null } },
"owner": { "id": 697, "type": "promoter", "name": "Insomnia", "image_url": null },
"stats": { "orders": 4, "tickets": 9, "revenue_cents": 27000 },
"credits": { "enabled": true, "balance": 12, "label_singular": "credit", "label_plural": "credits" },
"game": { "enabled": true, "xp_label": "XP", "lifetime_xp": 340, "tier": { "id": "2b3c4d5e-6f70-4812-9a3b-4c5d6e7f8091", "name": "Gold", "min_xp": 300, "color": "#f5c542" }, "next_tier": null, "badges_earned": 2, "quests_completed": 3 },
"tiers": [],
"quests": [],
"badges": [],
"xp_ledger": [],
"rewards": [],
"claims": [],
"ledger": [],
"events": [],
"leaderboard": []
},
"session": { "expires_at": "2026-09-26T20:00:00+00:00" }
}
Dezelfde ledenpagina die sway.events aan het lid toont, hier verkort: game draagt ook de eigen woorden van het programma (tier_noun, quest_noun, badge_noun) en next_tier zegt hoeveel XP er nog nodig is om te klimmen (null op de top). quests, badges, tiers en xp_ledger worden alleen gevuld terwijl gamification aan staat, rewards, claims en ledger (de credit-geschiedenis) alleen terwijl credits aan staan. events somt de evenementen op waarop de code van het lid werkt, met zijn korting, en leaderboard het klassement wanneer de promotor het publiceert, met revenue_cents op elke rang alleen bij een klassement op omzet, net als op sway.events.
access_token (de permanente inloggegevens van het lid voor zijn pagina op sway.events) en zijn telefoonnummer verschijnen hier nooit, wat de onderliggende rij ook bevat.
Fouten: invalid_key (401, de header ontbreekt of is misvormd, of de sessie is verlopen of ongeldig).
POST /v1/ambassador-profile
Het ingelogde lid corrigeert zijn eigen naam, e-mail of taal.
Scope write:ambassadors, plus sessie. Nooit gecachet. Neemt Idempotency-Key. Begrensd tot 20 per minuut per bezoeker (client_ip).
| Veld | Type | Verplicht | Opmerkingen |
|---|---|---|---|
first_name / last_name / email / locale | string | nee | Elke deelverzameling; minstens één is verplicht |
Het telefoonnummer kan hier niet gewijzigd worden (het is de ontdubbelsleutel: wijzigen zou een samenvoeging zijn, geen bewerking), en status, code, credits of XP evenmin: de code volgt een naamswijziging niet.
Fouten: invalid_key (401, sessie), validation_error (422, foute e-mail, geen veld meegestuurd, of een wegwerp-/geblokkeerd e-mailadres), rate_limited (429).
POST /v1/ambassador-claim
Het ingelogde lid besteedt credits aan een reward. De aanroeper noemt nooit een prijs: kosten, saldo, voorraad, de limiet per lid en de niveaudrempel worden allemaal gelezen en afgedwongen vanuit het grootboek onder een rijvergrendeling.
Scope write:ambassadors, plus sessie. Nooit gecachet. Neemt Idempotency-Key. Begrensd tot 20 per minuut per bezoeker (client_ip).
| Veld | Type | Verplicht | Opmerkingen |
|---|---|---|---|
reward_id | string | ja | Een UUID |
answer | string | nee | Hoogstens 500 tekens, wanneer de reward een vraag stelt |
Antwoord 201 bij succes, met claim_id en status.
Fouten: invalid_key (401, geen sessie), not_found (404, onbekende reward), conflict (409, inactive, not_started, ended, out_of_stock, max_per_member, insufficient_credits), validation_error (403, member_not_active of tier_locked; 422, answer_required of een misvormde body).
member_not_active en tier_locked, antwoorden 403 met de code validation_error: lees het veld reason om ze uit elkaar te houden.POST /v1/ambassador-email-preference
Het ingelogde lid zet programma-e-mails uit, of weer aan.
Scope write:ambassadors, plus sessie. Nooit gecachet. Neemt Idempotency-Key. Begrensd tot 20 per minuut per bezoeker (client_ip).
| Veld | Type | Verplicht | Opmerkingen |
|---|---|---|---|
opt_out | boolean | ja |
Een schakelaar, niet de eenrichtingsafmelding die een e-mailvoettekst uitvoert: het portaal is de enige plek waar een lid kan bewijzen wie hij is en weer van gedachten kan veranderen.
Fouten: invalid_key (401, sessie), validation_error (422, opt_out ontbreekt of is geen boolean).
POST /v1/ambassador-logout
Trekt de sessie in die in X-Ambassador-Session genoemd wordt.
Scope write:ambassadors. Nooit gecachet. Neemt Idempotency-Key.
Antwoord: altijd 200 { "ok": true }, ongeacht of de sessie bestond, en ongeacht of de header überhaupt werd meegestuurd: uitloggen is geen plek om iets te leren.
Fouten: geen naast authenticatie.
GET /v1/ambassador-code
Lost een ?amb=CODE op een ticketpagina op: is deze code actief op dit evenement, wat is hij waard, en van wie is hij. Een voorbeeld, nooit een prijs: de voorwaarden worden opnieuw gelezen binnen de checkout, vanuit dezelfde opening.
Scope read:ambassadors. 30 s gecachet. Begrensd tot 60 opzoekingen per minuut per sleutel.
| Parameter | Waarden | Standaard | Betekenis |
|---|---|---|---|
event_id | positief geheel getal | verplicht | Het evenement waartegen de code wordt gecontroleerd |
code | tekst, hoogstens 64 tekens | verplicht | De code zoals getypt |
{ "code": "MELANPAU", "discount_id": "f4c8b1a2-...", "ambassador_first_name": "Melanie", "percentage": 15, "amount": null, "min_order_amount": 0 }
discount_id is wat een storefront doorgeeft aan POST /v1/checkout-sessions als discount_id: die route weigert een ruwe couponcode ronduit. Een code die niet bestaat, niet op dit evenement staat, bij een geschorst lid hoort, of bij een andere tenant hoort, antwoorden allemaal met dezelfde 404: iets specifiekers zou hiervan een opsommingsorakel maken over elke promotor op het platform.
Fouten: validation_error (422, event_id / code ontbreekt of is misvormd), not_found (404), rate_limited (429).
MCP en webhooks
Nog twee manieren om dezelfde data te bereiken, elk gedocumenteerd op zijn eigen pagina:
POST /v1/mcpis de Sway MCP-server: de leesroutes hierboven, blootgesteld als alleen-lezen tools voor een AI-assistent over JSON-RPC (streamable HTTP, stateless), achter een sleutel die de scopemcp:accessdraagt. Zie De Sway MCP-server.- Webhooks, geconfigureerd in Crew admin → API → Webhooks, duwen events (bestellingen betaald en terugbetaald, evenementen gepubliceerd en bijgewerkt, bookingaanvragen, ambassadeursverkopen, formulierantwoorden, uitbetalingen) naar de eigen server van een partner zodra ze gebeuren, ondertekend op de manier van Standard Webhooks. Zie Webhooks.