API reference
Every endpoint, generated from the same OpenAPI spec the API serves. Requests and responses are JSON.
Authentication
Send an API key with every request, in the Authorization header. Create keys in the dashboard under Developers.
Authorization: Bearer sk_live_4f9aQm…Test keys and live keysA test key (sk_test_…) only ever issues trial passes, even after your business has gone live. They expire after seven days, are never billed and don’t count toward your trial cards, and they have test: true. A test key can read, update and void only the passes test keys issued: any other pass answers 404, and GET /v1/passes and GET /v1/events list only test passes. A business can issue 100 test passes in any seven days, then gets 403 test_limit. A live key (sk_live_…) works on every pass in your business.
Also availableThe spec at /v1/openapi.json works with any OpenAPI tool or client generator. The interactive explorer lets you send requests with your own key.
Cards
List cards
Published cards in your business, newest change first. Drafts don’t show until you publish them.
curl https://korti.is/v1/cards \
-H "Authorization: Bearer $KORTI_KEY"Returns 200: Published cards.
objectenumAlways the same, so you can tell objects apart.
listdataarray of objectThe items.
- 401unauthorized
The API key is missing, wrong or revoked.
- 429rate_limited
Too many requests. Wait for
Retry-Afterseconds.
Get a card
A published card and the variables you can set when you issue a pass from it.
idstring, in pathRequiredThe ID.
curl https://korti.is/v1/cards/CARD_ID \
-H "Authorization: Bearer $KORTI_KEY"Returns 200: The card.
idstringobjectenumAlways the same, so you can tell objects apart.
cardnamestringtypeenumstamppunchpointsmembershipgiftcouponeventversionintegerPublished version that new passes use.
shareUrlstringPublic sign-up link.
variablesarray of objectcreatedAtstringupdatedAtstring- 401unauthorized
The API key is missing, wrong or revoked.
- 404not_found
Nothing with that ID in this business.
- 429rate_limited
Too many requests. Wait for
Retry-Afterseconds.
Passes
List passes
Passes in your business, newest first. A test key lists only the passes test keys issued.
cardstring, in queryOptionalOnly passes for this card ID.
qstring, in queryOptionalSearch name, email or serial.
limitinteger, in queryOptional1 to 100. Defaults to 20.
curl https://korti.is/v1/passes \
-H "Authorization: Bearer $KORTI_KEY"Returns 200: Passes, newest first.
objectenumAlways the same, so you can tell objects apart.
listdataarray of objectThe items.
- 401unauthorized
The API key is missing, wrong or revoked.
- 404not_found
Nothing with that ID in this business.
- 422invalid_request
A value isn’t valid.
paramsays which. - 429rate_limited
Too many requests. Wait for
Retry-Afterseconds.
Issue a pass
Creates a pass for one customer from a published card and returns the links they use to save it. Send an Idempotency-Key header so a retried request never makes a second pass. A test key (sk_test_…) always issues a trial pass: it expires after seven days, is never billed, and doesn’t count toward your trial cards.
Idempotency-KeyheaderOptionalAny unique string up to 255 characters. The same key within 24 hours, from any key of your business, replays the first response. Responses over 16 KB aren’t remembered.
Body
cardstringRequiredID of a published card. See GET /v1/cards.
customerobjectOptionalWho the pass is for.
namestringOptionalUp to 60 characters.
emailstring or enumOptionalphonestringOptionalUp to 30 characters.
valuesobjectOptionalValues for the card’s variables. Send only the ones you want to set. A custom value goes either nested, as { "custom": { "member_number": "M-0042" } }, or under the dotted name GET /v1/cards lists, as { "custom.member_number": "M-0042" }. Both store the same thing; sending one key both ways is refused.
stampsintegerOptionalAt least 0. At most 1000000000.
pointsintegerOptionalAt least 0. At most 1000000000.
visitsLeftintegerOptionalAt least 0. At most 1000000000.
balancenumberOptionalAt least 0. At most 1000000000.
memberNumberstringOptionalThe built-in membership number. A holder detail you added yourself is a custom value. Up to 40 characters.
memberSincestringOptionalUp to 40 characters.
validUntilstringOptionalWhen the card runs out, as text shown on the card. A date (2026-12-31 or 31.12.2026, day first) is written the way the card writes dates, in the card’s language (31 Dec 2026, 31. des. 2026); a value written like a date that doesn’t exist (31.2.2026) is refused with invalid_valid_until. Other text is shown as you send it, but changing a date to or from text that isn’t a date counts as a renewal. A trial pass can’t be valid past its expiry: a later date is replaced by it, and the response carries a valid_until_capped warning. Up to 40 characters.
seatstringOptionalUp to 40 characters.
customobject of stringsOptionalsendEmailbooleanOptionalEmail the customer a link to their card. Needs customer.email.
curl -X POST https://korti.is/v1/passes \
-H "Authorization: Bearer $KORTI_KEY" \
-H "Content-Type: application/json" \
-d '{
"card": "CARD_ID",
"customer": { "name": "Anna Jónsdóttir" },
"values": { "stamps": 1 }
}'Returns 201: The pass exists and its links work.
idstringobjectenumAlways the same, so you can tell objects apart.
passcardstringserialstringPrinted on the card and encoded in its barcode.
statusenumactivevoidedtrialbooleanIssued on Korti’s trial certificate. Trial passes expire.
testbooleanIssued with a test key. Test passes are always trial passes, and only test keys can reach them.
expiresAtstring, nullablecustomerobjectWho the pass is for.
namestringemailstringphonestringvaluesobjectstampsintegerpointsintegervisitsLeftintegerbalancenumbermemberNumberstringmemberSincestringvalidUntilstringseatstringcustomobject of stringsrewardReadybooleanStamp cards: the card is full and the reward can be given.
warningsarray of objectThings that didn’t go as designed. barcode_fallback: the card’s barcode value, filled in for this customer, can’t be encoded in its format (for example an emoji in a Code 128 barcode), so this pass’s barcode holds its serial instead of no code at all (set on every read). valid_until_capped: a trial pass (every pass a test key issues, and live-key passes before your business goes live) is never valid past its expiry, so a later values.validUntil was replaced by the expiry date; the message says which date the pass shows (set on the response to POST /v1/passes and PATCH /v1/passes/{id} that sent it, empty on later reads).
savedobjectapple: the customer’s link to the .pkpass file was downloaded (appleDownloadedAt), which is not the same as the card being on a phone: a download can be cancelled, and your own scripts count. For “is it on a phone”, read onDevice. google: the customer saved it to Google Wallet.
applebooleangooglebooleanonDeviceobjectWhether the card is on a phone. apple: at least one iPhone has registered the pass with Apple Wallet to get updates (false until the customer adds it, and again if every device removes it). google: the customer saved it to Google Wallet, the same as saved.google.
applebooleangooglebooleanurlstringThe customer’s own card page. Works on any phone.
appleUrlstringgoogleUrlstringcreatedAtstringupdatedAtstring- 400invalid_json
The body isn’t valid JSON.
- 401unauthorized
The API key is missing, wrong or revoked.
- 403trial_limit
The business can’t do this yet, for example the Apple trial limit is reached.
- 404not_found
Nothing with that ID in this business.
- 409conflict
The request conflicts with the current state, for example the card is a draft.
- 413error
The request body is larger than 64 KB.
- 422invalid_request
A value isn’t valid.
paramsays which. - 429rate_limited
Too many requests. Wait for
Retry-Afterseconds.
Get a pass
A test key gets a 404 for passes a live key issued.
idstring, in pathRequiredThe ID.
curl https://korti.is/v1/passes/PASS_ID \
-H "Authorization: Bearer $KORTI_KEY"Returns 200: The pass.
idstringobjectenumAlways the same, so you can tell objects apart.
passcardstringserialstringPrinted on the card and encoded in its barcode.
statusenumactivevoidedtrialbooleanIssued on Korti’s trial certificate. Trial passes expire.
testbooleanIssued with a test key. Test passes are always trial passes, and only test keys can reach them.
expiresAtstring, nullablecustomerobjectWho the pass is for.
namestringemailstringphonestringvaluesobjectstampsintegerpointsintegervisitsLeftintegerbalancenumbermemberNumberstringmemberSincestringvalidUntilstringseatstringcustomobject of stringsrewardReadybooleanStamp cards: the card is full and the reward can be given.
warningsarray of objectThings that didn’t go as designed. barcode_fallback: the card’s barcode value, filled in for this customer, can’t be encoded in its format (for example an emoji in a Code 128 barcode), so this pass’s barcode holds its serial instead of no code at all (set on every read). valid_until_capped: a trial pass (every pass a test key issues, and live-key passes before your business goes live) is never valid past its expiry, so a later values.validUntil was replaced by the expiry date; the message says which date the pass shows (set on the response to POST /v1/passes and PATCH /v1/passes/{id} that sent it, empty on later reads).
savedobjectapple: the customer’s link to the .pkpass file was downloaded (appleDownloadedAt), which is not the same as the card being on a phone: a download can be cancelled, and your own scripts count. For “is it on a phone”, read onDevice. google: the customer saved it to Google Wallet.
applebooleangooglebooleanonDeviceobjectWhether the card is on a phone. apple: at least one iPhone has registered the pass with Apple Wallet to get updates (false until the customer adds it, and again if every device removes it). google: the customer saved it to Google Wallet, the same as saved.google.
applebooleangooglebooleanurlstringThe customer’s own card page. Works on any phone.
appleUrlstringgoogleUrlstringcreatedAtstringupdatedAtstring- 401unauthorized
The API key is missing, wrong or revoked.
- 404not_found
Nothing with that ID in this business.
- 429rate_limited
Too many requests. Wait for
Retry-Afterseconds.
Update a pass
Changes values or customer details and pushes the new version to every phone that saved the pass. Phones show it within seconds. Send only what changes; custom values are merged. Moving values.validUntil later, or clearing it, on a pass that already had one (a renewal, also before it expires, or bringing an expired pass back) is billed as one card, like issuing one, unless the pass is a trial or test pass. Setting a first date or a shorter one is free. Setting values.stamps to 0 on a full stamp card starts a new round and is billed the same way. A full stamp card can’t be lowered to any other number (409 card_full): redeem it, or set it to 0. A pass can be renewed once every 10 minutes; a second renewal sooner is a 409 renewal_too_soon.
idstring, in pathRequiredThe ID.
Idempotency-KeyheaderOptionalAny unique string up to 255 characters. The same key within 24 hours, from any key of your business, replays the first response. Responses over 16 KB aren’t remembered.
Body
customerobjectOptionalWho the pass is for.
namestringOptionalUp to 60 characters.
emailstring or enumOptionalvaluesobjectOptionalValues for the card’s variables. Send only the ones you want to set. A custom value goes either nested, as { "custom": { "member_number": "M-0042" } }, or under the dotted name GET /v1/cards lists, as { "custom.member_number": "M-0042" }. Both store the same thing; sending one key both ways is refused.
stampsintegerOptionalAt least 0. At most 1000000000.
pointsintegerOptionalAt least 0. At most 1000000000.
visitsLeftintegerOptionalAt least 0. At most 1000000000.
balancenumberOptionalAt least 0. At most 1000000000.
memberNumberstringOptionalThe built-in membership number. A holder detail you added yourself is a custom value. Up to 40 characters.
memberSincestringOptionalUp to 40 characters.
validUntilstringOptionalWhen the card runs out, as text shown on the card. A date (2026-12-31 or 31.12.2026, day first) is written the way the card writes dates, in the card’s language (31 Dec 2026, 31. des. 2026); a value written like a date that doesn’t exist (31.2.2026) is refused with invalid_valid_until. Other text is shown as you send it, but changing a date to or from text that isn’t a date counts as a renewal. A trial pass can’t be valid past its expiry: a later date is replaced by it, and the response carries a valid_until_capped warning. Up to 40 characters.
seatstringOptionalUp to 40 characters.
customobject of stringsOptionalcurl -X PATCH https://korti.is/v1/passes/PASS_ID \
-H "Authorization: Bearer $KORTI_KEY" \
-H "Content-Type: application/json" \
-d '{ "values": { "memberNumber": "004182" } }'Returns 200: The updated pass.
idstringobjectenumAlways the same, so you can tell objects apart.
passcardstringserialstringPrinted on the card and encoded in its barcode.
statusenumactivevoidedtrialbooleanIssued on Korti’s trial certificate. Trial passes expire.
testbooleanIssued with a test key. Test passes are always trial passes, and only test keys can reach them.
expiresAtstring, nullablecustomerobjectWho the pass is for.
namestringemailstringphonestringvaluesobjectstampsintegerpointsintegervisitsLeftintegerbalancenumbermemberNumberstringmemberSincestringvalidUntilstringseatstringcustomobject of stringsrewardReadybooleanStamp cards: the card is full and the reward can be given.
warningsarray of objectThings that didn’t go as designed. barcode_fallback: the card’s barcode value, filled in for this customer, can’t be encoded in its format (for example an emoji in a Code 128 barcode), so this pass’s barcode holds its serial instead of no code at all (set on every read). valid_until_capped: a trial pass (every pass a test key issues, and live-key passes before your business goes live) is never valid past its expiry, so a later values.validUntil was replaced by the expiry date; the message says which date the pass shows (set on the response to POST /v1/passes and PATCH /v1/passes/{id} that sent it, empty on later reads).
savedobjectapple: the customer’s link to the .pkpass file was downloaded (appleDownloadedAt), which is not the same as the card being on a phone: a download can be cancelled, and your own scripts count. For “is it on a phone”, read onDevice. google: the customer saved it to Google Wallet.
applebooleangooglebooleanonDeviceobjectWhether the card is on a phone. apple: at least one iPhone has registered the pass with Apple Wallet to get updates (false until the customer adds it, and again if every device removes it). google: the customer saved it to Google Wallet, the same as saved.google.
applebooleangooglebooleanurlstringThe customer’s own card page. Works on any phone.
appleUrlstringgoogleUrlstringcreatedAtstringupdatedAtstring- 400invalid_json
The body isn’t valid JSON.
- 401unauthorized
The API key is missing, wrong or revoked.
- 404not_found
Nothing with that ID in this business.
- 409conflict
The request conflicts with the current state, for example the card is a draft.
- 413error
The request body is larger than 64 KB.
- 422invalid_request
A value isn’t valid.
paramsays which. - 429rate_limited
Too many requests. Wait for
Retry-Afterseconds.
Add stamps
Stamp cards only. Adds stamps up to the card’s total. When rewardReady is true, redeem the reward to start over.
idstring, in pathRequiredThe ID.
Idempotency-KeyheaderOptionalAny unique string up to 255 characters. The same key within 24 hours, from any key of your business, replays the first response. Responses over 16 KB aren’t remembered.
Body
countintegerOptionalDefaults to 1. At least 1. At most 12.
curl -X POST https://korti.is/v1/passes/PASS_ID/stamps \
-H "Authorization: Bearer $KORTI_KEY" \
-H "Content-Type: application/json" \
-d '{ "count": 1 }'Returns 200: The updated pass.
idstringobjectenumAlways the same, so you can tell objects apart.
passcardstringserialstringPrinted on the card and encoded in its barcode.
statusenumactivevoidedtrialbooleanIssued on Korti’s trial certificate. Trial passes expire.
testbooleanIssued with a test key. Test passes are always trial passes, and only test keys can reach them.
expiresAtstring, nullablecustomerobjectWho the pass is for.
namestringemailstringphonestringvaluesobjectstampsintegerpointsintegervisitsLeftintegerbalancenumbermemberNumberstringmemberSincestringvalidUntilstringseatstringcustomobject of stringsrewardReadybooleanStamp cards: the card is full and the reward can be given.
warningsarray of objectThings that didn’t go as designed. barcode_fallback: the card’s barcode value, filled in for this customer, can’t be encoded in its format (for example an emoji in a Code 128 barcode), so this pass’s barcode holds its serial instead of no code at all (set on every read). valid_until_capped: a trial pass (every pass a test key issues, and live-key passes before your business goes live) is never valid past its expiry, so a later values.validUntil was replaced by the expiry date; the message says which date the pass shows (set on the response to POST /v1/passes and PATCH /v1/passes/{id} that sent it, empty on later reads).
savedobjectapple: the customer’s link to the .pkpass file was downloaded (appleDownloadedAt), which is not the same as the card being on a phone: a download can be cancelled, and your own scripts count. For “is it on a phone”, read onDevice. google: the customer saved it to Google Wallet.
applebooleangooglebooleanonDeviceobjectWhether the card is on a phone. apple: at least one iPhone has registered the pass with Apple Wallet to get updates (false until the customer adds it, and again if every device removes it). google: the customer saved it to Google Wallet, the same as saved.google.
applebooleangooglebooleanurlstringThe customer’s own card page. Works on any phone.
appleUrlstringgoogleUrlstringcreatedAtstringupdatedAtstring- 400invalid_json
The body isn’t valid JSON.
- 401unauthorized
The API key is missing, wrong or revoked.
- 404not_found
Nothing with that ID in this business.
- 409conflict
The request conflicts with the current state, for example the card is a draft.
- 413error
The request body is larger than 64 KB.
- 422invalid_request
A value isn’t valid.
paramsays which. - 429rate_limited
Too many requests. Wait for
Retry-Afterseconds.
Punch one visit
Klippikort (prepaid punch cards) only. Uses one visit. Fails with 409 card_empty when none are left.
idstring, in pathRequiredThe ID.
Idempotency-KeyheaderOptionalAny unique string up to 255 characters. The same key within 24 hours, from any key of your business, replays the first response. Responses over 16 KB aren’t remembered.
curl -X POST https://korti.is/v1/passes/PASS_ID/punch \
-H "Authorization: Bearer $KORTI_KEY"Returns 200: The updated pass.
idstringobjectenumAlways the same, so you can tell objects apart.
passcardstringserialstringPrinted on the card and encoded in its barcode.
statusenumactivevoidedtrialbooleanIssued on Korti’s trial certificate. Trial passes expire.
testbooleanIssued with a test key. Test passes are always trial passes, and only test keys can reach them.
expiresAtstring, nullablecustomerobjectWho the pass is for.
namestringemailstringphonestringvaluesobjectstampsintegerpointsintegervisitsLeftintegerbalancenumbermemberNumberstringmemberSincestringvalidUntilstringseatstringcustomobject of stringsrewardReadybooleanStamp cards: the card is full and the reward can be given.
warningsarray of objectThings that didn’t go as designed. barcode_fallback: the card’s barcode value, filled in for this customer, can’t be encoded in its format (for example an emoji in a Code 128 barcode), so this pass’s barcode holds its serial instead of no code at all (set on every read). valid_until_capped: a trial pass (every pass a test key issues, and live-key passes before your business goes live) is never valid past its expiry, so a later values.validUntil was replaced by the expiry date; the message says which date the pass shows (set on the response to POST /v1/passes and PATCH /v1/passes/{id} that sent it, empty on later reads).
savedobjectapple: the customer’s link to the .pkpass file was downloaded (appleDownloadedAt), which is not the same as the card being on a phone: a download can be cancelled, and your own scripts count. For “is it on a phone”, read onDevice. google: the customer saved it to Google Wallet.
applebooleangooglebooleanonDeviceobjectWhether the card is on a phone. apple: at least one iPhone has registered the pass with Apple Wallet to get updates (false until the customer adds it, and again if every device removes it). google: the customer saved it to Google Wallet, the same as saved.google.
applebooleangooglebooleanurlstringThe customer’s own card page. Works on any phone.
appleUrlstringgoogleUrlstringcreatedAtstringupdatedAtstring- 400invalid_json
The body isn’t valid JSON.
- 401unauthorized
The API key is missing, wrong or revoked.
- 404not_found
Nothing with that ID in this business.
- 409conflict
The request conflicts with the current state, for example the card is a draft.
- 413error
The request body is larger than 64 KB.
- 422invalid_request
A value isn’t valid.
paramsays which. - 429rate_limited
Too many requests. Wait for
Retry-Afterseconds.
Refill a klippikort
Klippikort only. Adds visits after the customer buys a new card, up to the card’s total. A refill is a new klippikort sold, so it’s billed as one card (the same price as issuing a card), unless the pass is a trial or test pass. It goes through the same checks as issuing a card, so it can fail with payment_card_needed or payment_overdue.
idstring, in pathRequiredThe ID.
Idempotency-KeyheaderOptionalAny unique string up to 255 characters. The same key within 24 hours, from any key of your business, replays the first response. Responses over 16 KB aren’t remembered.
Body
visitsintegerOptionalVisits to add. Defaults to a full card. The card never holds more than its total. At least 1. At most 100.
curl -X POST https://korti.is/v1/passes/PASS_ID/refill \
-H "Authorization: Bearer $KORTI_KEY"Returns 200: The updated pass.
idstringobjectenumAlways the same, so you can tell objects apart.
passcardstringserialstringPrinted on the card and encoded in its barcode.
statusenumactivevoidedtrialbooleanIssued on Korti’s trial certificate. Trial passes expire.
testbooleanIssued with a test key. Test passes are always trial passes, and only test keys can reach them.
expiresAtstring, nullablecustomerobjectWho the pass is for.
namestringemailstringphonestringvaluesobjectstampsintegerpointsintegervisitsLeftintegerbalancenumbermemberNumberstringmemberSincestringvalidUntilstringseatstringcustomobject of stringsrewardReadybooleanStamp cards: the card is full and the reward can be given.
warningsarray of objectThings that didn’t go as designed. barcode_fallback: the card’s barcode value, filled in for this customer, can’t be encoded in its format (for example an emoji in a Code 128 barcode), so this pass’s barcode holds its serial instead of no code at all (set on every read). valid_until_capped: a trial pass (every pass a test key issues, and live-key passes before your business goes live) is never valid past its expiry, so a later values.validUntil was replaced by the expiry date; the message says which date the pass shows (set on the response to POST /v1/passes and PATCH /v1/passes/{id} that sent it, empty on later reads).
savedobjectapple: the customer’s link to the .pkpass file was downloaded (appleDownloadedAt), which is not the same as the card being on a phone: a download can be cancelled, and your own scripts count. For “is it on a phone”, read onDevice. google: the customer saved it to Google Wallet.
applebooleangooglebooleanonDeviceobjectWhether the card is on a phone. apple: at least one iPhone has registered the pass with Apple Wallet to get updates (false until the customer adds it, and again if every device removes it). google: the customer saved it to Google Wallet, the same as saved.google.
applebooleangooglebooleanurlstringThe customer’s own card page. Works on any phone.
appleUrlstringgoogleUrlstringcreatedAtstringupdatedAtstring- 400invalid_json
The body isn’t valid JSON.
- 401unauthorized
The API key is missing, wrong or revoked.
- 404not_found
Nothing with that ID in this business.
- 409conflict
The request conflicts with the current state, for example the card is a draft.
- 413error
The request body is larger than 64 KB.
- 422invalid_request
A value isn’t valid.
paramsays which. - 429rate_limited
Too many requests. Wait for
Retry-Afterseconds.
Add or remove points
Points cards only. A negative delta takes points away. Points never go below 0.
idstring, in pathRequiredThe ID.
Idempotency-KeyheaderOptionalAny unique string up to 255 characters. The same key within 24 hours, from any key of your business, replays the first response. Responses over 16 KB aren’t remembered.
Body
deltanumberRequiredcurl -X POST https://korti.is/v1/passes/PASS_ID/points \
-H "Authorization: Bearer $KORTI_KEY" \
-H "Content-Type: application/json" \
-d '{ "delta": 50 }'Returns 200: The updated pass.
idstringobjectenumAlways the same, so you can tell objects apart.
passcardstringserialstringPrinted on the card and encoded in its barcode.
statusenumactivevoidedtrialbooleanIssued on Korti’s trial certificate. Trial passes expire.
testbooleanIssued with a test key. Test passes are always trial passes, and only test keys can reach them.
expiresAtstring, nullablecustomerobjectWho the pass is for.
namestringemailstringphonestringvaluesobjectstampsintegerpointsintegervisitsLeftintegerbalancenumbermemberNumberstringmemberSincestringvalidUntilstringseatstringcustomobject of stringsrewardReadybooleanStamp cards: the card is full and the reward can be given.
warningsarray of objectThings that didn’t go as designed. barcode_fallback: the card’s barcode value, filled in for this customer, can’t be encoded in its format (for example an emoji in a Code 128 barcode), so this pass’s barcode holds its serial instead of no code at all (set on every read). valid_until_capped: a trial pass (every pass a test key issues, and live-key passes before your business goes live) is never valid past its expiry, so a later values.validUntil was replaced by the expiry date; the message says which date the pass shows (set on the response to POST /v1/passes and PATCH /v1/passes/{id} that sent it, empty on later reads).
savedobjectapple: the customer’s link to the .pkpass file was downloaded (appleDownloadedAt), which is not the same as the card being on a phone: a download can be cancelled, and your own scripts count. For “is it on a phone”, read onDevice. google: the customer saved it to Google Wallet.
applebooleangooglebooleanonDeviceobjectWhether the card is on a phone. apple: at least one iPhone has registered the pass with Apple Wallet to get updates (false until the customer adds it, and again if every device removes it). google: the customer saved it to Google Wallet, the same as saved.google.
applebooleangooglebooleanurlstringThe customer’s own card page. Works on any phone.
appleUrlstringgoogleUrlstringcreatedAtstringupdatedAtstring- 400invalid_json
The body isn’t valid JSON.
- 401unauthorized
The API key is missing, wrong or revoked.
- 404not_found
Nothing with that ID in this business.
- 409conflict
The request conflicts with the current state, for example the card is a draft.
- 413error
The request body is larger than 64 KB.
- 422invalid_request
A value isn’t valid.
paramsays which. - 429rate_limited
Too many requests. Wait for
Retry-Afterseconds.
Top up or spend a balance
Gift cards only. A negative delta spends from the balance, which can’t go below 0.
idstring, in pathRequiredThe ID.
Idempotency-KeyheaderOptionalAny unique string up to 255 characters. The same key within 24 hours, from any key of your business, replays the first response. Responses over 16 KB aren’t remembered.
Body
deltanumberRequiredcurl -X POST https://korti.is/v1/passes/PASS_ID/balance \
-H "Authorization: Bearer $KORTI_KEY" \
-H "Content-Type: application/json" \
-d '{ "delta": -1500 }'Returns 200: The updated pass.
idstringobjectenumAlways the same, so you can tell objects apart.
passcardstringserialstringPrinted on the card and encoded in its barcode.
statusenumactivevoidedtrialbooleanIssued on Korti’s trial certificate. Trial passes expire.
testbooleanIssued with a test key. Test passes are always trial passes, and only test keys can reach them.
expiresAtstring, nullablecustomerobjectWho the pass is for.
namestringemailstringphonestringvaluesobjectstampsintegerpointsintegervisitsLeftintegerbalancenumbermemberNumberstringmemberSincestringvalidUntilstringseatstringcustomobject of stringsrewardReadybooleanStamp cards: the card is full and the reward can be given.
warningsarray of objectThings that didn’t go as designed. barcode_fallback: the card’s barcode value, filled in for this customer, can’t be encoded in its format (for example an emoji in a Code 128 barcode), so this pass’s barcode holds its serial instead of no code at all (set on every read). valid_until_capped: a trial pass (every pass a test key issues, and live-key passes before your business goes live) is never valid past its expiry, so a later values.validUntil was replaced by the expiry date; the message says which date the pass shows (set on the response to POST /v1/passes and PATCH /v1/passes/{id} that sent it, empty on later reads).
savedobjectapple: the customer’s link to the .pkpass file was downloaded (appleDownloadedAt), which is not the same as the card being on a phone: a download can be cancelled, and your own scripts count. For “is it on a phone”, read onDevice. google: the customer saved it to Google Wallet.
applebooleangooglebooleanonDeviceobjectWhether the card is on a phone. apple: at least one iPhone has registered the pass with Apple Wallet to get updates (false until the customer adds it, and again if every device removes it). google: the customer saved it to Google Wallet, the same as saved.google.
applebooleangooglebooleanurlstringThe customer’s own card page. Works on any phone.
appleUrlstringgoogleUrlstringcreatedAtstringupdatedAtstring- 400invalid_json
The body isn’t valid JSON.
- 401unauthorized
The API key is missing, wrong or revoked.
- 404not_found
Nothing with that ID in this business.
- 409conflict
The request conflicts with the current state, for example the card is a draft.
- 413error
The request body is larger than 64 KB.
- 422invalid_request
A value isn’t valid.
paramsays which. - 429rate_limited
Too many requests. Wait for
Retry-Afterseconds.
Redeem the reward
Records that the customer got their reward. On stamp cards this empties the card so they can start again; a completed round starting over is billed as one card, like issuing one, unless the pass is a trial or test pass. Only a full stamp card can be redeemed (409 reward_not_ready before that), and a pass can start a new round once every 10 minutes (409 renewal_too_soon). A coupon can be redeemed once: redeeming it again is a 409 already_used.
idstring, in pathRequiredThe ID.
Idempotency-KeyheaderOptionalAny unique string up to 255 characters. The same key within 24 hours, from any key of your business, replays the first response. Responses over 16 KB aren’t remembered.
curl -X POST https://korti.is/v1/passes/PASS_ID/redeem \
-H "Authorization: Bearer $KORTI_KEY"Returns 200: The updated pass.
idstringobjectenumAlways the same, so you can tell objects apart.
passcardstringserialstringPrinted on the card and encoded in its barcode.
statusenumactivevoidedtrialbooleanIssued on Korti’s trial certificate. Trial passes expire.
testbooleanIssued with a test key. Test passes are always trial passes, and only test keys can reach them.
expiresAtstring, nullablecustomerobjectWho the pass is for.
namestringemailstringphonestringvaluesobjectstampsintegerpointsintegervisitsLeftintegerbalancenumbermemberNumberstringmemberSincestringvalidUntilstringseatstringcustomobject of stringsrewardReadybooleanStamp cards: the card is full and the reward can be given.
warningsarray of objectThings that didn’t go as designed. barcode_fallback: the card’s barcode value, filled in for this customer, can’t be encoded in its format (for example an emoji in a Code 128 barcode), so this pass’s barcode holds its serial instead of no code at all (set on every read). valid_until_capped: a trial pass (every pass a test key issues, and live-key passes before your business goes live) is never valid past its expiry, so a later values.validUntil was replaced by the expiry date; the message says which date the pass shows (set on the response to POST /v1/passes and PATCH /v1/passes/{id} that sent it, empty on later reads).
savedobjectapple: the customer’s link to the .pkpass file was downloaded (appleDownloadedAt), which is not the same as the card being on a phone: a download can be cancelled, and your own scripts count. For “is it on a phone”, read onDevice. google: the customer saved it to Google Wallet.
applebooleangooglebooleanonDeviceobjectWhether the card is on a phone. apple: at least one iPhone has registered the pass with Apple Wallet to get updates (false until the customer adds it, and again if every device removes it). google: the customer saved it to Google Wallet, the same as saved.google.
applebooleangooglebooleanurlstringThe customer’s own card page. Works on any phone.
appleUrlstringgoogleUrlstringcreatedAtstringupdatedAtstring- 401unauthorized
The API key is missing, wrong or revoked.
- 404not_found
Nothing with that ID in this business.
- 409conflict
The request conflicts with the current state, for example the card is a draft.
- 429rate_limited
Too many requests. Wait for
Retry-Afterseconds.
Void a pass
Stops the pass working. Phones that saved it show it as no longer valid. This can’t be undone. Voiding twice is fine.
idstring, in pathRequiredThe ID.
Idempotency-KeyheaderOptionalAny unique string up to 255 characters. The same key within 24 hours, from any key of your business, replays the first response. Responses over 16 KB aren’t remembered.
curl -X POST https://korti.is/v1/passes/PASS_ID/void \
-H "Authorization: Bearer $KORTI_KEY"Returns 200: The voided pass.
idstringobjectenumAlways the same, so you can tell objects apart.
passcardstringserialstringPrinted on the card and encoded in its barcode.
statusenumactivevoidedtrialbooleanIssued on Korti’s trial certificate. Trial passes expire.
testbooleanIssued with a test key. Test passes are always trial passes, and only test keys can reach them.
expiresAtstring, nullablecustomerobjectWho the pass is for.
namestringemailstringphonestringvaluesobjectstampsintegerpointsintegervisitsLeftintegerbalancenumbermemberNumberstringmemberSincestringvalidUntilstringseatstringcustomobject of stringsrewardReadybooleanStamp cards: the card is full and the reward can be given.
warningsarray of objectThings that didn’t go as designed. barcode_fallback: the card’s barcode value, filled in for this customer, can’t be encoded in its format (for example an emoji in a Code 128 barcode), so this pass’s barcode holds its serial instead of no code at all (set on every read). valid_until_capped: a trial pass (every pass a test key issues, and live-key passes before your business goes live) is never valid past its expiry, so a later values.validUntil was replaced by the expiry date; the message says which date the pass shows (set on the response to POST /v1/passes and PATCH /v1/passes/{id} that sent it, empty on later reads).
savedobjectapple: the customer’s link to the .pkpass file was downloaded (appleDownloadedAt), which is not the same as the card being on a phone: a download can be cancelled, and your own scripts count. For “is it on a phone”, read onDevice. google: the customer saved it to Google Wallet.
applebooleangooglebooleanonDeviceobjectWhether the card is on a phone. apple: at least one iPhone has registered the pass with Apple Wallet to get updates (false until the customer adds it, and again if every device removes it). google: the customer saved it to Google Wallet, the same as saved.google.
applebooleangooglebooleanurlstringThe customer’s own card page. Works on any phone.
appleUrlstringgoogleUrlstringcreatedAtstringupdatedAtstring- 401unauthorized
The API key is missing, wrong or revoked.
- 404not_found
Nothing with that ID in this business.
- 429rate_limited
Too many requests. Wait for
Retry-Afterseconds.
Events
List events
What happened to your passes, oldest first, in the same shape webhooks use. A test key sees only events for the passes test keys issued. Poll with since set to the last next you got. Without since you get the most recent events.
sincestring, in queryOptionalOnly events after this one.
limitinteger, in queryOptional1 to 100. Defaults to 20.
curl https://korti.is/v1/events \
-H "Authorization: Bearer $KORTI_KEY"Returns 200: Events, oldest first.
objectenumAlways the same, so you can tell objects apart.
listdataarray of objectThe items.
nextstring, nullablePass this as since next time.
hasMoreboolean- 401unauthorized
The API key is missing, wrong or revoked.
- 422invalid_request
A value isn’t valid.
paramsays which. - 429rate_limited
Too many requests. Wait for
Retry-Afterseconds.