Skip to main content
Use the Developer Platform orders endpoints to list workspace orders with the same filters as the UI, create native agentic orders from external systems, and patch agentic order fields (status, created date, money, currency, and line items). Settlements (fees, settlement status, marketplace net, and payment received) are not order fields. Use the Settlements API (POST /api/v1/settlements).

Authentication

Send an OmniCommerce API key or OAuth client-credentials token:
OAuth clients must include the scope on the client. API keys created from organization settings receive all developer scopes by default. Session-authenticated calls must include organizationId in the query (GET) or JSON body (POST/PATCH).

Order status enum

Canonical statuses for create and patch (also used as listing filter groups): Marketplace-imported orders may store platform-specific raw status strings; the developer write APIs only accept this enum.

Pricing fields

Money fields on orders and line items:

price vs unitPrice vs paidPrice

These three are selling prices on the line (per unit). They are not COGS and not marketplace fees. How Omni picks a number for line money
  1. If paidPrice is set → use paidPrice × quantity
  2. Else if unitPrice or price is set → use that × quantity
  3. Else if productId is set on create → may resolve from the product catalog
You do not need all three. For most agentic / Zalora-style integrations, send one selling price:
or, if you only have a single price field in your system:
Use both list and paid when they differ:
These field descriptions are also published on OpenAPI / Redocly (POST/PATCH /api/v1/orders line schemas).

costPrice (product-owned)

costPrice is not a first-class order table column. Its reusable catalog value is stored at: products.product_data.costPrice When you send items[].costPrice with a productId:
  1. OmniCommerce upserts product_data.costPrice and product_data.costPriceCurrency on that product (after FX, in local/target currency).
  2. The value is snapshotted on the order line as metadata.costPrice; this snapshot is canonical for historical order/P&L economics.
Rules:
  • costPrice belongs on the items[] array (per line), not on the order root.
  • Omitted costPrice never clears an existing product or line cost.
  • When omitted on create with productId, the line snapshot may still resolve from the product catalog if a cost is already stored there.
  • Product cost is only written when costPrice is explicitly present on the request.

Cost currency and FX

P&L treats costPrice as the same unit as order revenue. When invoice COGS is in another currency (e.g. USD) and the order is MYR/SGD/PHP/HKD:
  • Rate meaning: 1 USD = 4.45 MYR → stored local cost 534.
  • If costPriceCurrency differs from the target and costPriceFxRate is omitted, Omni fetches the rate from Frankfurter (getFxQuote / ECB daily rates). Optional costPriceFxAsOf pins a historical date (YYYY-MM-DD or month YYYY-MM).
  • Line metadata keeps an audit trail: sourceCostPrice, sourceCostCurrency, costPriceFxRate, costPriceFxFrom, costPriceFxTo, costPriceFxAsOf, costPriceFxSource (manual | frankfurter | fallback | identity).
  • Alias: costCurrency = costPriceCurrency.
  • Manual seller rates always win over auto FX.
  • costPriceFxTo must match the effective line/order currency so COGS and revenue remain comparable.
  • Cost currency and FX fields require an explicit costPrice on the same line. A currency-tagged catalog fallback is converted when its stored currency differs from the new line/order currency.
  • When no rate can be resolved (unsupported pair, FX provider unreachable), the request fails with 400 before the order is written — retry with costPriceFxRate.

Catalog fallbacks on create

When line price / unitPrice / paidPrice / currency are omitted and productId is provided, create resolves missing values from the product catalog (products.price, product_data, currency). Order total is then computed from the resolved line amounts when totalAmount is omitted.

List orders

Query parameters

These match the workspace Orders listing page (/app/{organizationId}/orders):

Response

Each item includes order totals and line money fields when available:
Line costPrice is read from the order-line metadata snapshot (metadata.costPrice).

Create order

Creates a native agentic order and line items through the same upsert path used by agentic checkout completion. Marketplace orders should continue to flow through marketplace import/webhook pipelines.

Request body

Re-posting the same platform + externalOrderId pair updates the existing order and returns HTTP 200 with created: false. Lines upsert by externalOrderItemId.

Country from currency

When order country is empty, Omni may set country from order currency (and the same rule applies on PATCH and Zalora recon apply). Explicit country always wins. Workspace order listing and detail use the same fallback for display when stored country is empty.

Multi-SKU / one-row-per-SKU partners (Zalora recon)

