Create an order

Deprecated — use PUT /orders/{order_number} instead. It takes
the same body, creates the order on the first call, replaces it on
later calls, and is safe to retry.

This endpoint only accepts orders for stores in custom_api
ingestion mode (see the 409 note below), and every order it
ingests is stored as a custom order. Shopify and WooCommerce stores
reach Get Plus through their own webhook pipelines, not through
this endpoint.

Create a new order on Get Plus. Use this when your OMS or
e-commerce platform has produced an order and you want to
attach Get Plus coverage to it.

Order contract

This endpoint accepts the full order contract: a strict, closed
schema covering the order with a nested customer, amounts,
structured addresses, line items, shipments, discounts, and tax
lines. See
OrderCreateRequest
for the full shape.

Idempotency

The endpoint is idempotent: replaying the same
(store_id, order_number, order_id) tuple returns the existing
order with HTTP 200 and data.newly_created: false. The first
call gets HTTP 201 and data.newly_created: true.

Server-injected fields

Five fields are server-injected and dropped if sent by the
client: store_id, platform_domain, currency,
source_channel, api_version. See OrderCreateRequest for
details.

Order ingestion mode (HTTP 409)

This endpoint only accepts orders for stores in custom_api
ingestion mode
. A store left on the default shopify_webhook mode
gets a 409 Conflict, so the same order isn't ingested twice (once
via webhook and once via this endpoint). Set the store's Order
ingestion mode
in the Get Plus dashboard before pushing orders.

Recent Requests
Log in to see full request history
TimeStatusUser Agent
Retrieving recent requests…
LoadingLoading…
Body Params

Request body for POST /orders.

Six fields are required: order_number, ordered_at, currency, customer, amounts, line_items. Everything else is optional, but send what you have.

platform is deprecated and ignored — every order ingested through this API is stored as a custom order whatever you send. It is still accepted (and logged) so existing integrations do not break; omit it.

Server-injected fields

Five fields are server-injected and cannot be set by the client: store_id, platform_domain, currency, source_channel, and api_version. Any client values for these fields are silently dropped before the request is processed:

  • store_id is derived from the store_id claim on your JWT (the JWT you obtained from POST /auth/v1/token). You do not send any header for this — the gateway reads it from the token.
  • platform_domain is taken from your store record (resolved from the JWT-derived store_id), so it stays in sync with dashboard updates without forcing a token refresh.
  • currency is taken from the Store record's configured currency. You must still send currency in the body (it is validated for shape) but the value reaching storage is the Store's.
  • source_channel is always "custom_api" on this endpoint.
  • api_version is always "v1".

Strict body

The top-level object is closed (additionalProperties: false) — unknown keys are rejected with HTTP 422 (application/problem+json). Free-form / source-platform data belongs in metadata (≤16 top-level keys, ≤8 KB recommended) or source_payload (≤32 KB recommended, opaque to Get Plus).

Backward compatibility (deprecated, removed in the next release)

For one release window only, the gateway accepts two legacy keys and rewrites them silently before validation: store_order_number → order_number and store_order_id → order_id. Other legacy keys are not rewritten — see the full migration table in the POST /orders operation description.

Idempotency

Replaying the same (store_id, order_number, order_id) tuple returns the existing order with HTTP 200 and data.newly_created: false. The first call gets HTTP 201 and data.newly_created: true. Independently, an Idempotency-Key request header (UUID) makes any retried POST /orders safe — a replay returns the original response verbatim.

All timestamps are ISO 8601 / RFC 3339 in UTC. Monetary fields are decimal values accompanied by an ISO 4217 currency. Identifiers (store_id, order_id, …) are opaque strings — do not parse them.

amounts
object
required

The order's money figures, in the order's currency. Only subtotal is required by validation, but send every figure: 0 means zero, and a figure left out is read as not sent, never as zero. These six are the only keys accepted: any other, such as shipping, tax, discount or total, is refused with 422 VALIDATION_ERROR.

The figures fit together like this:

  • Each line's line_total = its unit_price × quantity, less the line's own discount.
  • subtotal = the lines' line_totals, less any order-wide discount. It includes tax only when prices include tax.
  • discount_total = every line's unit_price × quantity, less subtotal.
  • grand_total = subtotal + shipping_total + protection_cost, plus tax_total only when prices exclude tax.

When the order is stored, Get Plus checks every figure against the others. An order whose figures don't agree, or that leaves one out, is flagged, and staff see why before they approve a claim on it.

After a partial cancellation don't take the cancelled units out of these figures: the cancellation is recorded on its own, with POST /orders/{order_number}/cancel. Get Plus keeps the order's discount as it stood at its first partial cancellation: what the lines' line_totals come to above subtotal, or their unit_price × quantity when they carry no line_total. A request that moves subtotal without the lines, lowering it by the cancelled units included, gets the order flagged, and it stays flagged on every later write until the discount is as it was. Adding, removing or re-pricing an item that nothing was cancelled on, sending a figure for the first time, and refunding shipping sent as shipping_total are not flagged when the lines and subtotal move together. On a subtotal that has the shipping in it and lines with no line_total, a shipping refund lowers subtotal alone and is flagged. The discount is kept as an amount or as a share of the items, so a percentage off the whole order keeps its share as items are added, removed or re-priced, and is not flagged. An order partially cancelled before Get Plus began keeping the figures has none kept: only the request that changes them is flagged, and the same figures sent again are not.

