Create an order
Send an order from your own website or channel into O2M.
Overview
Creates an order from a channel O2M does not connect to, such as your own website. O2M reserves the units at once and your warehouse ships it like any other order.
Request
POST/orders
Needs the permission orders:write
curl -X POST "https://api.o2m.in/api/v1/orders" \
-H "X-Access-Key: $O2M_ACCESS_KEY" \
-H "X-Secret-Key: $O2M_SECRET_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-SO-1001" \
-d '{
"order_id": "SO-1001",
"channel": "mysite",
"ordered_at": "2026-10-02T10:00:00Z",
"payment_method": "prepaid",
"customer": {
"name": "Ravi",
"email": "ravi@example.com"
},
"shipping_address": {
"name": "Ravi",
"phone": "9800000000",
"address1": "12 MG Road",
"city": "Pune",
"state": "Maharashtra",
"pincode": "411001"
},
"taxes_included": true,
"lines": [
{
"sku": "MUG-BLUE",
"quantity": 2,
"unit_price": 100,
"tax": 30.51
}
]
}'Body
| Parameter | Type | Required | Description |
|---|---|---|---|
order_id | string | Yes | Your own order number, up to 100 characters. |
channel | string | No | Your own name for where the order came from: 2 to 40 lower-case letters, digits or _, starting with a letter. The default is api. |
ordered_at | date and time | No | When it was placed. The default is now. |
dispatch_by | date and time | No | When it must leave the warehouse. |
payment_method | string | No | prepaid (the default) or cod. |
customer | object | No | name, email and phone. |
shipping_address | object | No | name, phone, address1, address2, city, state, pincode and country (default IN). |
taxes_included | boolean | No | Whether line prices include the tax you send. The default is true. |
lines | array | Yes | From 1 to 200 lines, one per SKU. |
Each line
| Parameter | Type | Required | Description |
|---|---|---|---|
sku | string | Yes | Must exist in O2M. |
quantity | number | Yes | A whole number from 1 to 100,000. |
unit_price | number | No | The price of one unit. The default is 0. |
tax | number | No | The tax amount for the whole line. |
title | string | No | The default is the product's name. |
Response
201 with the new order, in the shape described in List orders.
{
"id": "4410",
"order_id": "SO-1001",
"channel": "mysite",
"status": "placed",
"channel_status": null,
"ordered_at": "2026-10-02T10:00:00.000Z",
"updated_at": "2026-10-02T10:00:02.000Z",
"dispatch_by": null,
"shipped_at": null,
"delivered_at": null,
"cancelled_at": null,
"total": 200,
"tax": 30.51,
"customer": {
"name": "Ravi",
"email": "ravi@example.com"
},
"shipping_address": {
"name": "Ravi",
"phone": "9800000000",
"address1": "12 MG Road",
"address2": null,
"city": "Pune",
"state": "Maharashtra",
"pincode": "411001",
"country": "IN"
},
"client": null,
"lines": [
{
"id": "9001",
"sku": "MUG-BLUE",
"title": "Blue mug",
"quantity": 2,
"unit_price": 100,
"total": 200,
"tax": 30.51,
"reserved": 2,
"backordered": 0,
"dispatched": 0,
"delivered": 0,
"returned": 0
}
],
"shipments": []
}Sending the same order_id on the same channel again creates nothing. It answers 200 with the order as it is now, so a retry is always safe.
What O2M does next
- Reserves the units and chooses the warehouse.
- Puts any units no warehouse has on backorder, shown in
backorderedon the line. - Treats the order like any other: your warehouse picks, packs and dispatches it.
- Sends an
order.createdwebhook if you asked for it.
Good to know Create orders only for channels O2M does not connect to. Orders of Amazon, Flipkart, Shopify and other connected channels come from the channel itself.
Errors
| Status | Code | Message | What to do |
|---|---|---|---|
| 403 | NOT_YOUR_SKU | SKU MUG-BLUE is not one of your items | A 3PL client's key can order only that client's items. skus lists them. |
| 413 | — | At most 200 lines per order | Split the order. |
| 422 | UNKNOWN_SKU | No item has SKU GHOST | Add the item to O2M or correct the SKU. skus lists them all. |
| 422 | — | order_id is required: your own number for this order | Send order_id. |
| 422 | — | channel is 2 to 40 lower-case letters, digits or _, starting with a letter | Correct channel. |
| 422 | — | Orders of Amazon are imported from Amazon itself: name your own channel | Use a name of your own. |
| 422 | — | 'pos' is a channel O2M uses itself: name your own | wholesale, manual and pos are taken. |
| 422 | — | Add at least one line | Send lines. |
| 422 | — | Line 1: sku is required | Add the sku. |
| 422 | — | Line 1: quantity must be a whole number from 1 to 100000 | Correct quantity. |
| 422 | — | Line 1: unit_price must be 0 or more | Correct unit_price. |
| 422 | — | Line 1: tax must be 0 or more | Correct tax. |
| 422 | — | SKU mug-blue is on two lines: put its units on one | Add the quantities into one line. |
| 422 | — | ordered_at must be a date and time, for example 2026-10-02T10:00:00Z | Correct the value. The same applies to dispatch_by. |
| 422 | — | payment_method is 'prepaid' or 'cod' | Correct payment_method. |
Every endpoint can also return the common errors: a missing or invalid key, a missing permission, the rate limit, or a temporary failure.