Skip to content
Documentation menu

Vouchereto API · v1

Idempotency, errors, limits

The rules every endpoint follows. Read this before you write retry logic.

Idempotency

Every POST needs an Idempotency-Key header. Use a value that identifies the operation on your side, such as order-3141-reserve, and send the same value when you retry after a timeout or a 5xx.

Idempotency outcomes
You sendYou get
A new keyThe request runs normally.
The same key and the same body (a retry)The original status and body, with the header Idempotent-Replayed: true. Nothing runs twice.
The same key with a different body409 IDEMPOTENCY_CONFLICT
The same key while the first request is still running409 IDEMPOTENCY_IN_PROGRESS: retry shortly
No key on a POST400 IDEMPOTENCY_KEY_REQUIRED

Keys are scoped to your merchant and mode. Responses to keys are kept, so a retry days later still returns the first result; use a new key for a new operation.

Safe retry policy

  • Retry on network errors, timeouts, 5xx, 409 IDEMPOTENCY_IN_PROGRESS and 429, with the same idempotency key, exponential backoff and jitter (for example 1 s, 2 s, 4 s, then give up and reconcile).
  • On 429, wait at least Retry-After seconds.
  • Do not retry other 4xx: fix the request or tell the customer.
  • When unsure whether a capture went through, GET /v1/redemptions/{id} tells you.

Errors

Errors use RFC 7807/9457 problem details. Branch on code (stable), show your own message to the customer, and log request_id: with it, support finds your exact call.

problem response
HTTP/1.1 409 Conflict
Content-Type: application/problem+json

{
  "type": "https://www.vouchereto.com/docs/errors/voucher_already_redeemed",
  "title": "voucher already redeemed",
  "status": 409,
  "code": "VOUCHER_ALREADY_REDEEMED",
  "request_id": "req_8f2c41d09a7b4e11"
}

Status families: 400 invalid request · 401 authentication · 403 not allowed in this mode or account state · 404 not found · 409 conflicting state · 422 valid request a business rule rejects · 429 slow down · 500 our side (retry with the same idempotency key). Every code, what it means and what to do.

Rate limits

Rate limits
ScopeLimit
POST /v1/redemptions120 requests / minute / key
POST /v1/checkout-sessions300 requests / minute / key
Every other endpoint600 requests / minute / key
Failed authentications30 / minute / IP, then 60 s of 429
Invalid voucher codes5 per customer (customer_ref) per 15 min, 20 per customer IP, 500 per merchant; blocks start at 5 minutes and double up to 24 hours (429 TOO_MANY_INVALID_ATTEMPTS)

Need more throughput? Tell us your expected peak.

Pagination

List endpoints return data and pagination. Pass limit (1–100, default 20) and, for the next page, cursor = the previous next_cursor. Results are newest first and stable while you page.

cursor pagination
GET /v1/redemptions?status=captured&limit=2

{
  "data": [ { "id": "f4e8…", "object": "redemption", … }, { "id": "2b91…", … } ],
  "pagination": { "has_more": true, "next_cursor": "eyJ0IjoiMjAyNi0xMC0yMlQxNzoyMjo1NS45MTVaIiwiaSI6IjJiOTEuLi4ifQ" }
}

GET /v1/redemptions?status=captured&limit=2&cursor=eyJ0Ijoi…

Formats

  • Amounts are integers in the currency's minor unit: 5000 USD = $50.00; JPY and KRW have no decimals, so 1000 JPY = ¥1,000.
  • Currencies are ISO 4217 upper-case codes; your account accepts a configured set (USD by default).
  • Timestamps are ISO 8601 in UTC, for example 2026-10-22T17:22:56.118Z.
  • IDs are UUIDs. Every object has an object field (redemption, checkout_session…) and livemode.
  • customer_ref is your id for the customer (max 128 chars). Do not put emails or names in it.
  • Request bodies are strict: unknown fields return 400 VALIDATION_ERROR. Responses may gain new fields at any time; ignore what you do not know.
  • Request bodies are limited to 64 KB.