# Arrangementer

<https://kuvert.dk/dokumentation/api/arrangementer>

Fire offentlige kald giver jeres egen hjemmeside de samme aftener, som butikken viser: navn, tider, plakat, line-up, priser, serier og bordpakker. De kræver ingen API-nøgle.

Kaldene ligger under https://api.kuvert.dk/v1/merchants/{slug}, hvor {slug} er butikkens adresse, fx demo-natklubben i shop.kuvert.dk/demo-natklubben. De er offentlige som butikken selv: ingen nøgle, ingen konto og kun det, en gæst også kan se. En aften, der stadig er en kladde, kommer aldrig med.

> **Vigtigt:** Kald dem fra jeres server, fx fra et WordPress-plugin eller et build-trin, og ikke fra browserens JavaScript på jeres egen side. API’et tillader kun Kuverts egne domæner i browseren, så et fetch fra et andet domæne bliver stoppet af browseren.

> **Bemærk:** Gem gerne svaret i et minut eller to, men ikke i timevis. Priser og pladser ændrer sig, mens der sælges, så lad knappen til billetterne gå til butikken, hvor tallene altid er de rigtige.

## Kaldene

| Kald | Giver |
| --- | --- |
| `GET /v1/merchants/{slug}` | Butikken og de aftener, der er til salg, i `events`, den tidligste først. Med `?include=canceled` kommer aflyste aftener med, og med `?include=closed` aftener, hvor onlinesalget er lukket, men aftenen ikke er slut. Begge kan stå sammen: `?include=canceled,closed`. |
| `GET /v1/merchants/{slug}/events/{event}` | Én aften med alle priser, hvad der er tilbage, og om den kan købes lige nu. {event} er aftenens slug eller id. |
| `GET /v1/merchants/{slug}/series` | De faste serier, hver med de aftener af serien, der er til salg. |
| `GET /v1/merchants/{slug}/table-nights` | De kommende aftener med bordpakker, og om hver pakke kan bookes lige nu. |
| `GET /v1/merchants/{slug}/events/{event}/plan` | Klubbens kort for én aften med bordpakker: rummene og hvert bord, ledigt eller solgt. Der står intet om, hvem der har købt. |

## Aftenerne

Butikkens eget kald har aftenerne med i `events`. Hver aften har navn, tider, sted og plakat og de felter, et program bygges af. Her er et uddrag af svaret med én aften:

```json
{
  "events": [
    {
      "id": "evt_65694ef606f6483083d368ec040601e2",
      "slug": "klubnat-2026-10-17",
      "name": "Klubnat",
      "startsAt": "2026-10-17T21:00:00.000Z",
      "endsAt": "2026-10-18T03:00:00.000Z",
      "venue": "Natklubben, Vejle",
      "bannerUrl": null,
      "bannerWidth": null,
      "bannerHeight": null,
      "salesCloseAt": "2026-10-18T00:00:00.000Z",
      "status": "published",
      "cancelNote": null,
      "series": {
        "id": "ser_216c1567afbb42368340cb9b11146a90",
        "name": "Klubnat",
        "weekdays": [
          5,
          6
        ],
        "isRecurring": true,
        "recurrence": {
          "kind": "weekly",
          "weekdays": [
            5,
            6
          ]
        },
        "description": "Hver fredag og lørdag"
      },
      "seriesDate": "2026-10-17",
      "subtitle": "Husets DJs på to gulve",
      "lineup": [
        {
          "name": "Kasper Ø",
          "role": "warm-up",
          "time": "2026-10-17T21:00:00.000Z"
        },
        {
          "name": "Selma Rask",
          "role": "resident",
          "time": "2026-10-17T23:00:00.000Z"
        }
      ],
      "genres": [
        "House",
        "Hiphop",
        "Top 40"
      ],
      "doorsAt": "2026-10-17T21:00:00.000Z",
      "lastEntryAt": "2026-10-18T01:00:00.000Z",
      "dressCode": "Ingen sportstøj",
      "ticketsUrl": null,
      "host": {
        "slug": "demo-natklubben",
        "name": "Natklubben"
      },
      "cohosts": []
    }
  ]
}
```

