Orders
Create and retrieve orders. An API order is written through the same order core as the dashboard and storefront.
Order endpoints require a secret key (ibp_sk_). A publishable key is
rejected with 403 publishable_key_not_allowed.
The pricing model
The API trusts the pricing you send. Item prices, tax (tax, tax_rate, tax_name, tax_inclusive, tax_configured, tax_breakdown), delivery fee, discount, tip, platform_fee, and total are written exactly as provided. The server never recomputes or overrides them, and it never checks that they add up.
What the server computes itself, from product_id references, is internal-only: the cost/COGS snapshot (productRef.costBreakdownSnapshot, not returned by the API) and the stock effect. Your prices are never derived from the catalog.
There is one exception. On a product-linked line with choices, the option upcharge is resolved server-side from the product record and added to your unit_price. The returned unit_price and total for that line therefore include the upcharge and can differ from what you sent. A client-supplied upcharge is never trusted. Lines without choices, and lines without product_id, are untouched.
A line item may or may not reference a product:
- With
product_id- the server attaches the cost snapshot, includes the line in the stock check, and validateschoicesagainst the product. - Without
product_id- a custom one-off line. Your price and name are used as-is, with no cost snapshot, no stock check, and no choice resolution.
Values are still bounds-checked. See Create an order for the limits.
The order model
These are the fields returned by POST /api/v2/orders and GET /api/v2/orders/:id. The list endpoint returns a smaller shape, documented separately below.
Properties
- Name
id- Type
- string
- Description
Unique identifier for the order.
- Name
order_number- Type
- integer
- Description
Sequential order number.
nullon records that never received one.
- Name
friendly_order_number- Type
- string
- Description
Display-friendly order number (e.g. "0141").
- Name
external_id- Type
- string
- Description
Your own reference, persisted and round-tripped.
nullwhen not supplied.
- Name
status- Type
- string
- Description
Order status. See Reference Data for the enum.
- Name
payment_status- Type
- string
- Description
Payment status. Derived from recorded payments when payments are attached.
- Name
payment_method- Type
- string
- Description
Order-level payment method, or
null.
- Name
title- Type
- string
- Description
Human title for the order, or
null.
- Name
event_category- Type
- string
- Description
Event category (e.g. "Wedding"), or
null.
- Name
tags- Type
- array
- Description
Order tags. Array of strings,
[]when none.
- Name
priority- Type
- string
- Description
Order priority. Defaults to
normalon create.
- Name
assigned_to- Type
- string
- Description
Assignee reference, or
null.
- Name
customer- Type
- object
- Description
id,first_name,last_name,email,phone,company,tags.
- Name
items- Type
- array
- Description
Line items. Each carries
id,name,quantity,unit_price,total,product_id,variant_id,description,category,unit,notes,special_instructions,customizations,custom_field_values,allergens,may_contain,processed_in,images, andchoices. Each entry inchoicesis{ choice_id, selected_option_id, choice_name, selected_option_name }.
- Name
pricing- Type
- object
- Description
subtotal,tax,tax_rate,tax_name,tax_inclusive,tax_breakdown,delivery_fee,platform_fee,discount,tip,total,currency.
- Name
discount- Type
- object
- Description
Structured discount, or
null:type,value,amount,code,reason,visible_to_customer.
- Name
payment_schedule- Type
- array
- Description
Schedule stages:
id,name,type,amount,percentage,due_date,status,description.[]when none.
- Name
amount_paid- Type
- number
- Description
Total recorded as paid.
- Name
balance_due- Type
- number
- Description
max(0, pricing.total - amount_paid). Never negative, so an overpayment reports0rather than a credit.
- Name
delivery- Type
- object
- Description
type(pickup,delivery, ordispatch),fulfillment_method,address,date,time,time_slot_id,time_slot_label,actual_delivery_time,notes,shipping_rate.
- Name
delivery.address- Type
- object
- Description
Fixed field set, or
null:line1,line2,city,state,postal_code,country,formatted. Individual fields may benull. Manually typed and geocode-failed addresses carry the readable address informattedonly. Coordinates and place ids are not exposed.
- Name
delivery.shipping_rate- Type
- object
- Description
Applied carrier rate, or
null:provider_id,rate_id,id,service,label,carrier,currency,amount. Only the keys that were stored are present.
- Name
dates- Type
- object
- Description
event,due,created,updated.createdandupdatedare ISO 8601 instants.eventanddueare calendar dates and pass through as stored, normallyYYYY-MM-DD.
- Name
notes- Type
- object
- Description
public,allergy,delivery. Back-of-house staff notes are deliberately not exposed by the API.
- Name
custom_fields- Type
- object
- Description
Order-level custom-field answers, keyed by definition id. Definitions flagged internal are excluded, and a value whose definition cannot be resolved is dropped. The map is
{}when nothing is exposable.
- Name
source- Type
- string
- Description
Origin marker.
apion orders created through this endpoint.
- Name
channel- Type
- string
- Description
Canonical order channel:
dashboard,storefront,wholesale,headless_checkout,shopify,import,pos,api. Orders created throughPOST /api/v2/ordersare alwaysapi; orders created through the hosted checkout session areheadless_checkout.nullon orders written before the field existed - read that as unknown.
- Name
created- Type
- string
- Description
ISO 8601. Same value as
dates.created.
- Name
updated- Type
- string
- Description
ISO 8601. Same value as
dates.updated.
Item-level custom_field_values is filtered the same way as custom_fields, against the product-scoped definitions. Internal-flagged and unresolvable values are dropped.
List all orders
Retrieve a page of orders. Soft-deleted orders are excluded.
Required scope: orders:read
Query parameters
- Name
limit- Type
- integer
- Description
Number of orders to return (default: 50, max: 100).
- Name
cursor- Type
- string
- Description
Pagination cursor from a previous response's
next_cursor.
- Name
status- Type
- string
- Description
Filter by status. Comma-separated for multiple (e.g.
confirmed,in_production).
- Name
customer_id- Type
- string
- Description
Filter by customer id. Matches the order's stored
customerId.
- Name
created_after- Type
- string
- Description
Return orders whose
createdAtis greater than or equal to this instant (ISO 8601). Applied server-side.
- Name
created_before- Type
- string
- Description
Return orders whose
createdAtis less than or equal to this instant (ISO 8601). Applied server-side.
- Name
sort- Type
- string
- Description
createdAtorupdatedAt, in either spelling (created_at,updated_at). Prefix with-for descending. Default:-createdAt. An unrecognised field falls back tocreatedAt.
List item fields
A list entry is a summary, not the full order: id, order_number,
friendly_order_number, external_id, status, payment_status,
priority, customer_first_name, customer_last_name, customer_id,
items_count, total, currency, event_date, created, source.
Fetch the order by id for items, pricing detail, delivery, and
channel.
Errors
400 invalid_value-created_afterorcreated_beforeis not a parseable date.400 unsupported_filter_sort_combination-created_afterorcreated_beforewas combined with a sort other thancreatedAt. A created-date range can only be returned increatedAtorder.400 invalid_cursor- the cursor is malformed, or it decodes to an order that no longer exists. Restart the list without a cursor rather than treating this as end-of-list.
Request
curl -G https://au.api.ibakepro.com/api/v2/orders \
-H "Authorization: Bearer {secret_key}" \
-d status=confirmed \
-d limit=10
Response
{
"data": [
{
"id": "Qm4TdvR7yKcB2sNxLpE9",
"order_number": 141,
"friendly_order_number": "0141",
"external_id": null,
"status": "confirmed",
"payment_status": "paid",
"priority": "normal",
"customer_first_name": "Jane",
"customer_last_name": "Doe",
"customer_id": "cust_36cfd704-5f2a-4c1e-9b7d-2e8a1c9f4b60",
"items_count": 3,
"total": 125.00,
"currency": "AUD",
"event_date": "2026-02-14",
"created": "2026-01-15T10:30:00.000Z",
"source": "api"
}
],
"pagination": {
"limit": 10,
"has_more": true,
"next_cursor": "eyJpZCI6IlFtNFRkdlI3eUtjQjJzTnhMcEU5In0",
"prev_cursor": null
}
}
Create an order
Create an order. The minimum body is customer.first_name, customer.email, one items[] entry, and pricing.total.
Required scope: orders:write
Send an Idempotency-Key header so a retry never creates a duplicate. See Authentication.
Required attributes
- Name
customer.first_name- Type
- string
- Description
Customer first name.
- Name
customer.email- Type
- string
- Description
Customer email. Stored on the order as contact detail only. It does not match, link, or create a customer record: only
customer.idlinks an order to a customer.
- Name
items- Type
- array
- Description
At least one line item.
- Name
pricing.total- Type
- number
- Description
Order total. Trusted verbatim. Must be present, but may be
0.
Customer
- Name
customer.id- Type
- string
- Description
Link to an existing customer instead of matching by email. Must resolve to a customer in your account.
- Name
customer.last_name- Type
- string
- Description
Customer last name. Stored as "" when omitted.
- Name
customer.phone- Type
- string
- Description
Customer phone. Stored as "" when omitted.
- Name
customer.company- Type
- string
- Description
Company name. Stored as
nullwhen omitted.
- Name
customer.tags- Type
- array
- Description
Strings, denormalised onto the order.
Line items
- Name
items[].name- Type
- string
- Description
Line name.
- Name
items[].quantity- Type
- number
- Description
Defaults to
1. Fractional values are allowed (sell-by-weight lines).
- Name
items[].unit_price- Type
- number
- Description
Per-unit price. The stored line
totalisunit_price * quantity; atotalyou send is bounds-checked but not used.
- Name
items[].product_id- Type
- string
- Description
Link the line to a catalog product. Enables the cost snapshot, the stock check, and choice validation.
- Name
items[].variant_id- Type
- string
- Description
Variant id. Omit or send
basefor the base variant.
- Name
items[].choices- Type
- array
- Description
{ choice_id, selected_option_id }. Validated server-side against the product: required choices must be present, options must exist and be enabled, and the resolved upcharge is added tounit_price. Sendingchoiceson a product with no choices is rejected.
- Name
items[].id- Type
- string
- Description
Your own line id. Passed through and returned. Lines you do not id are returned with
id: null.
- Name
items[].description- Type
- string
- Description
Free-text line description.
- Name
items[].category- Type
- string
- Description
Free-text line category.
- Name
items[].unit- Type
- string
- Description
Defaults to
piece.
- Name
items[].notes- Type
- string
- Description
Line note.
- Name
items[].special_instructions- Type
- string
- Description
Production instructions for the line.
- Name
items[].customizations- Type
- array
- Description
Free-form customisation entries, stored and returned as sent.
- Name
items[].custom_field_values- Type
- object
- Description
Product-scoped custom-field answers, keyed by definition id. Values whose definition is internal or unresolvable are dropped from the response.
- Name
items[].allergens- Type
- array
- Description
Declared allergens for a line the server cannot derive them for.
- Name
items[].may_contain- Type
- array
- Description
May-contain allergens.
- Name
items[].processed_in- Type
- array
- Description
Processed-in allergens.
- Name
items[].images- Type
- array
- Description
Reference images for the line, stored and returned as sent.
Other optional attributes
- Name
external_id- Type
- string
- Description
Your reference. Persisted and returned.
- Name
status- Type
- string
- Description
Initial status (default
pending). Must be a valid order status.
- Name
payment_status- Type
- string
- Description
Must be a valid payment status. Ignored when a
payment/paymentsblock is supplied.
- Name
payment_method- Type
- string
- Description
Order-level payment method.
- Name
pricing- Type
- object
- Description
subtotal,tax,tax_rate,tax_name,tax_inclusive,tax_configured,tax_breakdown,shipping(alias fordelivery_fee),platform_fee,discount,tip,total,currency. Omitted numeric fields store as0; omittedcurrencystores asnull.
- Name
discount- Type
- object
- Description
{ type: "percentage" | "fixed", value, amount?, code, reason, visible_to_customer }. Whenamountis omitted it is derived fromvalueand the subtotal.
- Name
delivery- Type
- object
- Description
method(pickup|delivery|dispatch; anything else stores aspickup),fulfillment_method,address,date,time,time_slot_id,time_slot_label,actual_delivery_time,notes,shipping_rate.timeis dropped whenmethodisdispatch.
- Name
delivery.shipping_rate- Type
- object
- Description
{ provider_id, rate_id, id, service, label, carrier, currency, amount }. A dispatch order needsprovider_id, or a provider-prefixedrate_id/idsuch asauspost:..., for its carrier to be resolvable.
- Name
payment_schedule- Type
- array
- Description
{ id?, name, type, amount, percentage, due_date, description, status? }.typedefaults topayment.
- Name
dates.event- Type
- string
- Description
Event date. Falls back to
delivery.datewhen omitted.
- Name
dates.due- Type
- string
- Description
Due date.
- Name
dates.created- Type
- string
- Description
Backdate a historical import. Must be a parseable date; it is stored normalised to UTC ISO 8601.
- Name
notes- Type
- object
- Description
public,internal,allergy,delivery. All four are stored;internalis never returned by the API.
- Name
custom_fields- Type
- object
- Description
Order-level custom-field answers, keyed by definition id.
- Name
tags- Type
- array
- Description
Order tags.
- Name
priority- Type
- string
- Description
Defaults to
normal.
- Name
assigned_to- Type
- string
- Description
Assignee reference. Stored as
nullwhen omitted.
- Name
title- Type
- string
- Description
Human title for the order.
- Name
event_category- Type
- string
- Description
Event category, returned as
event_category.
- Name
payment / payments- Type
- object | array
- Description
Record one or more payments on create. See below.
Validation
Trusted pricing does not mean unbounded. A create is rejected with 400 when:
customer.email,customer.first_name,items, orpricing.totalis missing.customer.idis supplied but no such customer exists in your account. Code:customer_not_found.statusorpayment_statusis outside its enum.discount.typeis notpercentageorfixed.- Any of
items[].unit_price,items[].total,pricing.subtotal,pricing.tax,pricing.delivery_fee,pricing.shipping,pricing.platform_fee,pricing.tip,pricing.totalis non-numeric, negative, or greater than100000000. items[].quantityis not greater than0, or is greater than10000.dates.createdis not a parseable date.- Customer choices on a product-linked line fail validation.
Other failure modes:
403 limit_reached(rate_limit_error) when your plan's order limit is reached. The body carrieslimit,current, andmax.500 internal_errorif the order cannot be written.
Request
curl -X POST https://au.api.ibakepro.com/api/v2/orders \
-H "Authorization: Bearer {secret_key}" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-0001" \
-d '{
"customer": { "first_name": "Jane", "email": "jane@example.com" },
"items": [
{ "name": "Chocolate Birthday Cake", "quantity": 1, "unit_price": 85.00,
"product_id": "prod_ze9HI0w0LpVbemUI" }
],
"pricing": { "subtotal": 85.00, "total": 85.00, "currency": "AUD" }
}'
Response (201)
{
"id": "HR7Pcz4Arg6kvZKseSil",
"order_number": 141,
"friendly_order_number": "0141",
"external_id": null,
"status": "pending",
"payment_status": "pending",
"payment_method": null,
"title": null,
"event_category": null,
"tags": [],
"priority": "normal",
"assigned_to": null,
"customer": {
"id": "cust_36cfd704-5f2a-4c1e-9b7d-2e8a1c9f4b60",
"first_name": "Jane", "last_name": "",
"email": "jane@example.com", "phone": "", "company": null, "tags": []
},
"items": [
{ "id": null, "name": "Chocolate Birthday Cake", "quantity": 1,
"unit_price": 85.00, "total": 85.00,
"product_id": "prod_ze9HI0w0LpVbemUI", "variant_id": "base",
"description": "", "category": "", "unit": "piece",
"notes": "", "special_instructions": "",
"customizations": [], "custom_field_values": {},
"allergens": [], "may_contain": [], "processed_in": [],
"images": [], "choices": [] }
],
"pricing": {
"subtotal": 85.00, "tax": 0, "tax_rate": 0, "tax_name": null,
"tax_inclusive": null, "tax_breakdown": null,
"delivery_fee": 0, "platform_fee": 0,
"discount": 0, "tip": 0, "total": 85.00, "currency": "AUD"
},
"discount": null,
"payment_schedule": [],
"amount_paid": 0,
"balance_due": 85.00,
"delivery": {
"type": "pickup", "fulfillment_method": null, "address": null,
"date": null, "time": null, "time_slot_id": null,
"time_slot_label": "", "actual_delivery_time": null,
"notes": "", "shipping_rate": null
},
"dates": { "event": null, "due": null,
"created": "2026-06-09T04:25:29.969Z", "updated": "2026-06-09T04:25:29.969Z" },
"notes": { "public": "", "allergy": "", "delivery": "" },
"custom_fields": {},
"source": "api",
"channel": "api",
"created": "2026-06-09T04:25:29.969Z",
"updated": "2026-06-09T04:25:29.969Z"
}
Recording payments on create
A secret key may record one or more payments in the same create request, for example importing an order that was already paid, or attaching a deposit. This is the only payments-write surface in v2.
Use payment for a single payment, or payments: [...] for several. When both are present, payments wins.
Payment webhooks are off by default on this endpoint. A payment recorded
during POST /api/v2/orders emits no payment.created, payment.completed,
or payment.failed event unless the request body sets emit_webhooks: true.
Subscribing an endpoint to those events is not enough. The default exists so a
bulk import does not fan out one webhook per historical payment. It does not
affect order.created, which is emitted for every successful create.
Payment fields
- Name
amount- Type
- number
- Description
Required. Must be greater than
0and no greater than100000000.
- Name
method- Type
- string
- Description
One of
card,credit_card,bank_transfer,wire_transfer,cash,check,cheque,paypal,apple_pay,google_pay,afterpay,klarna,store_credit,imported,other. Matching is case-insensitive.credit_cardmaps tocard,wire_transfertobank_transfer,chequetocheck. Any other value, including an omitted one, maps toother.
- Name
status- Type
- string
- Description
pending,completed, orapproved. Defaultcompleted. Any other value is rejected with400: refunds, disputes, failures, and cancellations are lifecycle transitions, not create-time inputs. Onlycompletedandapprovedpayments moveamount_paidandpayment_status.
- Name
paid_date- Type
- string
- Description
ISO 8601. A
completedpayment with nopaid_dateis timestamped now.
- Name
currency- Type
- string
- Description
Must match
pricing.currencywhen both are supplied. Defaults to the order currency.
- Name
tip_amount- Type
- number
- Description
Bounds-checked like any money field.
- Name
fee_amount- Type
- number
- Description
Gateway or processing fee recorded against the payment.
- Name
reference- Type
- string
- Description
Your manual reference.
- Name
transaction_id- Type
- string
- Description
Gateway transaction id.
- Name
description- Type
- string
- Description
Defaults to
API payment.
- Name
notes- Type
- string
- Description
Free-text note stored against the payment.
- Name
emit_webhooks- Type
- boolean
- Description
Top-level flag, not per payment. Defaults to
false, so payments recorded on create emit nopayment.*webhooks at all. Sendemit_webhooks: trueto receive them. This gates payment events only; theorder.createdevent fires either way.
Behaviour
- Payments are recorded after the order is created, so
payment_status,amount_paid,balance_due, and quote auto-conversion are derived for you. An explicitpayment_statuson the create body is ignored whenever a payment block is present. - Payment recording is non-fatal. If the order is created but a payment
fails, you still get
201with the order pluspayment_errors: [{ index, error }], andpayment_idsfor any that succeeded. Retrying with the sameIdempotency-Keyreplays that same response. warnings[]carries non-fatal notices. It appears when recorded payments exceed the order total (allowed for a trusted key, but surfaced), and when the order could not be re-read after payment, in which caseamount_paidis derived from the recorded payments andpayment_statusmay lag.payment_ids,payment_errors, andwarningsare absent from the response when empty.- No
payment.*webhook is emitted unlessemit_webhooksistrue. See the note above.
Request
curl -X POST https://au.api.ibakepro.com/api/v2/orders \
-H "Authorization: Bearer {secret_key}" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-paid-0001" \
-d '{
"customer": { "first_name": "Jane", "email": "jane@example.com" },
"items": [ { "name": "Chocolate Birthday Cake", "quantity": 1,
"unit_price": 85.00 } ],
"pricing": { "subtotal": 85.00, "total": 85.00, "currency": "AUD" },
"payment": { "amount": 85.00, "method": "cash",
"paid_date": "2026-06-01T00:00:00Z" }
}'
Response fragment (201)
{
"id": "HR7Pcz4Arg6kvZKseSil",
"payment_status": "paid",
"amount_paid": 85,
"balance_due": 0,
"payment_ids": ["kQ2mA8f1XbTn0pLdWc7e"]
}
Retrying a create
The Idempotency-Key reservation is released when a request fails, so a create rejected with 400, 403, or 500 can be retried immediately with the same key. Only a request that reached a response worth replaying holds its key for the full 24 hours. A successful create is replayed with Idempotent-Replayed: true.
Retrieve an order
Retrieve a single order by id. Returns the same shape as the create response, without payment_ids, payment_errors, or warnings.
Required scope: orders:read
Returns 404 not_found when the order does not exist, is soft-deleted, or belongs to another account.
Request
curl https://au.api.ibakepro.com/api/v2/orders/HR7Pcz4Arg6kvZKseSil \
-H "Authorization: Bearer {secret_key}"
Building an order from the catalog
GET /api/v2/productsto list, orGET /api/v2/products/{id}for detail.- Take the
id(product_id), avariants[].id(variant_id), and for each required choice achoices[].idplus anoptions[].id. POST /api/v2/orderswith those, plus yourpricing. The server validates the choices, adds the resolved option upcharges to your line prices, attaches the cost snapshot, and writes the order.
All required choices must be included or the create returns 400.
There is no update, cancel, delete, or batch-create endpoint for orders in v2.
An order is changed only in the dashboard after creation, and each order is a
separate POST with its own Idempotency-Key.