The calls live under https://api.kuvert.dk/v1/merchants/{slug}, where {slug} is the shop’s address, e.g. demo-natklubben in shop.kuvert.dk/demo-natklubben. They are public like the shop itself: no key, no account, and only what a guest can see too. A night that is still a draft is never included.
| Call | Returns |
|---|---|
GET /v1/merchants/{slug} | The shop and the nights on sale, in events, earliest first. With ?include=canceled cancelled nights are included, and with ?include=closed nights whose online sale has closed but which are not over. Both can be combined: ?include=canceled,closed. |
GET /v1/merchants/{slug}/events/{event} | One night with every price, what is left, and whether it can be bought right now. {event} is the night’s slug or id. |
GET /v1/merchants/{slug}/series | The regular series, each with the nights of the series that are on sale. |
GET /v1/merchants/{slug}/table-nights | The coming nights with table packages, and whether each package can be booked right now. |
GET /v1/merchants/{slug}/events/{event}/plan | The club’s map for one night with table packages: the rooms and every table, free or sold. It says nothing about who bought. |
The shop’s own call carries the nights in events. Each night has a name, times, venue and poster, and the fields a programme is built from. Here is an excerpt of the answer with one night:
{
"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": []
}
]
}| Field | Means |
|---|---|
id, slug | The night’s id and its readable address. The night’s page in the shop is shop.kuvert.dk/{slug}/event/{slug}, with the id if the night has no slug. |
startsAt, endsAt | When the night starts and ends. endsAt is null if the night does not say. |
salesCloseAt | When the online sale closes. |
bannerUrl, bannerWidth, bannerHeight | The poster and its size in pixels, so the page can hold its space before it has loaded. Show it whole: it is drawn to be seen uncropped. |
status, cancelNote | published or canceled, and the message you wrote when the night was cancelled. |
series, seriesDate | The series behind the night with name, weekdays (0 is Sunday), the rule and a ready sentence to show, e.g. «Hver fredag og lørdag», and which of the series’ days it is. null on a night you created yourselves. |
subtitle, genres, dressCode | The subtitle, the genres and the dress code, as you wrote them. |
lineup | The names in running order, each with name, role and time. time includes the date, so a set after midnight lands on the right day. |
doorsAt, lastEntryAt | When the doors open, and when the last guest is let in. |
ticketsUrl | Where the tickets are sold when someone else sells them, e.g. the promoter. If the night has its own prices in Kuvert, they are sold here and the field is not used. |
The night’s own call gives you everything: the description, the age limit and every price in tiers. onSale says whether it can be bought right now, and refusalCode why not, e.g. soldOut or closed. waitlistOpen is true when the guest can join the waiting list.
{
"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": []
}| Field | Means |
|---|---|
priceOre | The price in øre: 10000 is DKK 100. |
availability | on_sale, not_yet (opens later), closed or sold_out. |
remaining, scarcity | How many are left at that price, and what the shop shows about it: the number (count), «few left» (few) or nothing (null). Show what scarcity says, not the number. remaining is null when the price has no count of its own. |
salesOpenAt, salesCloseAt, opensAfterTierId | The price’s own sales window, and the price it waits to sell out when tickets are sold in tiers. |
tablePackage, picksTable, tableSeats, tablesFree | A table package: whether the guest picks the table on the map, the smallest and largest table, and how many tables are free. |
includedItems, creditPromisedOre | What comes with a package, and the bar credit if there is one. |
ageLimit | The age limit at the door, or null. |
If you hold the same night every week, the series give it to you as one row: «Hver fredag og lørdag», and the nights of the series that are on sale. A series whose nights are all still drafts is not included.
{
"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"
}
]
}
]
}If you sell tables for your nights, this call gives the coming nights with their table packages, so the page can put «Book bord» beside each night without fetching every night’s page. bookable says whether the package can be booked right now.
{
"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
}
]
}
]
}If your site needs to know the moment a night changes, it can subscribe to webhooks instead of asking every minute: event.published when a night goes on sale, event.updated when something public changes (with the names of the fields in changedFields), event.canceled and event.unpublished. Each delivery carries the whole night in the same form as the list above, with eventId instead of id. A webhook endpoint is created under Settings → Webhooks or with an API key.
The smallest thing that works: fetch the nights on your server, and build a link to each night’s page in the shop.
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 and signatures
- Tickets: your programme on your own website
- Embedding: a buy button beside each night
A night can be shared by several businesses, e.g. a promoter who sells the tickets and the club that sells the tables. The night belongs to the host, but it is in the programme of all of them and can be fetched under each of their slugs, with the same id and the same slug. It is counted once in each business’s list.
| Field | Means |
|---|---|
host | The business the night belongs to, with slug and name. The night’s real address is shop.kuvert.dk/{host.slug}/event/{slug}, also when you fetch it under your own slug. |
cohosts | The other businesses selling on the night, in the order they joined. An empty list on a night that is not shared. |
tiers[].seller | Who sells the price, and who the guest pays. Use it to show your own prices on their own or to say who sells what. |
lineup[].merchantSlug | The performer’s own shop on Kuvert, when the host has linked the name to it. |
GET /v1/merchants/{slug}/appearances gives the nights other businesses have booked you for, either as co-host or in the line-up, in the same form as the list above plus seller (the business whose page sells the night) and appearance (cohost or lineup). An artist’s site can then show the club nights the artist plays without anybody typing them in again. A night you co-host yourself is also on your own list above, so show only one of them, or filter on appearance.
Webhooks for a shared night (event.*) go to every business on the night. order.paid and ticket.issued go only to the one that sold, and carry seller, host and cohosts, so your system can tell your own sales from your partner’s.
Was this page helpful?