Spring til indhold

Gavekort

Otte endepunkter dækker hele kortets liv gennem API'et: udsted, list, slå op, indløs, fortryd, gensend, annullér og refundér.

Annullér kan ikke fortrydes — der findes ingen genaktivering, fordi et kort, der blev slået ihjel og siden stille genoplivet, er en forpligtelse, ingen har sagt ja til. Refundér er det eneste endepunkt, der flytter penge: Stripe sender beløbet tilbage til det kort, der betalte, og ingen andre steder hen.

Prøv det her på siden

Konsollen herunder kører de samme skemaer og den samme indløsningsregel som API'et, mod et kort, der kun findes i din browser. Ret i kroppen, og se hvilken status dit eget kald ville få.

Konsollen

Kort
KUV-DLT2-9GPW
Saldo
500,00 kr.
Status
active

Forespørgsel

GET /v1/api/giftcards/KUV-DLT2-9GPW

Authorization: Bearer pk_test_…

Ingen krop. Koden står i stien.

Svar

200 OK

{
  "giftCard": {
    "id": "gc_3n8qk2vh",
    "code": "KUV-DLT2-9GPW",
    "orderId": null,
    "status": "active",
    "initialOre": 50000,
    "balanceOre": 50000,
    "expiresAt": "2029-01-15T12:00:00.000Z",
    "merchantSlug": "cafe-noir",
    "origin": "b2b",
    "reference": "Faktura 2026-114",
    "punchValueOre": null,
    "noCashClaim": false,
    "productName": null
  }
}

Saldoen er regnet ud af posteringerne, ikke læst af et felt — det er derfor den altid stemmer med indløsningerne.

Svar 200 OK. Saldoen er regnet ud af posteringerne, ikke læst af et felt — det er derfor den altid stemmer med indløsningerne.

Konsollen kalder ikke ud på nettet — den kører de samme skemaer og den samme indløsningsregel som API’et, mod et kort, der kun findes i din browser. Statuskoder og fejltekster er derfor dem, din egen integration får.

Idempotens

Udsted og indløs kan begge bære en nøgle, der gør kaldet sikkert at gentage. Samme nøgle to gange svarer med resultatet af den FØRSTE gang — samme kort, samme postering — i stedet for at udstede eller trække to gange. De to verber opdager dog ikke det samme: ved INDLØS svarer vi 409 idempotency_key_conflict, hvis nøglen allerede er brugt på et andet kort eller på en udbetaling, i stedet for at ramme forkert. Ved UDSTED sammenligner vi ikke kaldet — genbruger du en nøgle med et andet beløb, får du 201 og det FØRSTE korts data tilbage, uden fejl. Brug én nøgle pr. kort.

Nøglen kan stå tre steder. Vi læser idempotencyKey i kroppen først, og ellers headeren Idempotency-Key og derefter X-Request-Guid. Kroppen vinder, når der er både og.

HvorNavn
KroppenidempotencyKey — det eksplicitte valg, og det, der vinder.
HeaderIdempotency-Key — navnet Stripe har gjort til standard.
HeaderX-Request-Guid — så en integration, der flytter fra Lifepeaks, virker uden at blive skrevet om.

Udsted et kort

POST/v1/api/giftcards

Udsteder et kort uden om betalingsflowet — solgt fra dit eget system, faktureret til en virksomhed, eller givet med på huset.

origin er påkrævet her, hvor det er valgfrit i dashboardet. Et system udsteder uden nogen kigger med, og valget følger kortet resten af dets levetid: sold betyder, at en kunde har betalt for det, og så bærer kortet kundens ret til at få restbeløbet udbetalt kontant. b2b og comp gør ikke.

curl -X POST https://api.kuvert.dk/v1/api/giftcards \
  -H "Authorization: Bearer $KUVERT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amountOre": 50000,
    "origin": "b2b",
    "reference": "Faktura 2026-114",
    "idempotencyKey": "faktura-2026-114"
  }'
201 CreatedJSON
{
  "giftCard": {
    "id": "gc_4f1c9a2e7b3d48e6a0c5d9f2b8e1a7c3",
    "code": "KUV-7K9F-2XQD",
    "orderId": null,
    "status": "active",
    "initialOre": 50000,
    "balanceOre": 50000,
    "expiresAt": "2029-09-29T08:00:00.000Z",
    "merchantSlug": "cafe-noir",
    "origin": "b2b",
    "reference": "Faktura 2026-114",
    "punchValueOre": null,
    "noCashClaim": false,
    "productName": null
  }
}
Prøv det i konsollen

