Orders & Quotes
Orders
Read a single order, list a customer's order history, and the order status machine.
View as MarkdownAn order is created by checkout (or by accepting a quote) in status pending_payment. From the storefront API orders are read-only: all status changes (payment, shipment, refunds) happen merchant-side in the dashboard. Both endpoints require the commerce:read scope and the commerce module.
An order is created by checkout (or by accepting a quote) in status pending_payment. From the storefront API orders are read-only: all status changes (payment, shipment, refunds) happen merchant-side in the dashboard. Both endpoints require the commerce:read scope and the commerce module.
Order status
| Status | Meaning | Can transition to |
|---|---|---|
pending_payment | Created, awaiting payment. | paid, cancelled |
paid | Payment received. | shipped, cancelled, refunded |
shipped | Handed to the carrier; tracking fields may be set. | completed, refunded |
completed | Fulfilled. | refunded |
cancelled | Cancelled before fulfillment. Inventory is restocked. | terminal |
refunded | Refunded. Inventory is restocked. | terminal |
Treat the enum as open: a client should render an unknown future status neutrally rather than fail.
Order status
| Status | Meaning | Can transition to |
|---|---|---|
pending_payment | Created, awaiting payment. | paid, cancelled |
paid | Payment received. | shipped, cancelled, refunded |
shipped | Handed to the carrier; tracking fields may be set. | completed, refunded |
completed | Fulfilled. | refunded |
cancelled | Cancelled before fulfillment. Inventory is restocked. | terminal |
refunded | Refunded. Inventory is restocked. | terminal |
Treat the enum as open: a client should render an unknown future status neutrally rather than fail.
The order response shape
Both endpoints serialize orders identically (single orders wrapped in {"data": {...}}, history entries as elements of a paginated data array). All money values are objects {"amount": int, "currency": "EUR"} with amount in minor units. Dates are ISO-8601 strings.
| Name | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | always | Order id. |
number | integer | always | Human-facing order number from a per-store counter. Plain integer, not a UUID. |
status | string | always | See the status table above. |
email | string | always | The email given at checkout. |
billing_address | object | always | The billing address as submitted (name, street, postal_code, city, country). |
shipping_address | object or null | always | The shipping address, or null when shipping to the billing address. |
currency | string | always | EUR. |
lines | array | always | Order lines, see below. |
subtotal | money | always | Goods total excluding tax. |
tax_total | money | always | Total tax including shipping tax. |
total | money | always | Grand total including shipping. |
tax_breakdown | array | always | Per-rate breakdown, each {"rate": float, "base": int, "tax": int}. |
shipping_method_name | string or null | always | Name snapshot of the chosen shipping method, null when no shipping applied. |
shipping | money | always | Shipping cost excluding tax. amount is null when no shipping applied. |
shipping_tax | money | always | Tax on shipping. amount is null when no shipping applied. |
tracking_carrier | string or null | always | Set by the merchant when shipping. |
tracking_number | string or null | always | Set by the merchant when shipping. |
invoice_number | integer or null | always | Per-store invoice counter, set when the merchant invoices the order. |
invoiced_at | string (ISO-8601) or null | always | When the order was invoiced. |
customer_id | string (UUID) or null | always | The customer the order is bound to, null for guest orders. |
placed_at | string (ISO-8601) or null | always | When the order was placed. |
created_at | string (ISO-8601) or null | always | Row creation time. |
lines[]
| Name | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | always | Order line id. |
product_id | string (UUID) | always | The product. |
variant_id | string (UUID) or null | always | The variant, when applicable. |
variant_label | string or null | always | Human-readable variant label snapshot, for example "Green / M". |
name | string | always | Product name snapshot. |
sku | string or null | always | SKU snapshot. |
quantity | integer | always | Quantity ordered. |
unit_price | money | always | Unit price. |
line_subtotal | money | always | Line total excluding tax. |
tax_rate | number | always | Tax rate percentage applied to the line. |
tax | money | always | Tax on the line. |
line_total | money | always | Line total including tax. |
attributes | object or null | always | Null for plain lines; the configuration snapshot for configurable products. |
The order response shape
Both endpoints serialize orders identically (single orders wrapped in {"data": {...}}, history entries as elements of a paginated data array). All money values are objects {"amount": int, "currency": "EUR"} with amount in minor units. Dates are ISO-8601 strings.
| Name | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | always | Order id. |
number | integer | always | Human-facing order number from a per-store counter. Plain integer, not a UUID. |
status | string | always | See the status table above. |
email | string | always | The email given at checkout. |
billing_address | object | always | The billing address as submitted (name, street, postal_code, city, country). |
shipping_address | object or null | always | The shipping address, or null when shipping to the billing address. |
currency | string | always | EUR. |
lines | array | always | Order lines, see below. |
subtotal | money | always | Goods total excluding tax. |
tax_total | money | always | Total tax including shipping tax. |
total | money | always | Grand total including shipping. |
tax_breakdown | array | always | Per-rate breakdown, each {"rate": float, "base": int, "tax": int}. |
shipping_method_name | string or null | always | Name snapshot of the chosen shipping method, null when no shipping applied. |
shipping | money | always | Shipping cost excluding tax. amount is null when no shipping applied. |
shipping_tax | money | always | Tax on shipping. amount is null when no shipping applied. |
tracking_carrier | string or null | always | Set by the merchant when shipping. |
tracking_number | string or null | always | Set by the merchant when shipping. |
invoice_number | integer or null | always | Per-store invoice counter, set when the merchant invoices the order. |
invoiced_at | string (ISO-8601) or null | always | When the order was invoiced. |
customer_id | string (UUID) or null | always | The customer the order is bound to, null for guest orders. |
placed_at | string (ISO-8601) or null | always | When the order was placed. |
created_at | string (ISO-8601) or null | always | Row creation time. |
lines[]
| Name | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | always | Order line id. |
product_id | string (UUID) | always | The product. |
variant_id | string (UUID) or null | always | The variant, when applicable. |
variant_label | string or null | always | Human-readable variant label snapshot, for example "Green / M". |
name | string | always | Product name snapshot. |
sku | string or null | always | SKU snapshot. |
quantity | integer | always | Quantity ordered. |
unit_price | money | always | Unit price. |
line_subtotal | money | always | Line total excluding tax. |
tax_rate | number | always | Tax rate percentage applied to the line. |
tax | money | always | Tax on the line. |
line_total | money | always | Line total including tax. |
attributes | object or null | always | Null for plain lines; the configuration snapshot for configurable products. |
GET /v1/api/commerce/orders/{id}
Fetches a single order with lines by id. There is no customer-ownership check on this endpoint: it is authorized purely by the tenant API key, which is a server-side secret. It exists for the storefront server, for example rendering the order-confirmation page right after checkout. Never proxy it to browsers with a client-supplied order id unless your server performs its own ownership check first.
Parameters
Path
| Name | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | yes | Order id. |
Errors
| Status | Body | When |
|---|---|---|
| 404 | {"message": "..."} | Unknown or soft-deleted order id, or an order of another store. |
| 403 | scope, module, or suspension body | Key lacks commerce:read, module disabled, or store suspended. |
| 429 | {"message": "Too Many Attempts."} | Rate limit exceeded. |
curl https://api.borkol.com/v1/api/commerce/orders/7f8a9b0c-1d2e-4f3a-b4c5-d6e7f8a9b0c1 \
-H "Authorization: Bearer {api_key}"{
"data": {
"id": "7f8a9b0c-1d2e-4f3a-b4c5-d6e7f8a9b0c1",
"number": 1042,
"status": "paid",
"email": "jane@example.com",
"billing_address": {
"name": "Jane Doe",
"street": "Keizersgracht 1",
"postal_code": "1015 CC",
"city": "Amsterdam",
"country": "NL"
},
"shipping_address": null,
"currency": "EUR",
"lines": [
{
"id": "8a9b0c1d-2e3f-4a4b-c5d6-e7f8a9b0c1d2",
"product_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"variant_id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
"variant_label": "Green / M",
"name": "Garden Chair",
"sku": "CHAIR-GRN-M",
"quantity": 2,
"unit_price": { "amount": 2250, "currency": "EUR" },
"line_subtotal": { "amount": 3347, "currency": "EUR" },
"tax_rate": 21,
"tax": { "amount": 703, "currency": "EUR" },
"line_total": { "amount": 4050, "currency": "EUR" },
"attributes": null
}
],
"subtotal": { "amount": 3347, "currency": "EUR" },
"tax_total": { "amount": 789, "currency": "EUR" },
"total": { "amount": 4545, "currency": "EUR" },
"tax_breakdown": [{ "rate": 21, "base": 3756, "tax": 789 }],
"shipping_method_name": "Standard",
"shipping": { "amount": 409, "currency": "EUR" },
"shipping_tax": { "amount": 86, "currency": "EUR" },
"tracking_carrier": "PostNL",
"tracking_number": "3STEST123456",
"invoice_number": null,
"invoiced_at": null,
"customer_id": null,
"placed_at": "2026-08-14T10:15:30+00:00",
"created_at": "2026-08-14T10:15:30+00:00"
}
}GET /v1/api/commerce/orders/{id}
Fetches a single order with lines by id. There is no customer-ownership check on this endpoint: it is authorized purely by the tenant API key, which is a server-side secret. It exists for the storefront server, for example rendering the order-confirmation page right after checkout. Never proxy it to browsers with a client-supplied order id unless your server performs its own ownership check first.
Parameters
Path
| Name | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | yes | Order id. |
curl https://api.borkol.com/v1/api/commerce/orders/7f8a9b0c-1d2e-4f3a-b4c5-d6e7f8a9b0c1 \
-H "Authorization: Bearer {api_key}"{
"data": {
"id": "7f8a9b0c-1d2e-4f3a-b4c5-d6e7f8a9b0c1",
"number": 1042,
"status": "paid",
"email": "jane@example.com",
"billing_address": {
"name": "Jane Doe",
"street": "Keizersgracht 1",
"postal_code": "1015 CC",
"city": "Amsterdam",
"country": "NL"
},
"shipping_address": null,
"currency": "EUR",
"lines": [
{
"id": "8a9b0c1d-2e3f-4a4b-c5d6-e7f8a9b0c1d2",
"product_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"variant_id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
"variant_label": "Green / M",
"name": "Garden Chair",
"sku": "CHAIR-GRN-M",
"quantity": 2,
"unit_price": { "amount": 2250, "currency": "EUR" },
"line_subtotal": { "amount": 3347, "currency": "EUR" },
"tax_rate": 21,
"tax": { "amount": 703, "currency": "EUR" },
"line_total": { "amount": 4050, "currency": "EUR" },
"attributes": null
}
],
"subtotal": { "amount": 3347, "currency": "EUR" },
"tax_total": { "amount": 789, "currency": "EUR" },
"total": { "amount": 4545, "currency": "EUR" },
"tax_breakdown": [{ "rate": 21, "base": 3756, "tax": 789 }],
"shipping_method_name": "Standard",
"shipping": { "amount": 409, "currency": "EUR" },
"shipping_tax": { "amount": 86, "currency": "EUR" },
"tracking_carrier": "PostNL",
"tracking_number": "3STEST123456",
"invoice_number": null,
"invoiced_at": null,
"customer_id": null,
"placed_at": "2026-08-14T10:15:30+00:00",
"created_at": "2026-08-14T10:15:30+00:00"
}
}Errors
| Status | Body | When |
|---|---|---|
| 404 | {"message": "..."} | Unknown or soft-deleted order id, or an order of another store. |
| 403 | scope, module, or suspension body | Key lacks commerce:read, module disabled, or store suspended. |
| 429 | {"message": "Too Many Attempts."} | Rate limit exceeded. |
GET /v1/api/commerce/my/orders
Paginated order history for the customer identified by X-Customer-Token, sorted by placed_at descending (newest first). The token is mandatory: this is the endpoint behind a storefront's "my orders" page. Uses the standard Laravel pagination envelope.
Parameters
Query
| Name | Type | Required | Description |
|---|---|---|---|
per_page | integer | no | Page size, default 25, clamped to 1..100. |
page | integer | no | Page number, default 1. |
Headers
| Name | Type | Required | Description |
|---|---|---|---|
X-Customer-Token | string | yes | Customer session token. Missing or unresolvable: 401. |
Errors
| Status | Body | When |
|---|---|---|
| 401 | {"message": "Invalid customer token."} | X-Customer-Token missing or unresolvable. |
| 403 | scope, module, or suspension body | Key lacks commerce:read, module disabled, or store suspended. |
| 429 | {"message": "Too Many Attempts."} | Rate limit exceeded. |
curl "https://api.borkol.com/v1/api/commerce/my/orders?per_page=25&page=1" \
-H "Authorization: Bearer {api_key}" \
-H "X-Customer-Token: {customer_token}"const res = await fetch(
"https://api.borkol.com/v1/api/commerce/my/orders?per_page=25",
{
headers: {
Authorization: `Bearer ${apiKey}`,
"X-Customer-Token": customerToken,
},
}
);
const { data: orders, meta } = await res.json();{
"data": [
{
"id": "7f8a9b0c-1d2e-4f3a-b4c5-d6e7f8a9b0c1",
"number": 1042,
"status": "shipped",
"email": "jane@example.com",
"billing_address": {
"name": "Jane Doe",
"street": "Keizersgracht 1",
"postal_code": "1015 CC",
"city": "Amsterdam",
"country": "NL"
},
"shipping_address": null,
"currency": "EUR",
"lines": [
{
"id": "8a9b0c1d-2e3f-4a4b-c5d6-e7f8a9b0c1d2",
"product_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"variant_id": null,
"variant_label": null,
"name": "Garden Chair",
"sku": "CHAIR-GRN",
"quantity": 2,
"unit_price": { "amount": 2250, "currency": "EUR" },
"line_subtotal": { "amount": 3719, "currency": "EUR" },
"tax_rate": 21,
"tax": { "amount": 781, "currency": "EUR" },
"line_total": { "amount": 4500, "currency": "EUR" },
"attributes": null
}
],
"subtotal": { "amount": 3719, "currency": "EUR" },
"tax_total": { "amount": 867, "currency": "EUR" },
"total": { "amount": 4995, "currency": "EUR" },
"tax_breakdown": [{ "rate": 21, "base": 4128, "tax": 867 }],
"shipping_method_name": "Standard",
"shipping": { "amount": 409, "currency": "EUR" },
"shipping_tax": { "amount": 86, "currency": "EUR" },
"tracking_carrier": "PostNL",
"tracking_number": "3STEST123456",
"invoice_number": null,
"invoiced_at": null,
"customer_id": "0a1b2c3d-4e5f-4a6b-7c8d-9e0f1a2b3c4d",
"placed_at": "2026-08-10T14:02:11+00:00",
"created_at": "2026-08-10T14:02:11+00:00"
}
],
"links": {
"first": "https://api.borkol.com/v1/api/commerce/my/orders?page=1",
"last": "https://api.borkol.com/v1/api/commerce/my/orders?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"links": [
{ "url": null, "label": "« Previous", "active": false },
{ "url": "https://api.borkol.com/v1/api/commerce/my/orders?page=1", "label": "1", "active": true },
{ "url": null, "label": "Next »", "active": false }
],
"path": "https://api.borkol.com/v1/api/commerce/my/orders",
"per_page": 25,
"to": 1,
"total": 1
}
}GET /v1/api/commerce/my/orders
Paginated order history for the customer identified by X-Customer-Token, sorted by placed_at descending (newest first). The token is mandatory: this is the endpoint behind a storefront's "my orders" page. Uses the standard Laravel pagination envelope.
Parameters
Query
| Name | Type | Required | Description |
|---|---|---|---|
per_page | integer | no | Page size, default 25, clamped to 1..100. |
page | integer | no | Page number, default 1. |
Headers
| Name | Type | Required | Description |
|---|---|---|---|
X-Customer-Token | string | yes | Customer session token. Missing or unresolvable: 401. |
curl "https://api.borkol.com/v1/api/commerce/my/orders?per_page=25&page=1" \
-H "Authorization: Bearer {api_key}" \
-H "X-Customer-Token: {customer_token}"const res = await fetch(
"https://api.borkol.com/v1/api/commerce/my/orders?per_page=25",
{
headers: {
Authorization: `Bearer ${apiKey}`,
"X-Customer-Token": customerToken,
},
}
);
const { data: orders, meta } = await res.json();{
"data": [
{
"id": "7f8a9b0c-1d2e-4f3a-b4c5-d6e7f8a9b0c1",
"number": 1042,
"status": "shipped",
"email": "jane@example.com",
"billing_address": {
"name": "Jane Doe",
"street": "Keizersgracht 1",
"postal_code": "1015 CC",
"city": "Amsterdam",
"country": "NL"
},
"shipping_address": null,
"currency": "EUR",
"lines": [
{
"id": "8a9b0c1d-2e3f-4a4b-c5d6-e7f8a9b0c1d2",
"product_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"variant_id": null,
"variant_label": null,
"name": "Garden Chair",
"sku": "CHAIR-GRN",
"quantity": 2,
"unit_price": { "amount": 2250, "currency": "EUR" },
"line_subtotal": { "amount": 3719, "currency": "EUR" },
"tax_rate": 21,
"tax": { "amount": 781, "currency": "EUR" },
"line_total": { "amount": 4500, "currency": "EUR" },
"attributes": null
}
],
"subtotal": { "amount": 3719, "currency": "EUR" },
"tax_total": { "amount": 867, "currency": "EUR" },
"total": { "amount": 4995, "currency": "EUR" },
"tax_breakdown": [{ "rate": 21, "base": 4128, "tax": 867 }],
"shipping_method_name": "Standard",
"shipping": { "amount": 409, "currency": "EUR" },
"shipping_tax": { "amount": 86, "currency": "EUR" },
"tracking_carrier": "PostNL",
"tracking_number": "3STEST123456",
"invoice_number": null,
"invoiced_at": null,
"customer_id": "0a1b2c3d-4e5f-4a6b-7c8d-9e0f1a2b3c4d",
"placed_at": "2026-08-10T14:02:11+00:00",
"created_at": "2026-08-10T14:02:11+00:00"
}
],
"links": {
"first": "https://api.borkol.com/v1/api/commerce/my/orders?page=1",
"last": "https://api.borkol.com/v1/api/commerce/my/orders?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"links": [
{ "url": null, "label": "« Previous", "active": false },
{ "url": "https://api.borkol.com/v1/api/commerce/my/orders?page=1", "label": "1", "active": true },
{ "url": null, "label": "Next »", "active": false }
],
"path": "https://api.borkol.com/v1/api/commerce/my/orders",
"per_page": 25,
"to": 1,
"total": 1
}
}Errors
| Status | Body | When |
|---|---|---|
| 401 | {"message": "Invalid customer token."} | X-Customer-Token missing or unresolvable. |
| 403 | scope, module, or suspension body | Key lacks commerce:read, module disabled, or store suspended. |
| 429 | {"message": "Too Many Attempts."} | Rate limit exceeded. |