Skip to main content
Buy packs and Buy a card spend your balance, so each one requires an Idempotency-Key header: your own id for the order. We record it before anything is charged, and from then on that order is charged at most once, however many times you send it.
Generate one order id per order and reuse it on every attempt of that order. A new id is a new order: a second set of packs, or a second card.

The order id

  • Header: Idempotency-Key. Through the MCP server, the buy_packs and buy_card tools take it as order_id.
  • Format: 8–128 characters of A-Z, a-z, 0-9, _ and -. A UUID works. A missing header is a 400 ("Idempotency-Key header is required"), and so is one in the wrong format.
  • Scope: unique per CatchBack account, across pack and card orders together. Every API key linked to the same account shares the same ids, and an id used for a pack order can’t be reused for a card order (422 IDEMPOTENCY_KEY_REUSED).
  • Lifetime: an id doesn’t expire. A finished order keeps returning its original response to that id.

What a retry returns

Only a new order is checked against your rate limits: a replay or an in-progress answer never counts against them, so you can always find out what your first attempt did.
409 IDEMPOTENCY_IN_PROGRESS

What counts as the same order

A retry must send the same body as the first attempt. We compare the fields that define the order, after filling in their defaults, so leaving out a default and sending it explicitly are the same order: Anything else is a different order, and reusing the id for it is a 422.

Timeouts and interrupted orders

A purchase can take up to 60 seconds, so set your client’s timeout above that. If a request times out or the connection drops, you can’t tell whether it went through: resend the same order id. You get the finished order, 409 IDEMPOTENCY_IN_PROGRESS while it is still running, or 500 PAYMENT_OUTCOME_UNKNOWN if the order runs on this attempt and we can’t confirm its charge. If a request is cut off on our side after the charge (a timeout, a crash, a deploy), the order stays in progress until we close it from our own records. We check every 5 minutes for orders that have been running for more than 5, so it usually takes about 10 minutes. From then on, your resend returns a shorter body than the original, marked "reconciled": true:
A reconciled pack order has no pulls, no summary and no remaining_balance. Its pull_ids are the pull_ids of the pulls, and the cards are already in your vault: read them, with their CatchBack offers, from Get vault. A reconciled card order has no fee, remaining_balance or item. The 10-minute close above doesn’t apply to an order held for review. When we can’t confirm a charge (500 PAYMENT_OUTCOME_UNKNOWN, and the 409 after it carries needs_review: true), nothing was delivered, so our records can’t prove the charge and there is nothing to close the order from. It stays in progress until a person settles it, and the id is then free to send again. You don’t have to resend an order to learn where it stands. Get an order takes its checkout_id (the 409 body carries it): it shows the order as pending until it completes or we close it, a pack order’s pulls as soon as they have landed, and reconciled: true on an order we closed. List orders shows the same for every order in a window. An order held for review stays pending until we settle it. Settling removes it, so Get an order then answers 404 and List orders no longer shows it. If an order still answers 409 after 30 minutes, we couldn’t prove from our records that it went through. Contact us with the order id and the checkout_id.

Purchases that need review

A purchase can return "needs_review": true. On a card buy’s 200 the card is yours and only our bookkeeping needs a check. On an error, you were, or may have been, charged and the order didn’t finish cleanly, so it stays in progress and we’re alerted to settle it by hand. Either way, don’t retry under a new order id. Details: Errors.

Shipments

Create a shipment takes the same header in the same format, with some differences. Its ids are a separate set from your pack and card order ids, a retry of a finished shipment returns the shipment as it stands now rather than a stored response, and one we couldn’t confirm stays with our team until we’ve checked it. See its retry table.