Krop

amountOreintegerPåkrævet
Kortets værdi i øre — mindst 1 øre og højst 100.000,00 kr.
origin"sold" | "b2b" | "comp"Påkrævet
sold: en kunde har betalt. b2b: faktureret til en virksomhed. comp: givet med på huset.
validityMonthsintegerValgfri
Gyldighed i måneder, mindst 36 og højst 600. Udelades den, gælder kortet i 36.
referencestring | nullValgfri
Din egen note, fx et fakturanummer. Højst 200 tegn.
noCashClaimbooleanValgfri
Markér kortet «kan ikke ombyttes til kontanter» — det, der gør en medarbejdergave skattefri. Kun på b2b og comp.
idempotencyKeystringValgfri
Samme nøgle to gange udsteder kun ét kort. Højst 120 tegn. Kan også sendes som header — se Idempotens.

Svarfelter

Kortet står under giftCard, i samme form som ved Slå et kort op, hvor felterne er beskrevet.

Statuskoder

  • 201

    Kortet er udstedt — eller, med en idempotencyKey, der er brugt før, det kort, nøglen udstedte første gang.

  • 400invalid_issue_request

    Kroppen matcher ikke det, udstedelse kræver.

  • 404merchant_not_found

    Nøglen er gyldig, men forretningen bag den findes ikke længere. Sjældent, og ikke noget en klient kan rette — kontakt os.

  • 409cash_claim_cannot_be_denied

    noCashClaim på et sold-kort. Kunden har betalt, og retten til at få restbeløbet udbetalt kan et flag ikke fjerne.

En fejl har altid formen { "error": "…" }. Ethvert kald kan desuden svare 401, 403, 429 og 500 — se Fejl.

List kort

GET/v1/api/giftcards

Alle forretningens kort, nyeste først, med saldoen regnet ud af posteringerne i samme øjeblik. Listen er ikke sidedelt.

curl https://api.kuvert.dk/v1/api/giftcards \
  -H "Authorization: Bearer $KUVERT_API_KEY"
200 OKJSON
{
  "giftCards": [
    {
      "id": "gc_4f1c9a2e7b3d48e6a0c5d9f2b8e1a7c3",
      "code": "KUV-7K9F-2XQD",
      "orderId": null,
      "status": "active",
      "initialOre": 50000,
      "balanceOre": 50000,
      "expiresAt": "2029-09-29T08:00:00.000Z",
      "merchantSlug": "cafe-noir",
      "origin": "b2b",
      "reference": "Faktura 2026-114",
      "punchValueOre": null,
      "noCashClaim": false,
      "productName": null
    },
    {
      "id": "gc_9b2e61d04c7f4a3e8d5b1c6a0f2e9d47",
      "code": "KUV-M4TQ-8WZR",
      "orderId": "ord_7d3f0b9c1e2a45f68b4c9d0e1f2a3b5c",
      "status": "active",
      "initialOre": 50000,
      "balanceOre": 43600,
      "expiresAt": "2029-06-12T14:31:07.000Z",
      "merchantSlug": "cafe-noir",
      "origin": "paid",
      "reference": null,
      "punchValueOre": null,
      "noCashClaim": false,
      "productName": "Gavekort"
    }
  ]
}

Svarfelter

Kortene står under giftCards, hvert i samme form som ved Slå et kort op.

Statuskoder

  • 200

    Listen, eventuelt tom.

En fejl har altid formen { "error": "…" }. Ethvert kald kan desuden svare 401, 403, 429 og 500 — se Fejl.

Slå et kort op

GET/v1/api/giftcards/{code}

Et kort ud fra dets kode, med saldoen, som den står lige nu.

curl https://api.kuvert.dk/v1/api/giftcards/KUV-7K9F-2XQD \
  -H "Authorization: Bearer $KUVERT_API_KEY"
200 OKJSON
{
  "giftCard": {
    "id": "gc_4f1c9a2e7b3d48e6a0c5d9f2b8e1a7c3",
    "code": "KUV-7K9F-2XQD",
    "orderId": null,
    "status": "active",
    "initialOre": 50000,
    "balanceOre": 50000,
    "expiresAt": "2029-09-29T08:00:00.000Z",
    "merchantSlug": "cafe-noir",
    "origin": "b2b",
    "reference": "Faktura 2026-114",
    "punchValueOre": null,
    "noCashClaim": false,
    "productName": null
  }
}
Prøv det i konsollen

Stiparametre

codestringPåkrævet
Kortets kode, fx KUV-7K9F-2XQD.

Svarfelter

Kortet står under giftCard:

idstring
Kortets id (gc_…). Koden er det, du slår op med.
codestring
Koden, der står på kortet.
orderIdstring | null
Ordren, kortet kom fra. null for et kort udstedt i hånden eller gennem API’et.
status"active" | "redeemed" | "expired" | "void" | "disputed"
Kortets tilstand. Kun active kan indløses.
initialOreinteger
Kortets værdi i øre, før noget er indløst.
balanceOreinteger
Saldoen i øre — regnet ud af posteringerne, ikke læst af et felt.
expiresAtstring
Hvornår kortet udløber, ISO 8601 i UTC.
merchantSlugstring
Butikkens adresse på shop.kuvert.dk.
origin"paid" | "sold" | "b2b" | "corporate" | "comp"
Hvor værdien kom fra. paid er købt i butikken og corporate købt som erhvervsgave; sold, b2b og comp er udstedt i hånden eller gennem API’et.
referencestring | null
Din egen note fra udstedelsen. null på et købt kort.
punchValueOreinteger | null
Værdien af ét klip, hvis kortet er et klippekort — ellers null. Et klippekort indløses i hele klip.
noCashClaimboolean
Kortet kan ikke ombyttes til kontanter.
productNamestring | null
Produktets navn, som det lød, da kortet blev udstedt. null på et kort udstedt i hånden.

Statuskoder

  • 200

    Kortet.

  • 400not_a_gift_card

    Koden i stien er en billetkode (TKT-…), ikke et gavekort.

  • 404gift_card_not_found

    Koden findes ikke på din forretning.

En fejl har altid formen { "error": "…" }. Ethvert kald kan desuden svare 401, 403, 429 og 500 — se Fejl.

Indløs

POST/v1/api/giftcards/{code}/redeem

Trækker et beløb fra kortets saldo. Koden står i stien, beløbet i kroppen.

Gem id. Det er posteringen, og det er det eneste, der kan fortryde netop denne indløsning.

Går det ikke igennem, er svaret én af disse. De er ikke ens for kassen: nogle er noget, gæsten skal have at vide, og nogle er noget, forretningen skal ringes op om.

curl -X POST https://api.kuvert.dk/v1/api/giftcards/KUV-7K9F-2XQD/redeem \
  -H "Authorization: Bearer $KUVERT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amountOre": 6400,
    "location": "Vesterbro",
    "idempotencyKey": "pos-3-20260929-0142"
  }'
200 OKJSON
{
  "id": "red_8f21c0b45d3e4a9b8c7d6e5f4a3b2c1d",
  "code": "KUV-7K9F-2XQD",
  "amountOre": 6400,
  "remainingBalanceOre": 43600,
  "status": "active"
}
Prøv det i konsollen

Stiparametre

codestringPåkrævet
Kortets kode, fx KUV-7K9F-2XQD.

Krop

amountOreintegerPåkrævet
Beløbet i øre, mindst 1. Et klippekort tager kun et helt antal klip.
locationstring | nullValgfri
Hvor det skete, fx «Vesterbro». Højst 120 tegn.
idempotencyKeystringValgfri
Samme nøgle to gange trækker kun én gang. Højst 120 tegn. Kan også sendes som header — se Idempotens.

Svarfelter

Svaret er posteringen:

idstring
Posteringens id (red_…) — det, du fortryder den med.
codestring
Kortets kode.
amountOreinteger
Det trukne beløb i øre.
remainingBalanceOreinteger
Saldoen efter indløsningen.
status"active" | "redeemed" | "expired" | "void" | "disputed"
status er kortets tilstand efter indløsningen — en af active, redeemed, expired, void, disputed. Er saldoen brugt op, skifter den til redeemed.