| Felt | Betyder |
| --- | --- |
| `id, slug` | Aftenens id og dens læsbare adresse. Aftenens side i butikken er shop.kuvert.dk/{slug}/event/{slug}, med id’et, hvis aftenen ikke har en slug. |
| `startsAt, endsAt` | Hvornår aftenen begynder og slutter. `endsAt` er `null`, hvis aftenen ikke siger det. |
| `salesCloseAt` | Hvornår onlinesalget lukker. |
| `bannerUrl, bannerWidth, bannerHeight` | Plakaten og dens størrelse i pixels, så siden kan holde pladsen til den, før den er hentet. Vis den hel: den er tegnet til at blive set uden beskæring. |
| `status, cancelNote` | `published` eller `canceled`, og den besked, I skrev, da aftenen blev aflyst. |
| `series, seriesDate` | Serien bag aftenen med navn, ugedage (0 er søndag), reglen og en færdig sætning at vise, fx «Hver fredag og lørdag», og hvilken af seriens dage det er. `null` på en aften, I selv har oprettet. |
| `subtitle, genres, dressCode` | Undertitlen, genrerne og dresscoden, som I skrev dem. |
| `lineup` | Navnene i rækkefølge, hver med `name`, `role` og `time`. `time` har dato med, så et sæt efter midnat står på den rigtige dag. |
| `doorsAt, lastEntryAt` | Hvornår dørene åbner, og hvornår sidste gæst lukkes ind. |
| `ticketsUrl` | Hvor billetterne sælges, når det er hos en anden, fx arrangøren. Har aftenen egne priser i Kuvert, sælges de her, og feltet bruges ikke. |

> **Bemærk:** Alle tidspunkter er i UTC. 21:00Z er kl. 23.00 i dansk sommertid og kl. 22.00 om vinteren, så regn om til Europe/Copenhagen, før I viser dem.

## Én aften

Aftenens eget kald giver det hele: beskrivelsen, aldersgrænsen og alle priser i `tiers`. `onSale` siger, om der kan købes lige nu, og `refusalCode` hvorfor ikke, fx `soldOut` eller `closed`. `waitlistOpen` er `true`, når gæsten kan skrive sig på ventelisten.

```json
{
  "id": "evt_65694ef606f6483083d368ec040601e2",
  "slug": "klubnat-2026-10-17",
  "name": "Klubnat",
  "startsAt": "2026-10-17T21:00:00.000Z",
  "endsAt": "2026-10-18T03:00:00.000Z",
  "venue": "Natklubben, Vejle",
  "bannerUrl": null,
  "bannerWidth": null,
  "bannerHeight": null,
  "description": "Gratis før midnat på gæstelisten, entré ved døren derefter. Borde med flasker hele natten.",
  "ageLimit": 18,
  "tiers": [
    {
      "id": "etr_e5e5766ded1e456599d7e8925f68bff9",
      "name": "Entré",
      "description": "Spring billetkøen over. Gælder hele natten.",
      "priceOre": 10000,
      "availability": "on_sale",
      "remaining": null,
      "scarcity": null,
      "salesOpenAt": null,
      "salesCloseAt": null,
      "seatsPerTicket": 1,
      "seatsChosenByGuest": false,
      "creditPromisedOre": null,
      "tablePackage": false,
      "includedItems": [],
      "minSeats": 1,
      "arriveBy": null,
      "seller": {
        "slug": "demo-natklubben",
        "name": "Natklubben"
      }
    },
    {
      "id": "etr_773b122865f0469e81c06781c4befa63",
      "name": "Flaske",
      "description": null,
      "priceOre": 240000,
      "availability": "on_sale",
      "remaining": 10,
      "scarcity": null,
      "salesOpenAt": null,
      "salesCloseAt": null,
      "seatsPerTicket": 10,
      "seatsChosenByGuest": true,
      "creditPromisedOre": null,
      "tablePackage": true,
      "picksTable": true,
      "tableSeats": {
        "min": 4,
        "max": 10
      },
      "tablesFree": 10,
      "includedItems": [
        "1 × Absolut Vodka 70 cl",
        "6 × Red Bull",
        "Entré for hele bordet"
      ],
      "minSeats": 1,
      "arriveBy": "2026-10-17T22:30:00.000Z",
      "seller": {
        "slug": "demo-natklubben",
        "name": "Natklubben"
      }
    }
  ],
  "minQuantity": 1,
  "salesCloseAt": "2026-10-18T00:00:00.000Z",
  "pickups": [],
  "remaining": 350,
  "onSale": true,
  "refusal": null,
  "refusalCode": null,
  "refusalCount": null,
  "waitlistOpen": false,
  "questions": [],
  "status": "published",
  "cancelNote": null,
  "series": {
    "id": "ser_216c1567afbb42368340cb9b11146a90",
    "name": "Klubnat",
    "weekdays": [
      5,
      6
    ],
    "isRecurring": true,
    "recurrence": {
      "kind": "weekly",
      "weekdays": [
        5,
        6
      ]
    },
    "description": "Hver fredag og lørdag"
  },
  "seriesDate": "2026-10-17",
  "subtitle": "Husets DJs på to gulve",
  "lineup": [
    {
      "name": "Kasper Ø",
      "role": "warm-up",
      "time": "2026-10-17T21:00:00.000Z"
    },
    {
      "name": "Selma Rask",
      "role": "resident",
      "time": "2026-10-17T23:00:00.000Z"
    }
  ],
  "genres": [
    "House",
    "Hiphop",
    "Top 40"
  ],
  "doorsAt": "2026-10-17T21:00:00.000Z",
  "lastEntryAt": "2026-10-18T01:00:00.000Z",
  "dressCode": "Ingen sportstøj",
  "ticketsUrl": null,
  "host": {
    "slug": "demo-natklubben",
    "name": "Natklubben"
  },
  "cohosts": []
}
```