Claim payouts. When every figure is sent and they all agree, a claim pays what was paid for the claimed items: each line's line_total, less its share of any order-wide discount. On a flagged order, a claim pays the claimed items' share of subtotal instead, never more than their list price. The Claims guide explains both under How a claim payout is priced.

string

Ignored if supplied by the client — server-injected (currently always "v1").

billing_address
object
string
required
^[A-Z]{3}$

ISO 4217 currency code, uppercase. Server-injected: required in the request for validation, but the value reaching storage is the Store's configured currency.

customer
object
required
discounts
array of objects
length ≤ 100

Every discount on the order, one entry per code or discount, each with its amount and applies_to. A line entry is a discount on particular lines, already taken off their line_total; an order entry is an order-wide discount, which is on no line. The line entries add up to the lines' own discounts, and the order entries to what the line totals come to above amounts.subtotal.

Claim payouts never use them to pay a claim. They must agree with the other figures, or the order is flagged: a line discount listed here but left off its line gets the order flagged.

discounts
boolean

True if Get Plus protection should be applied. When true, amounts.protection_cost should be greater than 0.

line_items
array of objects
required
length between 1 and 250
line_items*
string
length ≤ 32

BCP 47 locale tag (optional).

metadata
object

Free-form key-value object (≤16 top-level keys, ≤8 KB recommended). Total serialised size enforced by the body parser.

string
length ≤ 4096
string
length between 1 and 128

Source-platform internal order ID. Falls back to order_number upstream when omitted.

order_notifications
object

Customer's per-channel opt-in for order/tracking notifications. Get Plus sends a tracking email only when email is true and an SMS only when sms is true; omit a channel (or send false) to suppress it. Persisted on the order so notification delivery can honour the customer's preference.

string
required
length between 1 and 128

Customer-facing order number. This is the single canonical external order identifier across the API.

date-time

ISO 8601 / RFC 3339 timestamp (UTC) of when the order was last updated in your system. Stored on the order alongside the payload. Note: Get Plus also maintains its own record updatedAt (the time we last wrote the document), which is distinct from your source-system timestamp.

date-time
required

ISO 8601 / RFC 3339 timestamp (UTC) of when the order was placed on the source platform.

string
length ≤ 64
deprecated

Deprecated — ignored. Every order ingested through this API is stored as a custom order, whatever this field says. Any string is accepted (and logged), never acted on — there is no list of allowed values; the only constraint is a 64-character cap. Omit it.

string

Ignored if supplied by the client — server-injected from the authenticated session.

shipments
array of objects
length ≤ 100

Shipments to register for this order. Each entry is registered with the carrier and drives the customer tracking page + notifications — the same pipeline as POST /shipments, so no separate call is needed. Registration is idempotent per (store, tracking_number, order_number). Include more than one entry for a split order (shipped in several packages, even across carriers); each tracking number is tracked independently and shows only its own items.

shipments
shipping_address
object
string

Ignored if supplied by the client — server-injected (always "custom_api" for this endpoint).

source_payload
object

Verbatim copy of the original platform payload (opaque to Get Plus; retained for later reference). ≤32 KB recommended; size enforced by the body parser.

source_store
object

PPLUS-4743 — the store the order originated from, for B2B platform accounts (same "source" family as source_channel / source_payload: it names the partner's own system, not ours).

Who must send it. Required on every POST /orders and PUT /orders/{order_number} for a store configured as a B2B platform; omitting it is rejected with 422 SOURCE_STORE_REQUIRED. Every other store must NOT send it — a body containing it is rejected with 422 SOURCE_STORE_NOT_ALLOWED. The store's configuration is read server-side on every request; there is no request field or token claim that selects the behaviour.

It is a label, never a key. id is an opaque string YOU choose and manage. Get Plus never resolves it to a Get Plus store, merchant, API key or login — it is stored beside the order and shown on your dashboard. Source stores have no account, no credentials and no portal.

Order numbers stay globally unique across your source stores. Orders are addressed by (your store, order_number) everywhere in this API — replay, PUT, GET, cancel, the customer tracking page — and source_store does not form part of that key. Two source stores reusing one order number are the SAME order to Get Plus.

Immutable after the first write. A replay or PUT that names a different id or a different name for an order that already exists is rejected with 409 SOURCE_STORE_CONFLICT; sending the identical value is the normal idempotent path. Omit the whole object and the stored value is kept unchanged. Not accepted in the POST /orders/{order_number}/cancel body (422).

Not shown to shoppers. It never appears on tracking pages, notification emails or SMS.

string
length ≤ 64

Free-form source-platform status string.

string

Ignored if supplied by the client — server-injected from the authenticated session.

tax_lines
array of objects
length ≤ 100

The order's tax, one entry per tax. When amounts.tax_total is sent, it is the order's tax; when it is not, the tax is these entries' amounts added up.

tax_lines
Headers
string
enum
Defaults to application/json

Generated from available response content types

Allowed:
Responses

Language
Credentials
Bearer
JWT
LoadingLoading…
Response
Click Try It! to start a request and see the response here! Or choose an example:
application/json
application/problem+json