KortiDocs

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.

Header
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

GET/v1/cardshttps://korti.is

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.
objectenum

Always the same, so you can tell objects apart.

list
dataarray of object

The items.

  • 401unauthorized

    The API key is missing, wrong or revoked.

  • 429rate_limited

    Too many requests. Wait for Retry-After seconds.

Get a card

GET/v1/cards/{id}https://korti.is

A published card and the variables you can set when you issue a pass from it.

idstring, in pathRequired

The ID.

curl https://korti.is/v1/cards/CARD_ID \
  -H "Authorization: Bearer $KORTI_KEY"
Returns 200: The card.
idstring

objectenum

Always the same, so you can tell objects apart.

card
namestring

typeenum

stamppunchpointsmembershipgiftcouponevent
versioninteger

Published version that new passes use.

shareUrlstring

Public sign-up link.

variablesarray of object

createdAtstring

updatedAtstring

  • 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-After seconds.

Passes

List passes

GET/v1/passeshttps://korti.is

Passes in your business, newest first. A test key lists only the passes test keys issued.

cardstring, in queryOptional

Only passes for this card ID.

qstring, in queryOptional

Search name, email or serial.

limitinteger, in queryOptional

1 to 100. Defaults to 20.

curl https://korti.is/v1/passes \
  -H "Authorization: Bearer $KORTI_KEY"
Returns 200: Passes, newest first.
objectenum

Always the same, so you can tell objects apart.

list
dataarray of object

The 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. param says which.

  • 429rate_limited

    Too many requests. Wait for Retry-After seconds.

Issue a pass

POST/v1/passeshttps://korti.is

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-KeyheaderOptional

Any 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

cardstringRequired

ID of a published card. See GET /v1/cards.

customerobjectOptional

Who the pass is for.

namestringOptional

Up to 60 characters.

emailstring or enumOptional

phonestringOptional

Up to 30 characters.

valuesobjectOptional

Values 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.

stampsintegerOptional

At least 0. At most 1000000000.

pointsintegerOptional

At least 0. At most 1000000000.

visitsLeftintegerOptional

At least 0. At most 1000000000.

balancenumberOptional

At least 0. At most 1000000000.

memberNumberstringOptional

The built-in membership number. A holder detail you added yourself is a custom value. Up to 40 characters.

memberSincestringOptional

Up to 40 characters.

validUntilstringOptional

When 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.

seatstringOptional

Up to 40 characters.

customobject of stringsOptional

sendEmailbooleanOptional

Email 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.
idstring

objectenum

Always the same, so you can tell objects apart.

pass
cardstring

serialstring

Printed on the card and encoded in its barcode.

statusenum

activevoided
trialboolean

Issued on Korti’s trial certificate. Trial passes expire.

testboolean

Issued with a test key. Test passes are always trial passes, and only test keys can reach them.

expiresAtstring, nullable

customerobject

Who the pass is for.

namestring

emailstring

phonestring

valuesobject

stampsinteger

pointsinteger

visitsLeftinteger

balancenumber

memberNumberstring

memberSincestring

validUntilstring

seatstring

customobject of strings

rewardReadyboolean

Stamp cards: the card is full and the reward can be given.

warningsarray of object

Things 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).

savedobject

apple: 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.

appleboolean

googleboolean

onDeviceobject

Whether 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.

appleboolean

googleboolean

urlstring

The customer’s own card page. Works on any phone.

appleUrlstring

googleUrlstring

createdAtstring

updatedAtstring

  • 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. param says which.

  • 429rate_limited

    Too many requests. Wait for Retry-After seconds.

Get a pass

GET/v1/passes/{id}https://korti.is

A test key gets a 404 for passes a live key issued.

idstring, in pathRequired

The ID.

curl https://korti.is/v1/passes/PASS_ID \
  -H "Authorization: Bearer $KORTI_KEY"
Returns 200: The pass.
idstring

objectenum

Always the same, so you can tell objects apart.

pass
cardstring

serialstring

Printed on the card and encoded in its barcode.

statusenum

activevoided
trialboolean

Issued on Korti’s trial certificate. Trial passes expire.

testboolean