Statuskoder

  • 200

    Beløbet er trukket — eller, med en idempotencyKey brugt før på samme kort, svaret fra første gang, uden at der trækkes igen.

  • 400invalid_redeem_request

    Kroppen matcher ikke det, indløsning kræver — typisk et beløb, der ikke er et helt antal øre, eller som er nul.

  • 400not_a_gift_card

    Koden i stien er en billetkode (TKT-…), ikke et gavekort.

  • 404gift_card_not_found

    Koden findes ikke på din forretning.

  • 409card_inactive

    Kortet er ikke aktivt: brugt op, annulleret, sat til udløbet eller frosset under en indsigelse. Det går ikke over af sig selv — forretningen skal kontaktes.

  • 409redeem_too_soon

    Forretningen har sat en indløsningsforsinkelse, og den er ikke udløbet endnu. Kortet fejler ingenting; det kan bare ikke bruges endnu. Prøv igen senere.

  • 409idempotency_key_conflict

    Nøglen er allerede brugt på et andet kort — eller på en udbetaling af det samme kort. Se Idempotens.

  • 410gift_card_expired

    Kortet står stadig som aktivt, men gyldighedsdatoen er passeret. Til forskel fra card_inactive er det tiden og ikke en beslutning, der har lukket kortet.

  • 422insufficient_balance

    Beløbet er større end saldoen. Vi trækker aldrig et delvist beløb af os selv — slå kortet op, træk saldoen, og tag resten på anden vis.

  • 422invalid_amount

    Indløsningsreglens eget svar på et ulovligt beløb. Skemaet fanger det normalt allerede som 400 invalid_redeem_request, så en klient bør kunne læse begge.

  • 422punch_amount_not_whole

    Kortet er et klippekort, og beløbet er ikke et helt antal klip. Der er ikke noget galt med tallet — det er den forkerte slags kort til det. Slå kortet op, læs punchValueOre, og send den værdi eller et multiplum af den. Et klippekort, der står tilbage med en rest under ét klip, er penge, hverken kassen eller kunden kan nå.

En fejl har altid formen { "error": "…" }. Ethvert kald kan desuden svare 401, 403, 429 og 500 — se Fejl.

Fortryd en indløsning

POST/v1/api/redemptions/{id}/reverse

Lægger beløbet tilbage på kortet. Det sker som en ny postering med negativt beløb, der peger på den, den fortryder — ingenting slettes, og begge linjer bliver stående i kortets historik. Var kortet brugt helt op, bliver det aktivt igen.

curl -X POST https://api.kuvert.dk/v1/api/redemptions/red_8f21c0b45d3e4a9b8c7d6e5f4a3b2c1d/reverse \
  -H "Authorization: Bearer $KUVERT_API_KEY"
200 OKJSON
{
  "id": "red_2c77af90e1d24b3c9a8f7e6d5c4b3a21",
  "code": "KUV-7K9F-2XQD",
  "amountOre": -6400,
  "remainingBalanceOre": 50000,
  "status": "active"
}

Stiparametre

idstringPåkrævet
Indløsningens id (red_…), som du fik tilbage fra Indløs.

Svarfelter

Svaret er posteringen, der lagde beløbet tilbage — i samme form som ved Indløs, med negativt amountOre.

Statuskoder

  • 200

    Beløbet er lagt tilbage.

  • 404redemption_not_found

    Posteringen findes ikke på din forretning.

  • 409already_reversed

    Den er fortrudt før. Én gang, aldrig to.

  • 409not_reversible

    Posteringen er selv en fortrydelse eller en kontant udbetaling.

  • 409card_inactive

    Kortet er annulleret eller frosset under en indsigelse.

  • 409order_refunded

    Ordren bag kortet er refunderet. Køberen har allerede fået pengene tilbage, så en fortrydelse ville give dem værdien to gange.

En fejl har altid formen { "error": "…" }. Ethvert kald kan desuden svare 401, 403, 429 og 500 — se Fejl.

Bruges ofte sammen med

Send kortet igen

POST/v1/api/giftcards/{code}/resend

Sender kortet til modtageren igen — det, en kasse gør, når en kunde siger, at mailen aldrig kom.

Uden recipient sender vi det, kortets ordre endnu ikke har fået leveret, til den adresse, det står med — et kort, der allerede er leveret, sendes ikke igen. Med recipient retter du adressen på netop dette kort og sender det dertil, også hvis det er leveret før. Kun aktive kort sendes.

curl -X POST https://api.kuvert.dk/v1/api/giftcards/KUV-M4TQ-8WZR/resend \
  -H "Authorization: Bearer $KUVERT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipient": "ny-adresse@dit-domaene.dk"
  }'
200 OKJSON
{
  "delivered": 1
}

Stiparametre

codestringPåkrævet
Kortets kode, fx KUV-7K9F-2XQD.

Krop

recipientstringValgfri
En ny emailadresse til kortet. Kroppen kan udelades helt.

Svarfelter

Svaret siger, hvor meget der blev sendt:

deliveredinteger
Antal kort, der blev sendt. 0 betyder, at der ikke var noget at sende.

