ShopEazydevelopers
API referenceStorefront APICheckout

Place an order

Credentials, one of
  • Store key
  • Store key and Shopper session
  • Store key and Shopper ID token
Scopes
checkout:write
Idempotency
Send an optional Idempotency-Key header. A retry with the same key does the work once.
POST
/v1/store/orders

Re-derives prices server-side, finds or creates the customer, and reserves booking slots atomically. customer.name is required.

Members-only stores (store.membership.enabled): a shopper credential is required (401 shopper_required without one) and the shopper must be an active member (403 not_a_member). On other stores a shopper credential is optional; when sent, the order is linked to that shopper (it appears in GET /v1/store/me/orders and they can read it back with their credential).

The response carries accessToken, returned only here. Keep it for the confirmation page: GET /v1/store/orders/{id} and /confirm need it as X-Order-Token (or the shopper who placed the order). The id alone reads nothing.

Coming soon (the fields are in the schema and say so). discountCode, paymentMethod (eft answers bank details), event attendees, a price guard (expectedUnitMinor), a whole-basket stock check, giftNote, marketingOptIn, saveAddress, attribution, basketId. The refusals reuse 422 validation_error with details.reason (price_changed, items_unavailable with details.unavailableItemIds, out_of_stock, discount_invalid, payment_method_unavailable); a stale delivery stays 422 delivery_changed. When sent, customer.email is checked and lowercased and customer.phone is normalised to E.164 (422 validation_error names the field); customer.name stays the only required field, because requiring more would break existing sites.

Old path, deprecated, sunset 1 Feb 2027: POST /v1/orders.

Authorization

headerAuthorizationBearer <sez_pub_... (publishable) or sez_sk_... (secret)>

A per-store key from the console. Publishable keys are browser-safe; secret keys are server-only.

Scope: checkout:write

Header Parameters

Idempotency-Key?string

Optional. Mint it once per order or payment attempt and reuse it on every retry: the work is done once and a retry gets the first 2xx response back with Idempotent-Replay: true. Belongs to the store key, remembered 24 hours. The same key with a different method, path or body is 409 idempotency_key_reused; a request still running is 409 in_flight; a malformed key is 422 validation_error; if the key store cannot be read nothing is processed and the answer is 503 idempotency_unavailable.

Match^[A-Za-z0-9_-]{8,128}$

Request Body

application/json
  1. body
lines*array<>
fulfilment?Fulfilment
Value in"delivery""collect"
shippingAddress?
deliveryChoice?

The delivery service picked from a quote's delivery.options. Never a price to charge: the server re-quotes the courier and charges its price now. If that service is gone, or costs more than expectedPriceMinor, the call is 422 delivery_changed and the shopper chooses again. If no courier can quote at all, the store's flat fee is charged.

customer*
note?string
discountCode?string

Coming soon. The code the shopper typed. Evaluated again on the basket the server prices, and on an order its use is claimed (so the order's Idempotency-Key also protects the redemption). A code that does not apply is dropped and the totals carry no discount; Quote.discount says why. Never a price from the client.

Lengthlength <= 40
paymentMethod?string

Coming soon. The shopper's pick when the store offers both (store.payments.methods). Checked again against what the store has switched on. eft answers the bank details in payment and needs no POST /v1/store/orders/{id}/pay. Absent is card.

Value in"card""eft"
giftNote?string

Coming soon. A note for the recipient. Kept only when store.giftNotes is true; otherwise ignored.

Lengthlength <= 280
marketingOptIn?boolean

Coming soon. The shopper agrees to marketing mail from the store. Mirrored to the customer record (and the shopper's profile when signed in).

saveAddress?boolean

Coming soon. A signed-in shopper: also save shippingAddress to their address book.

attribution?

Where the order came from, for the merchant's campaign reports. The hosted storefront reads these from its own cookies; a site sends what it kept from the landing URL (se_c is a campaign link's id). Never trusted for price or access: an unknown campaign is dropped. Coming soon.

basketId?string

Coming soon. The saved basket this order was made from (createBasket). It is marked ordered, so it is no longer chased.

Response Body

The order.

application/json
  1. response
data*

The order as placed, plus its access token. accessToken is returned only here.

Example Request
curl -X POST 'https://api.shopeazy.co/v1/store/orders' \  -H 'Authorization: Bearer sez_pub_...' \  -H 'Idempotency-Key: <unique_key>' \  -H 'Content-Type: application/json' \  -d '{  "lines": [    {      "itemId": "65myAK8IFZKwZBG84Gmw",      "quantity": 1    }  ],  "fulfilment": "collect",  "customer": {    "name": "Thandi Mokoena",    "email": "thandi.mokoena@example.com",    "phone": "+27 82 000 0001"  },  "paymentMethod": "card",  "note": "Please wrap it as a gift."}'
Example Response
{  "data": {    "id": "riEhGrBxE2kF04RzXyaz",    "number": "ORD-00001",    "status": "open",    "paymentStatus": "unpaid",    "fulfillmentStatus": "unfulfilled",    "currency": "ZAR",    "totals": {      "subtotal": {        "amount": 32900,        "currency": "ZAR"      },      "discount": {        "amount": 0,        "currency": "ZAR"      },      "shipping": {        "amount": 0,        "currency": "ZAR"      },      "tax": {        "amount": 0,        "currency": "ZAR"      },      "total": {        "amount": 32900,        "currency": "ZAR"      },      "paid": {        "amount": 0,        "currency": "ZAR"      },      "balanceDue": {        "amount": 32900,        "currency": "ZAR"      }    },    "customer": {      "name": "Thandi Mokoena",      "email": "thandi.mokoena@example.com",      "phone": "+27 82 000 0001"    },    "lines": [      {        "itemId": "65myAK8IFZKwZBG84Gmw",        "title": "Monstera deliciosa, 20 cm pot",        "variantTitle": null,        "quantity": 1,        "unitPrice": {          "amount": 32900,          "currency": "ZAR"        },        "customisations": [],        "fulfillmentStatus": "unfulfilled",        "booking": null      }    ],    "createdAt": 1792924396792,    "paidAt": null,    "accessToken": "ord_tok_EXAMPLE"  }}