| Felt | Betyder |
| --- | --- |
| `priceOre` | Prisen i øre: 10000 er 100 kr. |
| `availability` | `on_sale`, `not_yet` (åbner senere), `closed` eller `sold_out`. |
| `remaining, scarcity` | Hvor mange der er tilbage til den pris, og hvad butikken viser om det: tallet (`count`), «få tilbage» (`few`) eller ingenting (`null`). Vis det, `scarcity` siger, og ikke tallet. `remaining` er `null`, når prisen ikke har sit eget antal. |
| `salesOpenAt, salesCloseAt, opensAfterTierId` | Prisens eget tidsrum, og den pris, den venter på at blive udsolgt, når billetterne sælges i trin. |
| `tablePackage, picksTable, tableSeats, tablesFree` | En bordpakke: om gæsten vælger bordet på kortet, det mindste og største bord, og hvor mange borde der er ledige. |
| `includedItems, creditPromisedOre` | Det, der følger med en pakke, og beløbet til baren, hvis der er et. |
| `ageLimit` | Aldersgrænsen ved døren, eller `null`. |

## Serier

Holder I den samme aften hver uge, giver serierne jer den som én række: «Hver fredag og lørdag», og de aftener af serien, der er til salg. En serie, hvor alle aftener stadig er kladder, er ikke med.

```json
{
  "series": [
    {
      "id": "ser_216c1567afbb42368340cb9b11146a90",
      "name": "Klubnat",
      "weekdays": [
        5,
        6
      ],
      "isRecurring": true,
      "recurrence": {
        "kind": "weekly",
        "weekdays": [
          5,
          6
        ]
      },
      "description": "Hver fredag og lørdag",
      "nights": [
        {
          "id": "evt_65694ef606f6483083d368ec040601e2",
          "slug": "klubnat-2026-10-17",
          "name": "Klubnat",
          "startsAt": "2026-10-17T21:00:00.000Z",
          "seriesDate": "2026-10-17"
        },
        {
          "id": "evt_0ba0fd9fb19c42cd80f4ebc11879b462",
          "slug": "klubnat-2026-10-23",
          "name": "Klubnat",
          "startsAt": "2026-10-23T21:00:00.000Z",
          "seriesDate": "2026-10-23"
        }
      ]
    }
  ]
}
```

## Bordpakker

Sælger I borde til aftenerne, giver dette kald de kommende aftener med deres bordpakker, så siden kan sætte «Book bord» ved hver aften uden at hente hver aftens side. `bookable` siger, om pakken kan bookes lige nu.