Omni models one marketplace order → one Omni order. Marketplace recon (for example Zalora Item Transaction Reports) matches the report order number to agentic external_order_id, then matches lines by external_order_item_id or unique Seller SKU on that order. If your system stores one row per SKU that share a marketplace order id:
  1. Always use the marketplace order id as externalOrderId (not your per-SKU order number).
  2. Put your unique per-SKU id on items[].externalOrderItemId.
  3. You may POST one line at a time with the same externalOrderId — lines upsert onto the same Omni order.
  4. Omit totalAmount when appending lines so Omni recomputes the order total from all lines. Send totalAmount only when you know the full cart total.
Do not invent composite externalOrderId values like MP-12345:SKU-A for uniqueness — recon will not match the marketplace order number. If you already created separate Omni orders per SKU with different external ids, create/upsert again using the marketplace order id as externalOrderId and stable line externalOrderItemIds (preferred going forward). Do not set the same marketplace id on multiple Omni order shells via PATCH — that still returns 409.

Example: Zalora cart with 2 SKUs

Your system (one DB row per SKU): Wrong — two Omni orders (or same externalOrderId on two shells → 409):
Zalora report order 3012345678 will not match either shell. Right — one Omni order; your row ids become line ids. Same marketplace id on every push; omit totalAmount so Omni sums all lines:
First response (201, created: true):
Second response (200, created: false — same order, second line appended):
Result in Omni: You can also send both lines in one request if your push job can group by marketplace order id:

Response

Update order

Updates a native agentic order. Supports external order identifiers, status, created date, currency, country, money fields, metadata, and line-item upserts (externalOrderItemId, price / unitPrice / paidPrice / costPrice / currency / status / quantity, and more). Marketplace orders are rejected with 409 — those fields are marketplace-owned. Use marketplace tooling or the workspace order-actions flow for them. At least one of externalOrderId, externalOrderNumber, status, currency, country, totalAmount, shippingFee, discountAmount, metadata, orderCreatedAt, or items is required. When country is omitted and the order’s stored country is empty, Omni fills country from the resulting order currency (same map as create — see Country from currency). Line upserts: matching externalOrderItemId (or unique productId) updates the line. A new externalOrderItemId with productName + quantity inserts a line (multi-SKU append on an existing order). When totalAmount is omitted and lines change, Omni recomputes the total from all lines.

Path parameters

Request body

Status-only:
Money, currency, and line pricing (status optional):
Correct created date:
Repair identifiers on an imported order:

Line patch identity

Each items[] entry must identify a line with: Each patch line must also include at least one field to update (price, unitPrice, paidPrice, costPrice, currency, status, quantity, etc.), or productName + quantity when inserting a new line. Omitted costPrice on a line patch does not clear product or line cost. Explicit costPrice with a resolved product id upserts the product catalog cost.

Partial vs full return (line status)

Canonical line/order status return marks a return. Returns are line-level; order status is a roll-up. Partial return — one of several lines returned (order stays sold for remaining lines):
Response includes roll-up fields: P&L and product economics treat returned lines as sold qty 0. Ledger fees with external_order_item_id attribute to that line; remaining fees pro-rate by sold line revenue. Full return — every line returned (or set order status explicitly):
When all lines are return and you did not send a different top-level status, Omni sets order status to return, returnState to full, and returnRefundAmount to at least the full order total so retained revenue is zero. You can still force full-order return with:
That top-level status marks every line return, zeros line paymentReceived, rolls up refund/sales flags, and restocks product inventory only when the line had inventory deducted on sale (metadata.inventoryDeductedAt). Line selection by productId works the same as by externalOrderItemId (must be unique on the order). PATCH responses and each GET /api/v1/orders item surface unit-economics fields: Optional per-line refund override: set items[].metadata.returnRefundAmount before/with the status patch; roll-up prefers that over paidPrice × qty.

Example: append a second SKU via PATCH

After creating order 3012345678 with line ORD-9001, append line ORD-9002 without re-posting the whole cart:
Response includes recomputed totalAmount (e.g. 90 when the first line was 50). Omit top-level totalAmount so Omni sums all lines. Update an existing line (same id) by sending only the fields to change:

Response

changed is false when the request is a no-op. changedFields lists what actually changed.

Errors

  • 400 — invalid JSON, validation failure, unknown status, missing patch fields, or line identity failure.
  • 401 — missing or invalid bearer token / session.
  • 403 — missing orders:read or orders:write scope.
  • 404 — order not found for this organization (PATCH only).
  • 409 — updates not supported for marketplace-owned orders, or an external identifier is already in use.
  • 429 — developer API rate limit exceeded.
  • 500 — unexpected server failure.