Issued with a test key. Test passes are always trial passes, and only test keys can reach them.

expiresAtstring, nullable

customerobject

Who the pass is for.

namestring

emailstring

phonestring

valuesobject

stampsinteger

pointsinteger

visitsLeftinteger

balancenumber

memberNumberstring

memberSincestring

validUntilstring

seatstring

customobject of strings

rewardReadyboolean

Stamp cards: the card is full and the reward can be given.

warningsarray of object

Things 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).

savedobject

apple: 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.

appleboolean

googleboolean

onDeviceobject

Whether 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.

appleboolean

googleboolean

urlstring

The customer’s own card page. Works on any phone.

appleUrlstring

googleUrlstring

createdAtstring

updatedAtstring

  • 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-After seconds.

Update a pass

PATCH/v1/passes/{id}https://korti.is

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 pathRequired

The ID.

Idempotency-KeyheaderOptional

Any 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

customerobjectOptional

Who the pass is for.

namestringOptional

Up to 60 characters.

emailstring or enumOptional

valuesobjectOptional

Values 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.

stampsintegerOptional

At least 0. At most 1000000000.

pointsintegerOptional

At least 0. At most 1000000000.

visitsLeftintegerOptional

At least 0. At most 1000000000.

balancenumberOptional

At least 0. At most 1000000000.

memberNumberstringOptional

The built-in membership number. A holder detail you added yourself is a custom value. Up to 40 characters.

memberSincestringOptional

Up to 40 characters.

validUntilstringOptional

When 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.

seatstringOptional

Up to 40 characters.

customobject of stringsOptional

curl -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.
idstring

objectenum

Always the same, so you can tell objects apart.

pass
cardstring

serialstring

Printed on the card and encoded in its barcode.

statusenum

activevoided
trialboolean

Issued on Korti’s trial certificate. Trial passes expire.

testboolean

Issued with a test key. Test passes are always trial passes, and only test keys can reach them.

expiresAtstring, nullable

customerobject

Who the pass is for.

namestring

emailstring

phonestring

valuesobject

stampsinteger

pointsinteger

visitsLeftinteger

balancenumber

memberNumberstring

memberSincestring

validUntilstring

seatstring

customobject of strings

rewardReadyboolean

Stamp cards: the card is full and the reward can be given.

warningsarray of object

Things 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).

savedobject

apple: 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.

appleboolean

googleboolean

onDeviceobject

Whether 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.

appleboolean

googleboolean

urlstring

The customer’s own card page. Works on any phone.

appleUrlstring

googleUrlstring

createdAtstring

updatedAtstring

  • 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. param says which.

  • 429rate_limited

    Too many requests. Wait for Retry-After seconds.

Add stamps

POST/v1/passes/{id}/stampshttps://korti.is

Stamp cards only. Adds stamps up to the card’s total. When rewardReady is true, redeem the reward to start over.

idstring, in pathRequired

The ID.

Idempotency-KeyheaderOptional

Any 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

countintegerOptional

Defaults 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.
idstring

objectenum

Always the same, so you can tell objects apart.

pass
cardstring

serialstring

Printed on the card and encoded in its barcode.

statusenum

activevoided
trialboolean

Issued on Korti’s trial certificate. Trial passes expire.

testboolean

Issued with a test key. Test passes are always trial passes, and only test keys can reach them.

expiresAtstring, nullable

customerobject

Who the pass is for.

namestring

emailstring

phonestring

valuesobject

stampsinteger

pointsinteger

visitsLeftinteger

balancenumber

memberNumberstring

memberSincestring

validUntilstring

seatstring

customobject of strings

rewardReadyboolean

Stamp cards: the card is full and the reward can be given.

warningsarray of object

Things 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).

savedobject

apple: 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.

appleboolean

googleboolean

onDeviceobject

Whether 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.

appleboolean

googleboolean

urlstring

The customer’s own card page. Works on any phone.

appleUrlstring

googleUrlstring

createdAtstring

updatedAtstring

  • 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. param says which.

  • 429rate_limited

    Too many requests. Wait for Retry-After seconds.

Punch one visit

POST/v1/passes/{id}/punchhttps://korti.is

