Changelog
What changed in the API and the dashboard, newest first.
25 October 2026: a reward only on a full card, and one renewal per pass every 10 minutes
Three rules that stop a new stamp round or a later validUntil from slipping past billing.
- Redeeming a stamp card that isn’t full is a
409 reward_not_readyeverywhere.POST /v1/passes/{id}/redeemalready did this; the dashboard and the scanner now do too. - A full stamp card can’t be lowered with
PATCH /v1/passes/{id}to a number below the total (409 card_full). Settingvalues.stampsto0still starts a new round and is billed as one. - A pass can get a new round or a later
validUntilonce every 10 minutes. Asking again sooner is a409 renewal_too_soon. Undoing a renewal frees the wait; trial and test passes aren’t limited.
19 October 2026: warnings, onDevice and readable validUntil dates on passes
Every pass has two new fields, warnings and onDevice, so existing integrations keep working.
warningslists what the request asked for that the pass didn’t get.valid_until_cappedmeans a trial pass (every pass a test key issues) can’t be valid past its expiry, so your latervalues.validUntilwas replaced by the expiry date. Before, this happened with no sign in the response.onDevice.appleistruewhen at least one iPhone has registered the pass with Apple Wallet.saved.applekeeps its meaning: the.pkpassfile was downloaded, which can also be a script or a cancelled add.onDevice.googleequalssaved.google.- A
values.validUntilsent as an ISO date (2026-12-31) is now written like Korti’s own default, in the card’s language (31 Dec 2026,31. des. 2026), instead of the raw text.
19 October 2026: a redeemed coupon looks used in the wallet
Redeeming a coupon now shows Used
with the date on the customer’s card and greys it out in Apple Wallet and Google Wallet. Apple’s lock screen says it too. The pass keeps status: "active", and undoing the redeem makes the card valid again. Apple Wallet is also no longer told about passes that didn’t change, so it stops re-downloading them.
16 October 2026: test passes are marked in events and kept out of the dashboard
Webhook events and GET /v1/events now have test: true for events of passes a test key issued, false for all others. It is a new field on every event, so existing integrations keep working.
- In the dashboard, passes issued with a test key are hidden from the customers lists unless you choose Sýna kort frá prufulykli, and are left out of the home figures, the wallet chart, the card page and the activity feed.
- Updates you send to a card’s customers never go to test passes.
16 October 2026: custom values by their listed name
values now accepts custom.<key>, the name GET /v1/cards lists. Before, only the nested form worked and the listed name was refused as a misspelling.
{ "custom.member_number": "M-0042" }and{ "custom": { "member_number": "M-0042" } }store the same value, onPOST /v1/passesandPATCH /v1/passes/{id}. The nested form still works.- A key sent in both forms in one request gets
422 invalid_requestnaming both. A dotted key Korti can’t use gets an error that points to the nested form. - Issue a pass now explains custom values and how they differ from the built-in
memberNumber.
16 October 2026: limits per business
Request limits now apply to the whole business, not just each key. Normal use is unaffected.
- All the keys of a business share 300 requests a minute, on top of 100 a minute per key. Over either limit you get
429 rate_limitedwithRetry-After, as before. - A business can have up to 10 active API keys. Revoke one to create another.
- Korti remembers at most 50,000 idempotent responses; the oldest are forgotten first.
16 October 2026: input limits
The API now bounds what it accepts. Requests inside these limits are unaffected.
- A request body can be up to 64 KB. Larger ones get
413 payload_too_large. values.customcan have up to 20 keys, and a pass can have up to 20 custom values in total. More gets422.- One points or balance change (
delta) can be up to 1,000,000 either way, and a pass holds up to 1,000,000,000 points, stamps, visits or kr. Beyond that you get422 value_out_of_range. - Idempotency keys are now shared by all keys of a business (live keys with live keys, test keys with test keys), and responses over 16 KB aren’t remembered, though they’re still returned.
16 October 2026
Test keys issue trial passes only. Before this, test keys and live keys reached the same passes.
- A test key (
sk_test_…) always issues a trial pass: it expires, is never billed and doesn’t count toward your trial cards, even after your business has gone live. - A test key can read, update and void only the passes test keys issued. Other passes answer
404, and the list and event endpoints show only test passes. - Test keys can issue 100 passes in any seven days. After that you get
403 test_limituntil older test passes expire. - Passes have a new
testfield. Live keys behave as before.
10 October 2026
The Korti API, version 1. The first public version of the API.
- Cards:
GET /v1/cardsandGET /v1/cards/{id}, with each card’s variables. - Passes: issue, list, get, update, add stamps, add points, change a balance, redeem and void.
- Events:
GET /v1/events, and webhooks signed withKorti-Signature. Idempotency-Keyon everyPOSTandPATCH, and a limit of 100 requests a minute per key.- An OpenAPI 3.1 spec at /v1/openapi.json, and an interactive explorer.
- API keys and webhooks in the dashboard, under Developers.