Create or replace an order

Use this endpoint for orders pushed from your own OMS. It creates
the order on the first call and replaces it on later calls, and is the
recommended way to send us orders.

  • 201 on first create — data.newly_created: true,
    data.applied: true, plus protect_order_number and
    order_number.
  • 200 with data.applied: true and data.fields_changed_count
    when the request body differs from the stored order.
  • 200 with data.applied: false and data.reason: "no_change"
    when the request body matches the stored order.

The path identifies the order

The path parameter order_number identifies the order. If the
body also supplies order_number, it must match the path; otherwise
the request fails with 422 PATH_BODY_MISMATCH. You may omit
order_number from the body — the path value populates it.

Fields that cannot change after the first create

These fields are set on the first create and cannot be changed by a
later request: order_number, order_id, protect_order_number,
is_protected, amounts.protection_cost, order_date_created,
platform_domain, source_channel, api_version, and
order_lifecycle_status. On later requests, send the same values or
omit them — both are accepted. (platform is not in this list because
it is ignored on every request — see the field's description.)

Protection is frozen after the first push. is_protected and
amounts.protection_cost are validated as a PAIR on every request,
including re-pushes: send both with their stored values, or omit both.
A request stating one without the other is rejected with 422
(code: VALIDATION_ERROR) naming the missing field — this is the same
pairing rule that applies on the first create, and it is checked before
immutability is considered.

Sending a different is_protected or amounts.protection_cost is
rejected with 409 (code: PROTECTION_IMMUTABLE).

One case is worth calling out because the two rules overlap: sending
amounts.protection_cost: 0 on a protected order is rejected with
422, not 409. It fails the pairing rule first — a protected order
requires a fee above zero — so the validation error is what you
receive. It is still a rejection; only the code differs.

Omitting both fields leaves the stored values untouched. Protection is
reduced only by cancelling the order or part of it, through the
cancellation endpoint.

Server-injected fields

store_id, platform_domain, currency, source_channel, and
api_version are server-injected from the JWT-derived Store
record. Client values for these fields are silently dropped.

Line-item identity across updates

line_items is replaced wholesale on every applied change, so the body
MUST contain the full, current set of lines. Get Plus owns a read-only
line_id per line — the stable key returns are filed against (the
line_id used by POST /returns).

  • On the first create you MAY supply your own line_id on each line.
    It's honoured only when every line carries a non-empty, order-unique
    line_id (then line_id_source: partner); otherwise Get Plus mints
    li_<hex> ids for all lines (line_id_source: protectplus).
  • On every later update Get Plus carries the id forward: a line
    that still matches an existing line (by product_id/sku) keeps its
    line_id; only new lines get a new id. A line_id sent on an update
    is ignored — the id is fixed at create. Removing a line, or
    swapping the product/sku on a line, drops/replaces that line's id —
    so prefer quantity edits over re-keying a line you may still receive
    returns for.

Guard: if an update would remove or re-key a line that already has
a return request, the request is rejected with 409
(code: LINE_HAS_ACTIVE_RETURN) and the offending lines are listed
under line_items. Adjust quantities instead, or leave the line in
place. (Lines without returns can be removed/changed freely.)

Recent Requests
Log in to see full request history
TimeStatusUser Agent
Retrieving recent requests…
LoadingLoading…
Path Params
string
required
length ≥ 1

The authoritative store order number. If the body supplies order_number, it must match this value.

Body Params

Request body for PUT /orders/{order_number} — create or replace an order on the custom platform.

  • platform is deprecated, optional 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.
  • order_number is optional. If supplied, it must match the URL path parameter; the path value is authoritative.
  • store_id, platform_domain, currency, source_channel, and api_version are server-injected. Any client values for these fields are silently dropped.
  • The top-level object is closed (additionalProperties: false); unknown keys are rejected with HTTP 422 (application/problem+json, VALIDATION_ERROR).

All timestamps are ISO 8601 / RFC 3339 in UTC. Monetary fields are decimal values with an ISO 4217 currency. Identifiers are opaque strings — do not parse them. Supply an Idempotency-Key (UUID) request header to make a retried PUT safe.

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 from the Store record.

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

Set on first create only; later requests to the same order cannot change this field.

line_items
array of objects
required
length between 1 and 250
line_items*
string
length ≤ 32
metadata
object
string
length ≤ 4096
string
length between 1 and 128

Optional source-platform internal order ID.

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. PUT /orders is a FULL REPLACE — resend order_notifications on every request to keep it; omitting it clears the stored opt-in.

string
length between 1 and 128

Optional. If supplied MUST equal the URL path order_number; otherwise the path value populates this field on the persisted doc.

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 order placement timestamp (UTC).

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 Store record.

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