# Veranstaltungen

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

Vier öffentliche Aufrufe geben Ihrer eigenen Website dieselben Abende, die der Shop zeigt: Name, Zeiten, Plakat, Line-up, Preise, Serien und Tischpakete. Sie brauchen keinen API-Schlüssel.

Die Aufrufe liegen unter https://api.kuvert.dk/v1/merchants/{slug}, wobei {slug} die Adresse des Shops ist, z. B. demo-natklubben in shop.kuvert.dk/demo-natklubben. Sie sind öffentlich wie der Shop selbst: kein Schlüssel, kein Konto und nur das, was auch ein Gast sehen kann. Ein Abend, der noch ein Entwurf ist, ist nie dabei.

> **Wichtig:** Rufen Sie sie von Ihrem Server auf, z. B. aus einem WordPress-Plugin oder einem Build-Schritt, und nicht aus dem JavaScript des Browsers auf Ihrer eigenen Seite. Die API erlaubt im Browser nur Kuverts eigene Domains, ein fetch von einer anderen Domain wird also vom Browser gestoppt.

> **Hinweis:** Speichern Sie die Antwort gern ein, zwei Minuten, aber nicht stundenlang. Preise und Plätze ändern sich, während verkauft wird, also lassen Sie den Ticket-Button zum Shop führen, wo die Zahlen immer stimmen.

## Die Aufrufe

| Aufruf | Liefert |
| --- | --- |
| `GET /v1/merchants/{slug}` | Der Shop und die Abende im Verkauf, in `events`, der früheste zuerst. Mit `?include=canceled` kommen abgesagte Abende dazu, mit `?include=closed` Abende, deren Online-Verkauf geschlossen, die aber noch nicht vorbei sind. Beides geht zusammen: `?include=canceled,closed`. |
| `GET /v1/merchants/{slug}/events/{event}` | Ein Abend mit allen Preisen, was noch übrig ist und ob er gerade gekauft werden kann. {event} ist der Slug oder die ID des Abends. |
| `GET /v1/merchants/{slug}/series` | Die festen Serien, jede mit den Abenden der Serie, die im Verkauf sind. |
| `GET /v1/merchants/{slug}/table-nights` | Die kommenden Abende mit Tischpaketen und ob jedes Paket gerade gebucht werden kann. |
| `GET /v1/merchants/{slug}/events/{event}/plan` | Der Plan des Clubs für einen Abend mit Tischpaketen: die Räume und jeder Tisch, frei oder verkauft. Wer gekauft hat, steht nicht darauf. |

## Die Abende

Der Aufruf des Shops selbst enthält die Abende in `events`. Jeder Abend hat Name, Zeiten, Ort und Plakat und die Felder, aus denen ein Programm gebaut wird. Hier ein Auszug der Antwort mit einem Abend:

```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": []
    }
  ]
}
```

| Feld | Bedeutet |
| --- | --- |
| `id, slug` | Die ID des Abends und seine lesbare Adresse. Die Seite des Abends im Shop ist shop.kuvert.dk/{slug}/event/{slug}, mit der ID, wenn der Abend keinen Slug hat. |
| `startsAt, endsAt` | Wann der Abend beginnt und endet. `endsAt` ist `null`, wenn der Abend es nicht angibt. |
| `salesCloseAt` | Wann der Online-Verkauf schließt. |
| `bannerUrl, bannerWidth, bannerHeight` | Das Plakat und seine Größe in Pixeln, damit die Seite den Platz dafür freihalten kann, bevor es geladen ist. Zeigen Sie es ganz: Es ist gestaltet, um unbeschnitten gesehen zu werden. |
| `status, cancelNote` | `published` oder `canceled` und die Nachricht, die Sie bei der Absage geschrieben haben. |
| `series, seriesDate` | Die Serie hinter dem Abend mit Name, Wochentagen (0 ist Sonntag), der Regel und einem fertigen Satz zum Anzeigen, z. B. «Hver fredag og lørdag», und welcher Tag der Serie es ist. `null` bei einem Abend, den Sie selbst angelegt haben. |
| `subtitle, genres, dressCode` | Untertitel, Genres und Dresscode, so wie Sie sie geschrieben haben. |
| `lineup` | Die Namen in Reihenfolge, jeweils mit `name`, `role` und `time`. `time` enthält das Datum, sodass ein Set nach Mitternacht auf dem richtigen Tag steht. |
| `doorsAt, lastEntryAt` | Wann die Türen öffnen und wann der letzte Gast eingelassen wird. |
| `ticketsUrl` | Wo die Tickets verkauft werden, wenn jemand anderes sie verkauft, z. B. der Veranstalter. Hat der Abend eigene Preise in Kuvert, werden sie hier verkauft, und das Feld wird nicht verwendet. |

> **Hinweis:** Alle Zeiten sind in UTC. 21:00Z ist 23:00 Uhr in dänischer Sommerzeit und 22:00 Uhr im Winter, rechnen Sie also in Europe/Copenhagen um, bevor Sie sie anzeigen.

## Ein Abend

Der Aufruf des Abends selbst liefert alles: die Beschreibung, die Altersgrenze und alle Preise in `tiers`. `onSale` sagt, ob gerade gekauft werden kann, und `refusalCode`, warum nicht, z. B. `soldOut` oder `closed`. `waitlistOpen` ist `true`, wenn sich der Gast auf die Warteliste setzen kann.

```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": []
}
```