```json
{
  "nights": [
    {
      "id": "evt_65694ef606f6483083d368ec040601e2",
      "slug": "klubnat-2026-10-17",
      "name": "Klubnat",
      "startsAt": "2026-10-17T21:00:00.000Z",
      "endsAt": "2026-10-18T03:00:00.000Z",
      "venue": "Natklubben, Vejle",
      "bannerUrl": null,
      "bannerWidth": null,
      "bannerHeight": null,
      "ageLimit": 18,
      "onSale": true,
      "packages": [
        {
          "id": "etr_773b122865f0469e81c06781c4befa63",
          "name": "Flaske",
          "description": null,
          "priceOre": 240000,
          "availability": "on_sale",
          "remaining": 10,
          "scarcity": null,
          "salesOpenAt": null,
          "salesCloseAt": null,
          "seatsPerTicket": 10,
          "seatsChosenByGuest": true,
          "creditPromisedOre": null,
          "tablePackage": true,
          "picksTable": true,
          "tableSeats": {
            "min": 4,
            "max": 10
          },
          "tablesFree": 10,
          "includedItems": [
            "1 × Absolut Vodka 70 cl",
            "6 × Red Bull",
            "Entré for hele bordet"
          ],
          "minSeats": 1,
          "arriveBy": "2026-10-17T22:30:00.000Z",
          "seller": {
            "slug": "demo-natklubben",
            "name": "Natklubben"
          },
          "bookable": true
        }
      ]
    }
  ]
}
```

## Hold programmet opdateret

Skal jeres side vide det med det samme, når en aften ændrer sig, kan den abonnere på webhooks i stedet for at spørge hvert minut: event.published, når en aften bliver sat til salg, event.updated, når noget offentligt ændrer sig (med navnene på felterne i `changedFields`), event.canceled og event.unpublished. Hver leverance har hele aftenen i samme form som listen ovenfor, med `eventId` i stedet for `id`. Et webhook-endepunkt oprettes under Indstillinger → Webhooks eller med en API-nøgle.

## Et eksempel

Det mindste, der virker: hent aftenerne på jeres server, og byg et link til hver aftens side i butikken.

```javascript
const res = await fetch('https://api.kuvert.dk/v1/merchants/demo-natklubben')
const { events } = await res.json()

for (const night of events) {
  const link = `https://shop.kuvert.dk/demo-natklubben/event/${night.slug ?? night.id}`
  console.log(night.name, night.startsAt, night.status, link)
}
```

- [Webhooks og signaturer](https://kuvert.dk/dokumentation/api/webhooks)
- [Billetter: programmet på jeres egen hjemmeside](https://kuvert.dk/dokumentation/billetter#hjemmeside)
- [Indlejring: en købsknap ved hver aften](https://kuvert.dk/dokumentation/indlejring)

## Delte aftener

En aften kan deles af flere forretninger, fx en arrangør, der sælger billetterne, og klubben, der sælger bordene. Aftenen hører til værten, men den står i programmet hos dem alle og kan hentes under hver af deres slugs, med samme id og samme slug. Den tælles én gang i hver forretnings liste.

| Felt | Betyder |
| --- | --- |
| `host` | Forretningen, aftenen hører til, med `slug` og `name`. Aftenens rigtige adresse er shop.kuvert.dk/{host.slug}/event/{slug}, også når I henter den under jeres egen slug. |
| `cohosts` | De andre forretninger, der sælger på aftenen, i den rækkefølge de kom med. En tom liste på en aften, der ikke er delt. |
| `tiers[].seller` | Hvem der sælger prisen, og som gæsten betaler. Brug den til at vise jeres egne priser for sig eller til at skrive, hvem der sælger hvad. |
| `lineup[].merchantSlug` | Den optrædendes egen butik på Kuvert, når værten har koblet navnet til den. |

GET /v1/merchants/{slug}/appearances giver de aftener, som andre forretninger har booket jer til, enten som medvært eller i line-up'et, i samme form som listen ovenfor plus `seller` (forretningen, hvis side sælger aftenen) og `appearance` (`cohost` eller `lineup`). Så kan en kunstners side vise de klubaftener, kunstneren spiller, uden at nogen skal skrive dem ind igen. En aften, I selv er medvært på, står også på jeres egen liste ovenfor, så vis kun den ene, eller sorter på `appearance`.

Webhooks for en delt aften (event.*) går til alle forretninger på aftenen. order.paid og ticket.issued går kun til den, der solgte, og har `seller`, `host` og `cohosts` med, så jeres system kan skelne jeres eget salg fra partnerens.

- [Del en aften med en anden forretning](https://kuvert.dk/dokumentation/del-en-aften)
