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

# POST /v1/catalogue/orders

> Place an order for a contact — from your shop, a call centre or any system of your own.

Places an order for one of the account's contacts. It is the same order a WhatsApp cart opens: it shows in the panel's **Orders**, gets the next order number, starts `new`, and its history begins "Placed through the API". When the account has set Catalogue to open a deal for each order, it opens one in Pipelines too. Webhooks get `order.opened`.

<Note>Needs the `catalogue.orders:write` scope.</Note>

## Body

| Field | Type | Required | Notes |
| :- | :- | :- | :- |
| `contact` | string | Yes | The contact's id. |
| `items` | array | Yes | What was ordered: 1 to 100 lines, below. |
| `channel` | string | No | The channel the order is on — `whatsapp`, `sms`, `rcs`… Replies when it is confirmed or declined go there; without one, none is sent. |
| `note` | string | No | The customer's note. Up to 1,000 characters. |
| `currency` | string | No | A three-letter code. The account's catalogue currency when left out. |

Each line in `items`:

| Field | Type | Required | Notes |
| :- | :- | :- | :- |
| `product` | string | One of these | A product's id. |
| `sku` | string | One of these | A SKU, when you don't send `product`. One the catalogue doesn't have is kept as sent, with no product. |
| `quantity` | integer | No | 1 or more; 1 by default. |
| `unit_price_minor` | integer | No | The price of one, in minor units. The product's own price when left out — its sale price while it has one. |
| `name` | string | No | What the line is called. The product's name when left out. |

The total is worked out from the lines. Send an `Idempotency-Key` header so a retried request places the order once.

## Request

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.fireflo.au/v1/catalogue/orders" \
    -H "Authorization: Bearer $OMNI_API_KEY" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: shop-order-88412" \
    -d '{
    "contact": "5b2f9e1c-8a3d-4c7e-9f61-2d4b7a0e3c85",
    "channel": "whatsapp",
    "items": [
      {
        "product": "3f8a2c1e-7b4d-4e6a-9c2f-1a5b8d7e6f40",
        "quantity": 2
      },
      {
        "sku": "DUP-PHUL-RED",
        "quantity": 1
      }
    ],
    "note": "Gift wrap, please."
  }'
  ```

  ```python Python theme={null}
  import os

  import requests

  response = requests.post(
      "https://api.fireflo.au/v1/catalogue/orders",
      headers={
          "Authorization": f"Bearer {os.environ['OMNI_API_KEY']}",
          "Idempotency-Key": "shop-order-88412",
      },
      json={
          "contact": "5b2f9e1c-8a3d-4c7e-9f61-2d4b7a0e3c85",
          "channel": "whatsapp",
          "items": [
              {
                  "product": "3f8a2c1e-7b4d-4e6a-9c2f-1a5b8d7e6f40",
                  "quantity": 2,
              },
              {
                  "sku": "DUP-PHUL-RED",
                  "quantity": 1,
              },
          ],
          "note": "Gift wrap, please.",
      },
  )
  print(response.status_code, response.json())
  ```

  ```javascript Node theme={null}
  const response = await fetch("https://api.fireflo.au/v1/catalogue/orders", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.OMNI_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": "shop-order-88412",
    },
    body: JSON.stringify({
      "contact": "5b2f9e1c-8a3d-4c7e-9f61-2d4b7a0e3c85",
      "channel": "whatsapp",
      "items": [
        {
          "product": "3f8a2c1e-7b4d-4e6a-9c2f-1a5b8d7e6f40",
          "quantity": 2
        },
        {
          "sku": "DUP-PHUL-RED",
          "quantity": 1
        }
      ],
      "note": "Gift wrap, please."
    }),
  });
  console.log(response.status, await response.json());
  ```
</CodeGroup>

## Response

`201 Created` — the order. `status` is `new`, `confirmed`, `declined`, `fulfilled` or `cancelled`. `source` is where it came from: `cart` (a WhatsApp cart), `agent` (an AI agent's draft, approved by a person), `person` (made by hand in the panel) or `api`. `channel` is the channel it came in on, where replies about it go. Each line keeps its own copy of the name and price, so a later change to the product doesn't rewrite it; `product` is the product's id, or `null` for a SKU the catalogue doesn't have. Money is in minor units.

```json theme={null}
{
  "id": "9d4e2b7a-1c3f-4a8e-b6d5-0f2e7c9a1b34",
  "number": 1043,
  "status": "new",
  "source": "api",
  "channel": "whatsapp",
  "contact": {
    "id": "5b2f9e1c-8a3d-4c7e-9f61-2d4b7a0e3c85",
    "name": "Asha Menon",
    "phone": "+919876500102"
  },
  "items": [
    {
      "product": "3f8a2c1e-7b4d-4e6a-9c2f-1a5b8d7e6f40",
      "sku": "KUR-COT-IND-M",
      "name": "Cotton kurta — indigo, M",
      "quantity": 2,
      "unit_price_minor": 199900
    },
    {
      "product": "a71c5e93-2d8b-4f16-8e0a-6b9d3c2f1e57",
      "sku": "DUP-PHUL-RED",
      "name": "Phulkari dupatta — red",
      "quantity": 1,
      "unit_price_minor": 179900
    }
  ],
  "total_minor": 579700,
  "currency": "INR",
  "note": "Gift wrap, please.",
  "created_at": "2026-10-06T11:08:37+05:30",
  "updated_at": "2026-10-06T11:08:37+05:30"
}
```

## Errors

Every refusal is `{"error": {"code", "message", "field"}}`; `field` is there when one input is at fault.

| Status | Error code | When |
| :- | :- | :- |
| 400 | `invalid_request` | `contact` is missing or isn't one of the account's contacts, or `items` is empty, has more than 100 lines, names a product id the account doesn't have, a line with neither `product` nor `sku`, or a `quantity` or `unit_price_minor` that isn't a whole number (`field` names it). |
| 404 | `module_off` | The account doesn't have Catalogue on. |
| 403 | `scope_missing` | The key doesn't have the `catalogue.orders:write` scope. |

Any request can also be refused for its key, its account or its rate (`key_required`, `invalid_key`, `account_suspended`, `plan_excludes_api`, `address_not_allowed`, `rate_limited`); see [the overview](/api-reference/overview).


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