Klippikort (prepaid punch cards) only. Uses one visit. Fails with 409 card_empty when none are left.

idstring, in pathRequired

The ID.

Idempotency-KeyheaderOptional

Any 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.
idstring

objectenum

Always the same, so you can tell objects apart.

pass
cardstring

serialstring

Printed on the card and encoded in its barcode.

statusenum

activevoided
trialboolean

Issued on Korti’s trial certificate. Trial passes expire.

testboolean

Issued with a test key. Test passes are always trial passes, and only test keys can reach them.

expiresAtstring, nullable

customerobject

Who the pass is for.

namestring

emailstring

phonestring

valuesobject

stampsinteger

pointsinteger

visitsLeftinteger

balancenumber

memberNumberstring

memberSincestring

validUntilstring

seatstring

customobject of strings

rewardReadyboolean

Stamp cards: the card is full and the reward can be given.

warningsarray of object

Things 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).

savedobject

apple: 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.

appleboolean

googleboolean

onDeviceobject

Whether 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.

appleboolean

googleboolean

urlstring

The customer’s own card page. Works on any phone.

appleUrlstring

googleUrlstring

createdAtstring

updatedAtstring

  • 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. param says which.

  • 429rate_limited

    Too many requests. Wait for Retry-After seconds.

Refill a klippikort

POST/v1/passes/{id}/refillhttps://korti.is

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 pathRequired

The ID.

Idempotency-KeyheaderOptional

Any 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

visitsintegerOptional

Visits 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.
idstring

objectenum

Always the same, so you can tell objects apart.

pass
cardstring

serialstring

Printed on the card and encoded in its barcode.

statusenum

activevoided
trialboolean

Issued on Korti’s trial certificate. Trial passes expire.

testboolean

Issued with a test key. Test passes are always trial passes, and only test keys can reach them.

expiresAtstring, nullable

customerobject

Who the pass is for.

namestring

emailstring

phonestring

valuesobject

stampsinteger

pointsinteger

visitsLeftinteger

balancenumber

memberNumberstring

memberSincestring

validUntilstring

seatstring

customobject of strings

rewardReadyboolean

Stamp cards: the card is full and the reward can be given.

warningsarray of object

Things 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).

savedobject

apple: 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.

appleboolean

googleboolean

onDeviceobject

Whether 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.

appleboolean

googleboolean

urlstring

The customer’s own card page. Works on any phone.

appleUrlstring

googleUrlstring

createdAtstring

updatedAtstring

  • 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. param says which.

  • 429rate_limited

    Too many requests. Wait for Retry-After seconds.

Add or remove points

POST/v1/passes/{id}/pointshttps://korti.is

Points cards only. A negative delta takes points away. Points never go below 0.

idstring, in pathRequired

The ID.

Idempotency-KeyheaderOptional

Any 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

deltanumberRequired

curl -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.
idstring

objectenum

Always the same, so you can tell objects apart.

pass
cardstring

serialstring

Printed on the card and encoded in its barcode.

statusenum

activevoided
trialboolean

Issued on Korti’s trial certificate. Trial passes expire.

testboolean

Issued with a test key. Test passes are always trial passes, and only test keys can reach them.

expiresAtstring, nullable

customerobject

Who the pass is for.

namestring

emailstring

phonestring

valuesobject

stampsinteger

pointsinteger

visitsLeftinteger

balancenumber

memberNumberstring

memberSincestring

validUntilstring

seatstring

customobject of strings

rewardReadyboolean

Stamp cards: the card is full and the reward can be given.

warningsarray of object

Things 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).

savedobject

apple: 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.

appleboolean

googleboolean

onDeviceobject

Whether 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.

appleboolean

googleboolean

urlstring

The customer’s own card page. Works on any phone.

appleUrlstring

googleUrlstring

createdAtstring

updatedAtstring

  • 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. param says which.

  • 429rate_limited

    Too many requests. Wait for Retry-After seconds.

Top up or spend a balance

POST/v1/passes/{id}/balancehttps://korti.is

Gift cards only. A negative delta spends from the balance, which can’t go below 0.

idstring, in pathRequired

The ID.

Idempotency-KeyheaderOptional

