> ## 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.

# Place order

> Close an open cart, lock its payment intent, and start fulfillment.

Validates the current cart, locks the payment intent, copies the fulfillment workflow, closes the order, and starts the durable place-order walker. The walker enters the first `state` and waits for a later [status update](https://firespark.cloud/docs/integrations-api/orders/\[id]/status/patch).

> [!NOTE]
>
> Requires a Storefront API access token from [Token
> exchange](https://firespark.cloud/docs/storefront-api/oauth/exchange/post.md). A second place of the same
> order is rejected.

In `@fire-spark/storefront`, call `order.placeOrder()`. With no `intent_id`, the SDK saves the current tenders first (from `setTenders` / `applyRedeem`, or from `payment` as one real tender) and then places with that draft's `intent_id`. If the last cart sync was rejected, `placeOrder` throws `OrderSyncRejectedError` (with the API `code`) and places nothing. With no real tender and redeems that do not cover the total, it throws `OrderPaymentRequiredError` (`code: PAYMENT_REQUIRED`) without calling the API.

## Path parameters

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

## Request body

Send `intent_id` or `payment.type`. There is no cash default: a body without either (`{}`) is rejected with `422` `PAYMENT_REQUIRED`, unless the redeems cover the whole total. Then place builds only `REDEMPTION` tenders.

| Field | Required | Type | Description |
| - | - | - | - |
| `intent_id` | No | string | Id of the `DRAFT` intent saved with [Save payment intent](https://firespark.cloud/docs/storefront-api/orders/\[id]/payment-intent/put). Place locks that intent. When set, `payment` is ignored. |
| `payment.type` | No | `CASH` \| `CARD` \| `BANK_TRANSFER` \| `WALLET` \| `PIN_PAD` \| `FINANCING` \| `REDEMPTION` | Single-method shortcut, required without `intent_id` unless the redeems cover the total. Place builds one real tender plus one `REDEMPTION` tender per redeem `payment_id`. |
| `payment.provider` | No | catalog provider id | Defaults to `firespark`. |
| `payment.id` | No | string | Merchant payment id. Copied onto the real tender as `payment_id`. |
| `payment.collect_at` | No | `DEVICE` \| `KIOSK` \| `COUNTER` \| `DOOR` \| `OTHER` | Where that tender is collected. Defaults to `DOOR` for `CASH` and `DEVICE` for every other method. |

A saved `DRAFT` or `LOCKED` intent is abandoned when you place without `intent_id`. The new intent is `LOCKED`.

```bash theme={null}
curl -X POST "https://firespark.cloud/api/storefront/v1/orders/ord-48291/place" \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "payment": {
      "type": "CARD",
      "provider": "kushki",
      "collect_at": "DEVICE"
    }
  }'
```

To lock a draft you already saved:

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

## Response

| Status | Meaning |
| - | - |
| `201` | Accepted — fulfillment started (`status: ACCEPTED`) |
| `202` | A place run is already in progress (`status: IN_PROGRESS`) |
| `409` | The order is already placed or no longer `OPEN` (`status: EXISTS`) |
| `422` | Validation failed, no payment was sent (`details.code: PAYMENT_REQUIRED`), the draft intent does not match, or the fulfillment graph is invalid |

```json Success theme={null}
{
  "data": {
    "order_id": "ord-48291",
    "order_fulfillment_id": "ord-48291",
    "status": "ACCEPTED"
  }
}
```


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