Statuskoder

  • 200

    Sendt — eller intet at sende.

  • 400not_a_gift_card

    Koden i stien er en billetkode (TKT-…), ikke et gavekort.

  • 404gift_card_not_found

    Koden findes ikke på din forretning.

  • 404order_not_found

    Gensend fandt kortet, men ikke den ordre, det kom fra. Et kort udstedt i hånden har ingen ordre og kan derfor ikke gensendes ad den vej.

  • 409card_has_no_delivery

    Kortet har aldrig været sendt af os — det blev udleveret over disken. Der er ingen levering at gentage.

  • 422invalid_recipient

    recipient i kroppen på gensend er ikke en emailadresse, vi kan sende til. Udelad feltet for at sende til den adresse, kortet allerede står med.

  • 502delivery_failed

    Vi nåede vores udbyder, og den afviste forsendelsen. Kortet fejler ingenting, og intet er trukket — prøv igen, eller kontrollér adressen.

En fejl har altid formen { "error": "…" }. Ethvert kald kan desuden svare 401, 403, 429 og 500 — se Fejl.

Bruges ofte sammen med

Annullér et kort

POST/v1/api/giftcards/{code}/cancel

Annullerer kortet med det samme. Saldoen bliver stående på kortet, men den kan ikke længere bruges, og det kan ikke fortrydes. Er kortet allerede annulleret, får du det tilbage, som det er, uden fejl.

curl -X POST https://api.kuvert.dk/v1/api/giftcards/KUV-7K9F-2XQD/cancel \
  -H "Authorization: Bearer $KUVERT_API_KEY"
200 OKJSON
{
  "giftCard": {
    "id": "gc_4f1c9a2e7b3d48e6a0c5d9f2b8e1a7c3",
    "code": "KUV-7K9F-2XQD",
    "orderId": null,
    "status": "void",
    "initialOre": 50000,
    "balanceOre": 50000,
    "expiresAt": "2029-09-29T08:00:00.000Z",
    "merchantSlug": "cafe-noir",
    "origin": "b2b",
    "reference": "Faktura 2026-114",
    "punchValueOre": null,
    "noCashClaim": false,
    "productName": null
  }
}

Stiparametre

codestringPåkrævet
Kortets kode, fx KUV-7K9F-2XQD.

Svarfelter

Kortet står under giftCard, nu med status void.

Statuskoder

  • 200

    Kortet er annulleret — eller var det allerede.

  • 400not_a_gift_card

    Koden i stien er en billetkode (TKT-…), ikke et gavekort.

  • 404gift_card_not_found

    Koden findes ikke på din forretning.

En fejl har altid formen { "error": "…" }. Ethvert kald kan desuden svare 401, 403, 429 og 500 — se Fejl.

Refundér en ordre

POST/v1/api/orders/{id}/refund

Sender hele betalingen for ordren tilbage til det kort, der betalte — køberens ekspeditionsgebyr med — og Kuverts gebyr på salget går tilbage til dig. Det er det eneste endepunkt, der flytter penge.

Når Stripe har bekræftet refunderingen, tages værdien af ordrens kort, dens billetter annulleres, og order.refunded sendes. Det sker typisk få sekunder efter svaret.

Kaldet tager ingen idempotensnøgle — ordrens egen status er spærren. En ordre, der allerede er refunderet, svarer 409 order_not_refundable.

curl -X POST https://api.kuvert.dk/v1/api/orders/ord_7d3f0b9c1e2a45f68b4c9d0e1f2a3b5c/refund \
  -H "Authorization: Bearer $KUVERT_API_KEY"
200 OKJSON
{
  "orderId": "ord_7d3f0b9c1e2a45f68b4c9d0e1f2a3b5c",
  "refundId": "re_3PqX9aLkT2mN8vRb1c4D7eFg",
  "amountOre": 50500
}

Stiparametre

idstringPåkrævet
Ordrens id (ord_…) — orderId på kortet eller i order.paid.

Svarfelter

Svaret er refunderingen, som Stripe tog imod den:

orderIdstring
Ordren.
refundIdstring
Stripes id for refunderingen (re_…) — det, du finder den under i Stripe.
amountOreinteger
Beløbet, der sendes tilbage, i øre.

Statuskoder

  • 200

    Stripe har taget imod refunderingen.

  • 404order_not_found

    Ordren findes ikke på din forretning.

  • 409order_not_refundable

    Ordren kan ikke refunderes: den er ikke betalt, allerede refunderet, eller frosset under en indsigelse.

  • 409merchant_not_payment_ready

    Din Stripe-konto er ikke forbundet.

  • 503stripe_not_configured

    Betalinger er midlertidigt utilgængelige hos os. Prøv igen senere.

En fejl har altid formen { "error": "…" }. Ethvert kald kan desuden svare 401, 403, 429 og 500 — se Fejl.

Var siden nyttig?