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

# Reopen order

> Void every payment of a placed, unpaid order and continue with a new OPEN order that has the same content.

Reopens a placed order owned by the authenticated customer while nothing has been charged yet. On a kiosk, the Cancel button during the checkout-release wait calls this endpoint.

Fire spark voids every pending payment tender (REDEMPTION rewards are released), cancels the order as `VOIDED` with the usual notifications, and creates a new `OPEN` order with the same store, channel, fulfillment, brand, customer, products, modifiers, and redemptions. Payments are not copied.

The link is stored in `metadata.reopen`. `as_order_id` is this order's replacement. `from_order_id` is the order this one replaced. Both can be set. A new order can be placed and reopened again while it is `CLOSED` and still cancelable, with no limit on the chain. A retry without `order_id` returns the same replacement.

An order that is already `VOIDED`, `REVERSED`, or legacy `CANCELLED` and was never fulfilled can also be reopened, for example after a failed injection whose card payment was reversed on the device. Nothing is voided or cancelled again and no webhook is sent; only the new `OPEN` order is created and linked. Every real tender must have ended with no money held (`CANCELLED`, `FAILED`, or fully `REFUNDED`). While a reversal is still in flight (a tender is `PAID`) the response is `400` `ORDER_PAYMENT_CAPTURED`; retry once the refund lands. A tender that is still `IDLE` or `PENDING` is `422` `ORDER_NOT_REOPENABLE`. A `REFUNDED` or `COMPLETED` order is never reopened: a refund only happens after delivery.

`order_id` in the body is optional. Omit it, or send no body, and the new order id is generated exactly as before (`genOrderId(storeId)`: `ord-<store>-<12 lowercase alphanumeric>`). When you send `order_id`, that value is the new order's id. It can be any id `genId()` can build (`isGenId` is the same check the API uses). `genOrderId` is one option and still returns `ord-<store>-<hash>`. `genOrderId(storeId, { length, format })` changes the hash: `length` is at least 8 (default 12) and `format` is `alphanumeric` (default, `0-9a-z`), `numeric` (`0-9`), or `alphabetic` (`a-z`). A bare hash is `genId().hash(16, "numeric").build()`. Separators are optional, so a literal can sit directly against the hash: `genId().literal("BB21921").hash(8, "numeric").build()` is an id like `BB2192100000001`. A hash shorter than 12 characters warns, and a numeric hash shorter than 16 digits warns; both still return the id. Shorter hashes are easier to guess and collide more often. `isGenId` accepts `[A-Za-z0-9-]`, at most 64 characters, no leading, trailing, or doubled `-`, and a run of at least 8 `[0-9a-z]`. A value that does not match is `400` with `details.code` and `code` `ORDER_ID_INVALID` and `error` `order_id does not match the genId format`. If a live order in this merchant and environment already has that id, the response is `409` with `details.code` and `code` `ORDER_ID_EXISTS` and `error` `An order with this id already exists`. The same `409` is returned when insert loses a race on `orders_id_merchant_env_deleted_unique` (Postgres `23505`). Uniqueness is that existing constraint, scoped to `(id, merchant_id, env, deleted_at)`. There is no single-column unique constraint on `orders.id`, and this API does not add one.

> [!NOTE]
>
> Requires a Storefront API access token from [Token
> exchange](https://firespark.cloud/docs/storefront-api/oauth/exchange/post.md).

In `@fire-spark/storefront`, call `order.reopen()`. It returns the new `Order`; replace the current order with it. Pass an id from `genId` or `genOrderId` when the new order should use that code: `order.reopen(genOrderId(storeId))`. A custom id is `order.reopen(genId().literal("BB21921").hash(8, "numeric").build())`. The same call with `genOrderId` options is `order.reopen(genOrderId(storeId, { length: 16, format: "numeric" }))`. The SDK sends that value as `order_id`. Omit the argument to keep the generated id.

> [!WARNING]
>
> Reopen is rejected with `400` when any payment was already captured and is
> not fully refunded on a cancelled order. Nothing changes in that case.

## Path parameters

| Parameter | Required | Description |
| - | - | - |
| `id` | Yes | External order identifier |

## Request body

| Field | Required | Description |
| - | - | - |
| `order_id` | No | New order id from `genId` (`genOrderId` is one option). Example: `BB2192100000001` from `genId().literal("BB21921").hash(8, "numeric")`. Omit it to keep the generated id. |

```bash theme={null}
curl -X POST "https://firespark.cloud/api/storefront/v1/orders/ord-48291/reopen" \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"order_id":"ord-store1-abcdefghij12"}'
```

Without `order_id`, send the same request with no body.

## Response

Returns `201` with the new open order. Retrying the same reopen returns `200` with the same new order.

> [!NOTE]
>
> Integrations receive the same `order.voided` webhook as a
> [cancel](https://firespark.cloud/docs/storefront-api/orders/\[id]/cancel/post) for the source order.

```json Success theme={null}
{
  "data": {
    "id": "ord-48292",
    "status": "OPEN",
    "payment_status": "IDLE",
    "metadata": { "reopen": { "from_order_id": "ord-48291" } }
  }
}
```

## Error responses

| Status | Description |
| - | - |
| `400` | A payment was already captured, or a cancelled order still has a `PAID` tender (`details.code` and `code`: `ORDER_PAYMENT_CAPTURED`), or `order_id` is not a `genId` (`ORDER_ID_INVALID`, `error`: `order_id does not match the genId format`) |
| `401` | Missing or invalid access token |
| `404` | Order not found |
| `409` | An order with `order_id` already exists, including a unique-constraint race (`details.code` and `code`: `ORDER_ID_EXISTS`, `error`: `An order with this id already exists`) |
| `422` | Order cannot be reopened in its current state, including a cancelled order with an `IDLE` or `PENDING` tender (`details.code: ORDER_NOT_REOPENABLE`) |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.