Vouchers
A voucher is one redeemable item of a set: a code (voucherKind: code) or a link (voucherKind: link).
Voucher
status: available, exhausted (all redemptions used), expired (past validUntil) or revoked. Links are checked against the set’s current content: the live revision, or the draft or pending content if the set was never approved.
You can add vouchers in every status except suspended and archived; no change request is needed. New vouchers are redeemable once the set is active. Stock figures update within about two minutes.
Upload a file
For more than 1,000 vouchers, upload a CSV or XLSX file. The file goes directly to storage, never through the API:1
Create the upload
status: pending-upload and an uploadTarget (url, method, headers, expiresAt), valid for 1 hour.2
PUT the file to the upload target
uploadTarget (text/csv, or application/vnd.openxmlformats-officedocument.spreadsheetml.sheet for XLSX).3
Start processing
Location and Retry-After: 2. A missing file → 409 upload-file-missing; a size that differs from sizeBytes → 422 upload-size-mismatch.4
Wait for the result
Poll
Location (start after 2 seconds, double up to 30 seconds) or wait for the voucher-upload-completed / voucher-upload-failed webhook. You also get an email.voucher-upload-limit-reached). An upload not started within 1 hour is cancelled with failureReason: upload-expired. Cancel an upload in pending-upload or validated with :cancel.
File format
- CSV: UTF-8 (a BOM is allowed), comma or semicolon separator (detected from the header), RFC 4180 quoting, LF or CRLF line ends.
- XLSX: the first worksheet only; strings, numbers and date cells (read as UTC).
- At most 100 MiB and 1,000,000 data rows.
- A header row is required. Column names are case-insensitive:
value(required),redemptionType,maxRedemptions,validFrom,validUntil,metadata(a JSON object as text). - An empty cell takes the upload’s
defaults. InmaxRedemptions, the wordunlimitedmeans unlimited, even when the defaults set a maximum.
value column fails with failureReason: missing-value-column. An unknown column fails the whole upload with unknown-column before any row is checked, so a misspelt validUntill never silently drops data. A row with more or fewer cells than the header is invalid (column-count-mismatch).
Validation and import
Processing has two phases:- Validation. The file’s SHA-256 is checked (
checksum-mismatchfails the upload), then every row is validated before any voucher is written. - Import. With no invalid rows, the import starts automatically. With invalid rows, the upload stops in
validated: inspect the errors, then confirm with:importand{"skipInvalidRows": true}to import only the valid rows, or:cancel. Avalidatedupload left for 7 days is cancelled (validation-expired).
{rowNumber, column, code} (never the value); up to 10,000 are stored. Codes: value-missing, value-invalid, link-host-not-allowed, scheme-not-allowed, redemption-type-invalid, max-redemptions-invalid, max-redemptions-not-allowed-for-single, max-redemptions-too-small, validity-window-invalid, date-invalid, metadata-invalid, column-count-mismatch.
Duplicates are not errors. A value repeated in the file (duplicate-in-file) or already in the set (value-exists) is a valid row that is skipped and counted in duplicateRows; it appears in the row list but never stops the upload. Uploading the same file twice imports nothing the second time.
counts follows: totalRows = validRows + invalidRows, and when completed importedRows = validRows − duplicateRows. Imports run in chunks of 5,000 rows and resume after interruptions without duplicates. A row whose validUntil passed between validation and import is skipped as validity-window-invalid. If AllRide suspends or you archive the set during an import, the upload fails with voucher-set-unavailable; chunks already imported stay.
Batch API
Create up to 1,000 vouchers synchronously, all or nothing:- 201 with
{createdCount, items}: compact items (id,valueMask,redemptionType,maxRedemptions,status) in request order. - Any invalid item → 400
data-failed-validationwith one entry per problem (vouchers[17].value); nothing is created. - A value already in the set → 409
voucher-value-exists, naming each item; a value twice in the request →duplicate-value. Nothing is created. - More than 1,000 items → 422
batch-too-large. - Send an
Idempotency-Key: a retry then replays the result and never duplicates vouchers.
Revoking vouchers
Revoke vouchers that must never be redeemed (for example leaked codes):- Only
availablevouchers can be revoked; others → 409voucher-not-revocable. Up to 1,000 ids, all or nothing. - One voucher:
POST /provider/v1/vouchers/{voucherId}:revokewith{"reason": …}. - Revoked vouchers are never redeemable and never deleted; past redemptions stay.
Viewing voucher values
List and get responses always show masked values (valueMask: the first 2 and last 2 characters of a code, scheme and host of a link), for every principal. Dashboard downloads (CSV / Excel) contain the same masked values.
The clear value of one voucher comes only from the reveal operation (reveal-provider-vouchers, delegable; dashboard users need a sign-in within the last 15 minutes):
- One voucher per call; there is no bulk reveal.
- Every reveal is recorded in your audit log as
voucher.revealed(never with the value) and monitored by AllRide. - An idempotent replay returns
"value": nullwithIdempotent-Replay-Redacted: true. - To find a voucher by its value, use
searchon the vouchers list: an exact match on the full value, available only to principals withreveal-provider-vouchers; results stay masked.