Any 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

deltanumberRequired

curl -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.
idstring

objectenum

Always the same, so you can tell objects apart.

pass
cardstring

serialstring

Printed on the card and encoded in its barcode.

statusenum

activevoided
trialboolean

Issued on Korti’s trial certificate. Trial passes expire.

testboolean

Issued with a test key. Test passes are always trial passes, and only test keys can reach them.

expiresAtstring, nullable

customerobject

Who the pass is for.

namestring

emailstring

phonestring

valuesobject

stampsinteger

pointsinteger

visitsLeftinteger

balancenumber

memberNumberstring

memberSincestring

validUntilstring

seatstring

customobject of strings

rewardReadyboolean

Stamp cards: the card is full and the reward can be given.

warningsarray of object

Things 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).

savedobject

apple: 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.

appleboolean

googleboolean

onDeviceobject

Whether 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.

appleboolean

googleboolean

urlstring

The customer’s own card page. Works on any phone.

appleUrlstring

googleUrlstring

createdAtstring

updatedAtstring

  • 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. param says which.

  • 429rate_limited

    Too many requests. Wait for Retry-After seconds.

Redeem the reward

POST/v1/passes/{id}/redeemhttps://korti.is

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 pathRequired

The ID.

Idempotency-KeyheaderOptional

Any 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.
idstring

objectenum

Always the same, so you can tell objects apart.

pass
cardstring

serialstring

Printed on the card and encoded in its barcode.

statusenum

activevoided
trialboolean

Issued on Korti’s trial certificate. Trial passes expire.

testboolean

Issued with a test key. Test passes are always trial passes, and only test keys can reach them.

expiresAtstring, nullable

customerobject

Who the pass is for.

namestring

emailstring

phonestring

valuesobject

stampsinteger

pointsinteger

visitsLeftinteger

balancenumber

memberNumberstring

memberSincestring

validUntilstring

seatstring

customobject of strings

rewardReadyboolean

Stamp cards: the card is full and the reward can be given.

warningsarray of object

Things 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).

savedobject

apple: 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.

appleboolean

googleboolean

onDeviceobject

Whether 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.

appleboolean

googleboolean

urlstring

The customer’s own card page. Works on any phone.

appleUrlstring

googleUrlstring

createdAtstring

updatedAtstring

  • 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-After seconds.

Void a pass

POST/v1/passes/{id}/voidhttps://korti.is

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 pathRequired

The ID.

Idempotency-KeyheaderOptional

Any 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.
idstring

objectenum

Always the same, so you can tell objects apart.

pass
cardstring

serialstring

Printed on the card and encoded in its barcode.

statusenum

activevoided
trialboolean

Issued on Korti’s trial certificate. Trial passes expire.

testboolean

Issued with a test key. Test passes are always trial passes, and only test keys can reach them.

expiresAtstring, nullable

customerobject

Who the pass is for.

namestring

emailstring

phonestring

valuesobject

stampsinteger

pointsinteger

visitsLeftinteger

balancenumber

memberNumberstring

memberSincestring

validUntilstring

seatstring

customobject of strings

rewardReadyboolean

Stamp cards: the card is full and the reward can be given.

warningsarray of object

Things 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).

savedobject

apple: 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.

appleboolean

googleboolean

onDeviceobject

Whether 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.

appleboolean

googleboolean

urlstring

The customer’s own card page. Works on any phone.

appleUrlstring

googleUrlstring

createdAtstring

updatedAtstring

  • 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-After seconds.

Events

List events

GET/v1/eventshttps://korti.is

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 queryOptional

Only events after this one.

limitinteger, in queryOptional

1 to 100. Defaults to 20.

curl https://korti.is/v1/events \
  -H "Authorization: Bearer $KORTI_KEY"
Returns 200: Events, oldest first.
objectenum

Always the same, so you can tell objects apart.

list
dataarray of object

The items.

nextstring, nullable

Pass this as since next time.

hasMoreboolean

  • 401unauthorized

    The API key is missing, wrong or revoked.

  • 422invalid_request

    A value isn’t valid. param says which.

  • 429rate_limited

    Too many requests. Wait for Retry-After seconds.