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

# Order lifecycle

> Every status an order moves through, how your decisions drive it, and the fulfillment and payment fields it carries.

An order moves through a defined set of states. Maple creates it and handles payment and customer-facing transitions; you drive fulfillment by accepting it and reporting progress. This page is the reference for every status, the transitions between them, and the related fields on the order resource. To build the loop, see [Receive and decide orders](/developer-api/guides/receive-orders).

## Statuses

The order resource's `status` is always one of these nine values:

| Status               | Meaning                                   | Set by                                    |
| -------------------- | ----------------------------------------- | ----------------------------------------- |
| `PENDING`            | Created and awaiting a decision           | Maple (initial state)                     |
| `ACCEPTED`           | You accepted the order                    | your `accept` / `status: ACCEPTED`        |
| `AUTO_ACCEPTED`      | Accepted automatically at submission      | Maple — treat it like `ACCEPTED`          |
| `READY`              | Ready for pickup or courier handoff       | your `ready` / `status: READY`            |
| `IN_DELIVERY`        | Out for delivery                          | your `status: IN_DELIVERY`                |
| `FULFILLED`          | Completed                                 | your `complete` / `status: FULFILLED`     |
| `REJECTED`           | Declined, or couldn't be submitted to you | your `deny` / `status: REJECTED`          |
| `STORE_CANCELLED`    | Cancelled after acceptance by the store   | your `cancel` / `status: STORE_CANCELLED` |
| `CUSTOMER_CANCELLED` | The customer cancelled                    | Maple                                     |

`FULFILLED`, `REJECTED`, `STORE_CANCELLED`, and `CUSTOMER_CANCELLED` are **terminal** — an order in one of these states won't change again.

<Note>
  You set status through the [decision endpoints](/developer-api/guides/receive-orders#step-5--decide-and-report-progress).
  `PENDING`, `AUTO_ACCEPTED`, and `CUSTOMER_CANCELLED` are system states you'll observe but never set yourself.
</Note>

## How it flows

```mermaid theme={null}
stateDiagram-v2
  [*] --> PENDING
  PENDING --> ACCEPTED: accept
  PENDING --> REJECTED: deny
  ACCEPTED --> READY: ready
  READY --> IN_DELIVERY: status (delivery)
  READY --> FULFILLED: complete
  IN_DELIVERY --> FULFILLED: complete
  ACCEPTED --> STORE_CANCELLED: cancel
  READY --> STORE_CANCELLED: cancel
  FULFILLED --> [*]
  REJECTED --> [*]
  STORE_CANCELLED --> [*]
```

The happy path is `PENDING → ACCEPTED → READY → FULFILLED`, with `IN_DELIVERY` between `READY` and `FULFILLED` for delivery orders. From `PENDING` you either accept or reject. After accepting, you can still cancel (`STORE_CANCELLED`) up until the order is fulfilled. The customer cancelling (`CUSTOMER_CANCELLED`) can interrupt any non-terminal state, and arrives as an `order.cancelled` webhook.

Transitions are validated — a decision that isn't legal from the current state is rejected. Because every decision is [replay-safe](/developer-api/concepts/idempotency), repeating one is harmless.

## How your decisions map to status

| Call                         | Resulting status                                                                                    |
| ---------------------------- | --------------------------------------------------------------------------------------------------- |
| `POST /orders/{id}/accept`   | `ACCEPTED`                                                                                          |
| `POST /orders/{id}/deny`     | `REJECTED`                                                                                          |
| `POST /orders/{id}/ready`    | `READY`                                                                                             |
| `POST /orders/{id}/complete` | `FULFILLED`                                                                                         |
| `POST /orders/{id}/cancel`   | `STORE_CANCELLED`                                                                                   |
| `POST /orders/{id}/status`   | the value you send (`ACCEPTED`, `READY`, `IN_DELIVERY`, `FULFILLED`, `REJECTED`, `STORE_CANCELLED`) |

## When the webhooks fire

This is where each webhook lands across one order's life. Dashed arrows are webhooks Maple sends you; solid arrows are calls you make back.

```mermaid theme={null}
sequenceDiagram
  participant C as Customer
  participant M as Maple
  participant You as Your app
  C->>M: Places an order
  M-->>You: order.created
  opt You subscribed to validation
    M-->>You: order.validation_requested
    You->>M: validation_result (valid / invalid)
  end
  M-->>You: order.notification
  You->>M: accept
  M-->>You: order.paid
  You->>M: ready, then complete
  opt Customer or store cancels
    M-->>You: order.cancelled
  end
```

1. **`order.created`** — the order now exists. Fires whether or not you use validation.
2. **`order.validation_requested`** *(only if you subscribed)* — Maple asks you to confirm the order is fulfillable and waits for your `validation_result`. An `invalid` result rejects the order here, so it never reaches the notification.
3. **`order.notification`** — the order is handed to you to fulfill. You `accept` (or `deny`), then report `ready` and `complete`.
4. **`order.paid`** — payment settled. Its position varies: a pay-by-link order may be paid before the notification, while a pay-in-store order is paid afterward — don't assume it lands at a fixed point.
5. **`order.cancelled`** — the customer or store cancelled. This can arrive almost any time after creation, including after you've started fulfilling. Stop when it does.

None of your own transitions (`accept`, `ready`, `complete`) come back as webhooks, and there's no event for every status change — see below.

## Webhooks don't track every transition

There is no webhook for every status change. Maple emits a fixed set of order events — `order.notification`, `order.created`, `order.paid`, `order.cancelled`, and (if you subscribe) `order.validation_requested`. The transitions **you** drive — `accept`, `ready`, `complete` — aren't echoed back to you, and there's no event for reaching `IN_DELIVERY` or for payment moving to `refunded`, `voided`, or `failed`.

So the **order resource is the source of truth for current state, not the event stream.** When you need to know where an order stands, read `GET /v1/orders/{orderId}`. The webhooks tell you something happened; the resource tells you the state. See [Webhooks](/developer-api/concepts/webhooks).

## Fulfillment type

Every order carries a `fulfillment_type`, one of:

| Value      | Meaning                                                     |
| ---------- | ----------------------------------------------------------- |
| `pickup`   | The customer collects the order                             |
| `delivery` | The order is delivered; this is where `IN_DELIVERY` applies |

## Payment is read-only

Maple owns the customer payment lifecycle end to end. Payment is **never something you create or change** — there is no payment endpoint. You only ever read it, as fields on the order:

```json theme={null}
"payment_status": "paid",
"payment": { "provider": "stripe", "status": "paid", "payment_link_url": "https://..." }
```

`payment_status` and `payment.status` are the same value, one of:

| Payment status       | Meaning                |
| -------------------- | ---------------------- |
| `pending`            | Awaiting payment       |
| `paid`               | Paid                   |
| `failed`             | Payment attempt failed |
| `voided`             | Authorization voided   |
| `refunded`           | Fully refunded         |
| `partially_refunded` | Partially refunded     |

`payment_link_url` is the Maple-hosted link the customer pays through. It's `null` for pay-in-store orders and before a link has been created. Treat all of this as authoritative and read-only — see [How Maple works](/developer-api/how-maple-works#who-owns-what).
