Skip to main content
A redemption takes one voucher from a voucher set in your catalog and hands it to you as a code or a link. The platform allocates vouchers first-expiring-first and never issues the same single-use voucher twice, also under heavy concurrency. Redeeming needs the permission create-consumer-redemptions (API keys can hold it); reading redemptions needs view-consumer-redemptions.

Redeem a voucher

Send POST /consumer/v1/redemptions with an Idempotency-Key:
The response is 201 Created, sent only after the redemption is committed, with a Location header pointing at the new redemption:
A voucher set is redeemable when it is visible in your catalog, its availability is active or deactivation-scheduled, both Catalog Toggles are on, you have accepted its current Price Terms and it has stock.

Choosing a set or a provider

Name exactly one target:
  • voucherSetId: redeem from this voucher set. Use it when your customer picked a specific offer.
  • providerId: let the platform pick the provider’s best redeemable set. Candidates are the provider’s visible, switched-on sets in your effective position order (unset positions last), then by activation time. Sets without a redeemable Price Acceptance are skipped; a set that is depleted or whose entity limit is reached is skipped and the next one is tried.
Sending both, or neither, answers 400 data-failed-validation with the constraint mutually-exclusive or required. In providerId mode, when every candidate is depleted you get 409 provider-depleted; when every candidate was skipped for its entity limit, 409 entity-limit-reached.

Attaching a redemption entity

A Redemption Entity is your record of who redeems: an end customer, an employee or a device, identified by your own opaque refId. Attach one in either of two ways (at most one per request):
  • redemptionEntityId: an existing entity of yours.
  • redemptionEntity: { "refId": "customer:42", "displayName": "…", "metadata": {} }. The platform finds the entity with this refId or creates it in the same transaction. metadata, when sent and different, updates the entity.
Attaching an entity enables per-entity limits: a voucher set’s setting.entityLimit (for example {"max": 1, "period": "calendar-month"}) caps how often one entity can redeem that set; the next attempt answers 409 entity-limit-reached. A blocked entity answers 409 redemption-entity-blocked, an erased one 409 redemption-entity-erased. You can also send your own metadata (a JSON object up to 16 KiB). It is stored on the redemption and included in the redemption-created webhook. Never put personal data in refId, metadata or the Idempotency-Key: redemptions are kept for accounting after an entity is erased.

Batch redemptions

POST /consumer/v1/redemptions:batch redeems up to 10 vouchers in one all-or-nothing request, for example a welcome bonus of three ride credits:
  • items holds 1-10 items, each with voucherSetId or providerId and a quantity from 1 to 10. The sum of all quantities must not exceed 10, else 422 batch-too-large.
  • The entity and metadata apply to every redemption of the batch.
  • The 201 response is a redemption-batch whose items are full redemptions in request order; an item with quantity: 2 becomes two consecutive redemptions. Read it again with GET /consumer/v1/redemption-batches/{redemptionBatchId}.
  • If any item fails, nothing is redeemed. The error names the failing item in more.validationErrors with the property items[<index>].
  • Every redemption of the batch stores the batch’s Idempotency-Key, so GET /consumer/v1/redemptions?filter[idempotencyKey]=<key> returns the whole batch.
Each item needs quantity distinct vouchers. A multi-use voucher (one shared code) counts once per batch, so quantity: 2 on a set whose only stock is one shared code fails with 409 voucher-set-depleted and nothing is redeemed. For such sets send quantity: 1, or one batch per voucher. stockStatus: available never promises more than one voucher.

What you receive

  • issued: kind is code or link. For code sets, code holds the voucher code and link the link rendered from the set’s Link Template (or null when the set has no Link Template); for link sets, link holds the link. Show it only to the entitled customer.
  • validFrom / validUntil: when the voucher can be used at the provider. Allocation only picks vouchers that are still valid.
  • voucherSet: the set’s name and provider name as they were at redemption time, so historical redemptions stay readable after a set is renamed or ends.
  • redemptionEntity, metadata, actor, idempotencyKey and redeemedAt.
Issued codes are not show-once. You can read them again at any time with GET /consumer/v1/redemptions/{redemptionId} or list redemptions, for example filtered by redemptionEntity.refId or redeemedAt. Files downloaded from the dashboard show them masked. You also receive the webhook redemption-created with the same representation. The provider receives its own reduced projection that contains no consumer data, entity, metadata or issued value.

Errors

Errors use the standard error body; branch on errorCode:
The first failing check answers; nothing is redeemed. The checks run in this order: set, redeemability, price, entity, entity limit, stock. A suspended partner gets 403 partner-suspended. See Errors for the common codes and the retry table.

Best practices

  • Always send an Idempotency-Key and reuse it for every retry of the same intent, for example order-8812:line-1. A retry after a timeout then replays the original 201 with the identical issued object instead of redeeming twice. See Idempotency.
  • A stored 409 is final for its key. After voucher-set-depleted or price-acceptance-required, a retry with the same key replays the 409 even if stock was added or prices were accepted. Use a new key for a new attempt.
  • Retry only transient failures with the same key: network errors, 409 idempotency-key-in-use, 409 concurrent-update and 5xx.
  • Reconcile instead of guessing. If you lost track of an intent, GET /consumer/v1/redemptions?filter[idempotencyKey]=<key>: a non-empty page means it ran.
  • Treat issued codes as secrets. Show them only to the customer they belong to, never log them, and keep them out of analytics tools.
  • Keep your catalog fresh with the catalog-* webhooks and hide entries whose priceAcceptance.status is not redeemable.
  • Sync your ledger incrementally with filter[redeemedAt][gte]=<last seen minus 60 seconds>&sort=redeemedAt and de-duplicate by id.