---
title: "Order lifecycle"
description: "Every order has one of five statuses. fulfilled, failed, and canceled are final, and only fulfilled means success."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.cardzone.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Order lifecycle

This page explains each order status and what your code should do for it. The lifecycle is the path an order takes, from creation to a final status.

Every order response has one `status`. This is true when you create an order, when you poll it, and in a webhook. Click a status to see what it means and an example response for it:

## The most important rule

**Mark a sale as successful only when `status` is `fulfilled`.**

- A `201 Created` response means Cardzone accepted the order. It does not mean the order was delivered.
- An order-created webhook is not a success signal either.

| Status | Final | Meaning |
| --- | --- | --- |
| `processing` | No | Cardzone accepted the order, or is still fulfilling it. |
| `action_required` | No | Paused until the entries in `actions[]` are handled. |
| `fulfilled` | Yes | Every item was delivered. |
| `failed` | Yes | Fulfillment ended without delivering. Check `failure_code`. |
| `canceled` | Yes | The order was canceled. Nothing more will happen. |

## Order IDs

Every order response has an `order_id`. It is a 22-character Base58 string (letters and numbers), like `1CBDzqwiovwVrtFk6nZ1Aw`. Use it to poll the order, in links, and when you contact support. Save it next to your own `merchant_order_ref`.

To look up an order, you can use either:

- the `order_id` of any order in your store, or
- the `merchant_order_ref` you sent when you created the order through the API.

If a create request times out and you never got the `order_id`, [poll by your `merchant_order_ref`](https://docs.cardzone.ai/guides/idempotency-and-retries/).

## Actions

When `status` is `action_required`, `actions[]` lists what is blocking the order. Your code MUST make decisions based on `type` and `code`. Show `message` to people.

| `type` | `code` | What to do |
| --- | --- | --- |
| `wallet` | `wallet_topup_required` | Recharge the store wallet. `message` gives the total amount to recharge for all wallet-blocked orders in the store. |
| `fulfillment` | `merchant_attention_required` | Fulfillment has not delivered within 15 minutes. Review the order in the dashboard. When you mark it as reviewed there, the action is cleared. |
| `fulfillment` | `manual_review_required` | Cardzone is reviewing the order. Keep polling. |

See [Handle action_required](https://docs.cardzone.ai/guides/action-required/) for a full code example.

## Failures

`failure_code` tells your code why the order failed:

- `player_id_incorrect`: the game rejected the player ID for sure. Ask the customer to fix it, then place a new order.
- `fulfillment_failed`: any other failure.

`failure_reason` is a short text for people. It is kept for compatibility. Messages from providers (the suppliers that deliver the items) never appear in either field.

> **Final orders can still change**
>
> - Sometimes Cardzone delivers replacement codes that your store paid for. Cardzone adds them to `codes[]`, and you get another status webhook. This happens even when the status is already `failed`.
> - Your store team can retry a `failed` order in the Cardzone dashboard. The order then moves back to `processing`, and then on to a new final status. You get a status webhook for each change.
>
> So your code MUST keep accepting updates for final orders.

Source: https://docs.cardzone.ai/concepts/order-lifecycle/index.mdx
