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 validates choices against 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. null on 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. null when 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 normal on 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, and choices. Each entry in choices is { 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 reports 0 rather than a credit.

  • Name
    delivery
    Type
    object
    Description

    type (pickup, delivery, or dispatch), 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 be null. Manually typed and geocode-failed addresses carry the readable address in formatted only. 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. created and updated are ISO 8601 instants. event and due are calendar dates and pass through as stored, normally YYYY-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. api on orders created through this endpoint.

  • Name
    channel
    Type
    string
    Description

    Canonical order channel: dashboard, storefront, wholesale, headless_checkout, shopify, import, pos, api. Orders created through POST /api/v2/orders are always api; orders created through the hosted checkout session are headless_checkout. null on 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.


GET/api/v2/orders

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 createdAt is greater than or equal to this instant (ISO 8601). Applied server-side.

  • Name
    created_before
    Type
    string
    Description

    Return orders whose createdAt is less than or equal to this instant (ISO 8601). Applied server-side.

  • Name
    sort
    Type
    string
    Description

    createdAt or updatedAt, in either spelling (created_at, updated_at). Prefix with - for descending. Default: -createdAt. An unrecognised field falls back to createdAt.

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_after or created_before is not a parseable date.
  • 400 unsupported_filter_sort_combination - created_after or created_before was combined with a sort other than createdAt. A created-date range can only be returned in createdAt order.
  • 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

GET
/api/v2/orders
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
  }
}

POST/api/v2/orders

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.id links 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 null when 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 total is unit_price * quantity; a total you 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 base for 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 to unit_price. Sending choices on 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 / payments block 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 for delivery_fee), platform_fee, discount, tip, total, currency. Omitted numeric fields store as 0; omitted currency stores as null.

  • Name
    discount
    Type
    object
    Description

    { type: "percentage" | "fixed", value, amount?, code, reason, visible_to_customer }. When amount is omitted it is derived from value and the subtotal.

  • Name
    delivery
    Type
    object
    Description

    method (pickup | delivery | dispatch; anything else stores as pickup), fulfillment_method, address, date, time, time_slot_id, time_slot_label, actual_delivery_time, notes, shipping_rate. time is dropped when method is dispatch.

  • Name
    delivery.shipping_rate
    Type
    object
    Description

    { provider_id, rate_id, id, service, label, carrier, currency, amount }. A dispatch order needs provider_id, or a provider-prefixed rate_id / id such as auspost:..., for its carrier to be resolvable.

  • Name
    payment_schedule
    Type
    array
    Description

    { id?, name, type, amount, percentage, due_date, description, status? }. type defaults to payment.

  • Name
    dates.event
    Type
    string
    Description

    Event date. Falls back to delivery.date when 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; internal is 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 null when 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, or pricing.total is missing.
  • customer.id is supplied but no such customer exists in your account. Code: customer_not_found.
  • status or payment_status is outside its enum.
  • discount.type is not percentage or fixed.
  • Any of items[].unit_price, items[].total, pricing.subtotal, pricing.tax, pricing.delivery_fee, pricing.shipping, pricing.platform_fee, pricing.tip, pricing.total is non-numeric, negative, or greater than 100000000.
  • items[].quantity is not greater than 0, or is greater than 10000.
  • dates.created is 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 carries limit, current, and max.
  • 500 internal_error if the order cannot be written.

Request

POST
/api/v2/orders
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 0 and no greater than 100000000.

  • 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_card maps to card, wire_transfer to bank_transfer, cheque to check. Any other value, including an omitted one, maps to other.

  • Name
    status
    Type
    string
    Description

    pending, completed, or approved. Default completed. Any other value is rejected with 400: refunds, disputes, failures, and cancellations are lifecycle transitions, not create-time inputs. Only completed and approved payments move amount_paid and payment_status.

  • Name
    paid_date
    Type
    string
    Description

    ISO 8601. A completed payment with no paid_date is timestamped now.

  • Name
    currency
    Type
    string
    Description

    Must match pricing.currency when 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 no payment.* webhooks at all. Send emit_webhooks: true to receive them. This gates payment events only; the order.created event 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 explicit payment_status on 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 201 with the order plus payment_errors: [{ index, error }], and payment_ids for any that succeeded. Retrying with the same Idempotency-Key replays 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 case amount_paid is derived from the recorded payments and payment_status may lag.
  • payment_ids, payment_errors, and warnings are absent from the response when empty.
  • No payment.* webhook is emitted unless emit_webhooks is true. See the note above.

Request

POST
/api/v2/orders
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.


GET/api/v2/orders/:id

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

GET
/api/v2/orders/HR7Pcz4Arg6kvZKseSil
curl https://au.api.ibakepro.com/api/v2/orders/HR7Pcz4Arg6kvZKseSil \
  -H "Authorization: Bearer {secret_key}"

Building an order from the catalog

  1. GET /api/v2/products to list, or GET /api/v2/products/{id} for detail.
  2. Take the id (product_id), a variants[].id (variant_id), and for each required choice a choices[].id plus an options[].id.
  3. POST /api/v2/orders with those, plus your pricing. 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.