| Feld | Bedeutet |
| --- | --- |
| `priceOre` | Der Preis in Øre: 10000 sind 100 DKK. |
| `availability` | `on_sale`, `not_yet` (öffnet später), `closed` oder `sold_out`. |
| `remaining, scarcity` | Wie viele zu diesem Preis noch übrig sind und was der Shop davon zeigt: die Zahl (`count`), «nur noch wenige» (`few`) oder nichts (`null`). Zeigen Sie, was `scarcity` sagt, und nicht die Zahl. `remaining` ist `null`, wenn der Preis kein eigenes Kontingent hat. |
| `salesOpenAt, salesCloseAt, opensAfterTierId` | Das eigene Verkaufsfenster des Preises und der Preis, dessen Ausverkauf er abwartet, wenn Tickets in Stufen verkauft werden. |
| `tablePackage, picksTable, tableSeats, tablesFree` | Ein Tischpaket: ob der Gast den Tisch auf dem Plan wählt, der kleinste und größte Tisch und wie viele Tische frei sind. |
| `includedItems, creditPromisedOre` | Was zu einem Paket gehört, und das Guthaben für die Bar, falls es eines gibt. |
| `ageLimit` | Die Altersgrenze an der Tür oder `null`. |

## Serien

Veranstalten Sie jede Woche denselben Abend, liefern die Serien ihn als eine Zeile: «Hver fredag og lørdag» und die Abende der Serie, die im Verkauf sind. Eine Serie, deren Abende alle noch Entwürfe sind, ist nicht dabei.

```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"
        }
      ]
    }
  ]
}
```

## Tischpakete

Verkaufen Sie Tische für Ihre Abende, liefert dieser Aufruf die kommenden Abende mit ihren Tischpaketen, sodass die Seite neben jeden Abend «Book bord» setzen kann, ohne die Seite jedes Abends abzurufen. `bookable` sagt, ob das Paket gerade gebucht werden kann.

```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
        }
      ]
    }
  ]
}
```

## Das Programm aktuell halten

Muss Ihre Seite sofort wissen, wenn sich ein Abend ändert, kann sie Webhooks abonnieren, statt jede Minute nachzufragen: event.published, wenn ein Abend in den Verkauf geht, event.updated, wenn sich etwas Öffentliches ändert (mit den Namen der Felder in `changedFields`), event.canceled und event.unpublished. Jede Lieferung enthält den ganzen Abend in derselben Form wie die Liste oben, mit `eventId` statt `id`. Ein Webhook-Endpunkt wird unter Einstellungen → Webhooks oder mit einem API-Schlüssel angelegt.

## Ein Beispiel

Das Kleinste, das funktioniert: Rufen Sie die Abende auf Ihrem Server ab, und bauen Sie zu jedem Abend einen Link auf seine Seite im Shop.

```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 und Signaturen](https://kuvert.dk/de/dokumentation/api/webhooks)
- [Tickets: das Programm auf Ihrer eigenen Website](https://kuvert.dk/de/dokumentation/billetter#hjemmeside)
- [Einbettung: ein Kauf-Button neben jedem Abend](https://kuvert.dk/de/dokumentation/indlejring)

## Geteilte Abende

Ein Abend kann von mehreren Unternehmen geteilt werden, z. B. von einem Veranstalter, der die Tickets verkauft, und dem Club, der die Tische verkauft. Der Abend gehört dem Gastgeber, steht aber im Programm aller und lässt sich unter jedem ihrer Slugs abrufen, mit derselben ID und demselben Slug. In der Liste jedes Unternehmens wird er einmal gezählt.

| Feld | Bedeutet |
| --- | --- |
| `host` | Das Unternehmen, dem der Abend gehört, mit `slug` und `name`. Die richtige Adresse des Abends ist shop.kuvert.dk/{host.slug}/event/{slug}, auch wenn Sie ihn unter Ihrem eigenen Slug abrufen. |
| `cohosts` | Die anderen Unternehmen, die an dem Abend verkaufen, in der Reihenfolge, in der sie dazukamen. Eine leere Liste bei einem Abend, der nicht geteilt ist. |
| `tiers[].seller` | Wer den Preis verkauft und wen der Gast bezahlt. Nutzen Sie es, um Ihre eigenen Preise für sich zu zeigen oder anzugeben, wer was verkauft. |
| `lineup[].merchantSlug` | Der eigene Shop des Auftretenden bei Kuvert, wenn der Gastgeber den Namen damit verknüpft hat. |

GET /v1/merchants/{slug}/appearances liefert die Abende, für die andere Unternehmen Sie gebucht haben, entweder als Mitveranstalter oder im Line-up, in derselben Form wie die Liste oben plus `seller` (das Unternehmen, dessen Seite den Abend verkauft) und `appearance` (`cohost` oder `lineup`). So kann die Website eines Künstlers die Clubabende zeigen, an denen er spielt, ohne dass jemand sie noch einmal eintippen muss. Ein Abend, bei dem Sie selbst Mitveranstalter sind, steht auch auf Ihrer eigenen Liste oben. Zeigen Sie also nur einen davon, oder filtern Sie nach `appearance`.

Webhooks für einen geteilten Abend (event.*) gehen an alle Unternehmen des Abends. order.paid und ticket.issued gehen nur an das verkaufende Unternehmen und enthalten `seller`, `host` und `cohosts`, damit Ihr System Ihre eigenen Verkäufe von denen des Partners unterscheiden kann.

- [Einen Abend mit einem anderen Unternehmen teilen](https://kuvert.dk/de/dokumentation/del-en-aften)
