Checkout API Overview
The Checkout API lets you place orders. It is the write counterpart to the read-only Orders API. Placing an order is a two-step flow, with an optional lookup in between:
- Create a checkout draft from your order lines, delivery address and references — you get back
a
checkoutId. Nothing is placed yet. - (optional) Get the checkout to inspect the delivery options prepared for it, and pick the one you want.
- Submit that
checkoutIdto place the order, optionally pinning the delivery option you chose in step 2.
Steps 1–3 are meant to happen in one sitting. A draft left unsubmitted expires.
This split lets you build, inspect, and choose delivery for a draft before committing it. A created checkout that is never submitted is not an order.
All request/response examples use placeholder values; field names and types match what the API accepts and returns.
Base URL
Section titled “Base URL”https://<store-url>/public/checkout/v1<store-url> is the unique base URL issued to your store as part of onboarding (see
Getting Started → Base URL). All paths below are relative to it.
Authentication
Section titled “Authentication”Every request must be authenticated. You need two credentials on each call:
| Header | Value | Purpose |
|---|---|---|
Authorization |
Bearer <access_token> |
OAuth 2.0 JWT access token |
Ocp-Apim-Subscription-Key |
<your-subscription-key> |
Identifies your subscription at the API gateway |
- The access token must carry the
order:writescope. A token without it is rejected with403 Forbidden. This applies to every checkout endpoint, including theGET. - Tokens are short-lived (currently 30 minutes). Request a new one when the old one expires. See Getting Started → Authentication for the token flow.
Conventions
Section titled “Conventions”- Format: JSON only (
Content-Type: application/json,Accept: application/json). Field names are camelCase. - Enums / type discriminators are strings (e.g.
"MaterialNumber"). - Timestamps are ISO 8601 with an explicit UTC offset, e.g.
2026-05-01T09:32:00+02:00. - Nullable / optional fields may be sent as
nullor omitted; both mean “not supplied”. - Each response carries an
X-Trace-Idheader. Quote it when contacting support — it lets us correlate your request with our logs.
Endpoints
Section titled “Endpoints”| Method | Path | Description |
|---|---|---|
POST |
/checkout/v1/create |
Create a checkout draft; returns the generated checkoutId. |
GET |
/checkout/v1/{checkoutId} |
Get a checkout — its status and the delivery options prepared for it. |
POST |
/checkout/v1/submit |
Submit (place) an existing checkout draft, optionally pinning a delivery option. |
1. Create checkout
Section titled “1. Create checkout”POST /checkout/v1/createCreates a checkout draft from your order. The order is not placed until you submit. The response is the generated checkout identifier — not the full order.
Request body — see CreateCheckout request for every field.
Example request
{ "orderLines": [ { "materialId": { "type": "MaterialNumber", "value": "1000001" }, "quantity": 1, "references": { "deliveryReference": "line-1" } } ], "delivery": { "deliveryAddress": { "name": "Contoso AS", "addressLine1": "Storgata 1", "addressLine2": null, "postCode": "0151", "city": "Oslo", "country": "NO", "contactPersonName": "Ola Nordmann", "phone": "+4722000000", "mobilePhone": "+4790000000", "email": "orders@contoso.example", "globalLocationNumber": null } }, "references": { "billingReference": null, "deliveryReference": null }, "notes": { "messageToSalesDepartment": "Handle as standard delivery." }}A minimal request is just one orderLines entry and a delivery.deliveryAddress
with addressLine1 / postCode / city:
{ "orderLines": [ { "materialId": { "type": "MaterialNumber", "value": "1000001" }, "quantity": 1 } ], "delivery": { "deliveryAddress": { "name": "Contoso AS", "addressLine1": "Storgata 1", "postCode": "0151", "city": "Oslo", "country": "NO", "email": "orders@contoso.example" } }}Responses
| Status | Meaning |
|---|---|
201 Created |
Draft created. Body is the checkout identifier. |
400 Bad Request |
The request body failed validation. See errors[] and Validation rules. |
401 Unauthorized |
Missing or invalid token. |
403 Forbidden |
Token lacks order:write, or you are not entitled to place orders for the soldTo you supplied (ERR_ACCESS). |
422 Unprocessable Entity |
The order was understood but could not be created downstream (ERR_PROCESSING). |
500 Internal Server Error |
Unexpected server error. |
Example response (201 Created)
{ "name": "CheckoutId", "value": "019fd6cac2fd7383ac6d759468e7360c"}Take
valueand pass it ascheckoutIdto get (to inspect delivery options) and submit.
2. Get checkout
Section titled “2. Get checkout”GET /checkout/v1/{checkoutId}Returns a checkout’s current status and the delivery options prepared for it at create time.
Use it to show the available delivery options and let the buyer choose one, then pass the chosen
option’s id to submit as deliveryOptionId. This step is optional — if you
submit without choosing, the first available option is used.
{checkoutId} is the value returned by create.
Responses
| Status | Meaning |
|---|---|
200 OK |
Body is the checkout, including its delivery options. |
401 Unauthorized |
Missing or invalid token. |
403 Forbidden |
Token lacks order:write. |
404 Not Found |
No checkout exists with that id (ERR_NOTFOUND). |
500 Internal Server Error |
Unexpected server error. |
Example response (200 OK)
{ "checkoutId": "019fd6cac2fd7383ac6d759468e7360c", "status": "Created", "delivery": { "options": [ { "id": "do_3f1c9a8b6d2e4f70a1b2c3d4e5f60718", "type": "HomeDelivery", "displayName": "Home delivery (1-3 business days)", "express": false, "price": { "net": 39.2, "vat": 9.8, "gross": 49.0 }, "transporter": "Bring", "collectionPoint": null }, { "id": "do_9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e", "type": "PickupPoint", "displayName": "Pick-up at Narvesen Storgata", "express": false, "price": { "net": 0.0, "vat": 0.0, "gross": 0.0 }, "transporter": "Posten", "collectionPoint": { "id": "1234", "name": "Narvesen Storgata 1", "addressLine": "Storgata 1", "postCode": "0151", "city": "Oslo", "country": "NO" } } ] }}
deliveryisnullwhen the checkout has no prepared delivery snapshot (for example, a checkout that failed during create). The optionidvalues are opaque and specific to this checkout — do not store or reuse them across checkouts; fetch them fresh and pass them straight back to submit.
3. Submit checkout
Section titled “3. Submit checkout”POST /checkout/v1/submitSubmits an existing checkout draft, placing the order. You may pin a delivery option by passing the
id of one of the options from get checkout as deliveryOptionId; omit it to use
the first available option. On success there is no body (204).
Checkout drafts are short-lived. A draft that is not submitted within its validity window expires and can no longer be submitted — you get
422withdetail: "Checkout has expired."and must create a new checkout. Do not create a checkout and then wait on slow user input; create it when the buyer is ready to commit. See Handling failures for the recovery pattern.
Request body
{ "checkoutId": "019fd6cac2fd7383ac6d759468e7360c", "deliveryOptionId": "do_3f1c9a8b6d2e4f70a1b2c3d4e5f60718"}| Field | Type | Required | Description |
|---|---|---|---|
checkoutId |
string | yes | The identifier returned by create. |
deliveryOptionId |
string | null | no | The id of a delivery option from get checkout. Omit (or send null) to use the first available option. |
Responses
| Status | Meaning |
|---|---|
204 No Content |
Checkout submitted; the order is placed. No body. |
400 Bad Request |
checkoutId was empty/whitespace, or the supplied deliveryOptionId is not one of this checkout’s options (ERR_VALIDATION_0001). |
401 Unauthorized |
Missing or invalid token. |
403 Forbidden |
Token lacks order:write. |
404 Not Found |
No checkout exists with that id (ERR_NOTFOUND). |
422 Unprocessable Entity |
The checkout could not be submitted (ERR_PROCESSING) — see table below. |
500 Internal Server Error |
Unexpected server error. |
422 reasons — all returned with code: ERR_PROCESSING, distinguished by detail:
detail |
Cause |
|---|---|
Checkout has expired. |
The draft is too old to submit. Create a new checkout. |
Checkout placement failed. |
Downstream rejected placement (e.g. business-rule failure). |
Checkout submission is already in progress. |
The checkout is already being submitted — do not retry immediately. |
Unsupported checkout state. |
The checkout is in a state that cannot be submitted. |
Choosing a delivery option: a
deliveryOptionIdthat is not one of the options returned by get checkout for this checkout is rejected with400(anerrors[]entry onDeliveryOptionId), not422. The option ids are ephemeral — always take them from a fresh get.
Idempotency: submitting the same
checkoutIdtwice never places a second order. While the first submit is still in flight, a second call returns422(Checkout submission is already in progress.); once the order has been placed, re-submitting returns204again (an idempotent replay — still no second order). Either way, treat204as the single source of truth that the order is placed.
Request models
Section titled “Request models”CreateCheckout request
Section titled “CreateCheckout request”| Field | Type | Required | Description |
|---|---|---|---|
soldTo |
SoldTo | null | no | The customer the order is placed for. Defaults to your own customer. |
orderLines |
OrderLine[] | yes | The items to order. At least one. |
delivery |
Delivery | yes | Where and how the order should be delivered. |
references |
References | null | no | Purchase-order / billing / delivery references. |
notes |
Notes | null | no | Free-text notes for Komplett. |
SoldTo
Section titled “SoldTo”| Field | Type | Required | Description |
|---|---|---|---|
customerId |
string (GUID) | yes | Customer the order is sold to. Must be a valid GUID when soldTo is supplied. |
Most integrations should omit
soldToentirely. Leave it out and the order is placed for your own customer. Supply it only to place an order on behalf of a different customer, which requires an entitlement arranged with Komplett — without one you get403(ERR_ACCESS).
OrderLine
Section titled “OrderLine”| Field | Type | Required | Description |
|---|---|---|---|
materialId |
MaterialId | yes | Identifies the product. |
quantity |
integer | yes | Number of units. Must be greater than zero. |
references |
LineReferences | null | no | Line-level references. |
MaterialId
Section titled “MaterialId”| Field | Type | Required | Description |
|---|---|---|---|
type |
string | yes | Material identifier type. Supported values: "MaterialNumber" and "KomplettPcConfigurationId". |
value |
string | yes | The identifier value. For MaterialNumber this is the material number; for KomplettPcConfigurationId this is the GUID of a Komplett PC configuration, e.g. "a5f6b89d-6096-48cf-9a73-ce2898feb51b". |
LineReferences
Section titled “LineReferences”| Field | Type | Required | Description |
|---|---|---|---|
deliveryReference |
string | null | no | Your reference for this order line. |
Delivery
Section titled “Delivery”| Field | Type | Required | Description |
|---|---|---|---|
deliveryAddress |
DeliveryAddress | yes | The destination address. |
DeliveryAddress
Section titled “DeliveryAddress”Every field marked required is rejected with 400 when missing or empty.
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Recipient name. |
addressLine1 |
string | yes | Street address. |
addressLine2 |
string | null | no | Additional address line. |
postCode |
string | yes | Postal code. |
city |
string | yes | City. |
country |
string | yes | Country (e.g. "NO"). |
contactPersonName |
string | null | no | Contact person at the destination. |
phone |
string | null | no | Phone number. |
mobilePhone |
string | null | no | Mobile number. |
email |
string | yes | Contact email. |
globalLocationNumber |
string | null | no | GLN, if applicable. |
Note —
phone/mobilePhoneasymmetry with Orders. On this request contract bothphoneandmobilePhoneare optional / nullable. On the Orders API response the same two fields on a delivery address are always present (non-null). This asymmetry is deliberate: you may create a checkout without a phone number, but an order that comes back always carries one.
References
Section titled “References”| Field | Type | Required | Description |
|---|---|---|---|
billingReference |
string | null | no | Billing reference. |
deliveryReference |
string | null | no | Delivery reference. |
| Field | Type | Required | Description |
|---|---|---|---|
messageToSalesDepartment |
string | null | no | Free-text message for Komplett’s sales department. |
SubmitCheckout request
Section titled “SubmitCheckout request”| Field | Type | Required | Description |
|---|---|---|---|
checkoutId |
string | yes | The checkout to submit (the value from create). |
deliveryOptionId |
string | null | no | A delivery option id from get checkout; omit to use the first available option. |
Response models
Section titled “Response models”Checkout identifier
Section titled “Checkout identifier”Returned by create on 201.
| Field | Type | Description |
|---|---|---|
name |
string | The identifier’s name; always "CheckoutId". |
value |
string | The generated checkout id. Pass it to get and submit. |
The
checkoutIdis an opaque string — currently 32 lowercase hex characters with no dashes. Do not parse it, assume it is a GUID, or validate its shape; treat it as text and store it whole.
Submit returns no body on success (204 No Content).
GetCheckout response
Section titled “GetCheckout response”Returned by get checkout on 200.
| Field | Type | Description |
|---|---|---|
checkoutId |
string | The checkout’s id. |
status |
string | Checkout state: one of Created, Submitting, Placed, Failed. |
delivery |
DeliveryMenu | null | The prepared delivery options, or null when the checkout has no delivery snapshot. |
DeliveryMenu
Section titled “DeliveryMenu”| Field | Type | Description |
|---|---|---|
options |
DeliveryOption[] | The selectable delivery options for this checkout. |
DeliveryOption
Section titled “DeliveryOption”| Field | Type | Description |
|---|---|---|
id |
string | Opaque, checkout-specific option id. Pass it to submit as deliveryOptionId. |
type |
string | Stable delivery-method type. One of HomeDelivery, BusinessDelivery, Locker, PickupPoint, Mailbox, Electronic, Other. Treat any unrecognised value as Other — new values may be added without notice. |
displayName |
string | Human-readable name for the option. |
express |
boolean | Whether this is an express option. |
price |
Price | The delivery price for this option. |
transporter |
string | null | Transporter name, when known. |
collectionPoint |
CollectionPoint | null | Pickup location, for collection-point options; null otherwise. |
typeanddisplayNameare not unique within a menu. A single checkout regularly returns several options sharing the sametypeand the samedisplayName— four pickup points with identical labels, or two business-delivery options from different transporters at different prices.idis the only unique, selectable value. Never match an option bytypeordisplayName. See Choose a delivery option.
Amounts are in the checkout’s currency (a checkout is single-currency, so the currency is not
repeated per option). The invariant gross = net + vat holds.
| Field | Type | Description |
|---|---|---|
gross |
decimal | Amount including VAT. |
net |
decimal | Amount excluding VAT. |
vat |
decimal | VAT amount. (gross = net + vat) |
CollectionPoint
Section titled “CollectionPoint”| Field | Type | Description |
|---|---|---|
id |
string | Collection-point id. |
name |
string | Collection-point name. |
addressLine |
string | null | Street address. |
postCode |
string | null | Postal code. |
city |
string | null | City. |
country |
string | null | Country. |
Validation rules
Section titled “Validation rules”Validation failures return 400 with code ERR_VALIDATION_0001 and one errors[] entry per
broken rule (see Errors). fieldName is the dotted path to the field.
POST /checkout/v1/create
Section titled “POST /checkout/v1/create”fieldName |
message |
Rule |
|---|---|---|
SoldTo.CustomerId |
CustomerId cannot be null or empty. |
If soldTo is supplied, customerId must be supplied. |
SoldTo.CustomerId |
CustomerId must be a valid GUID. |
If soldTo is supplied, customerId must parse as a GUID. |
OrderLines |
At least one order line is required. |
orderLines must be non-empty. |
OrderLines[i] |
OrderLine cannot be null. |
No entry in orderLines may be null. |
OrderLines[i].Quantity |
Quantity must be greater than zero. |
Each line quantity > 0. |
OrderLines[i].MaterialId |
MaterialId is required. |
Each line must have a materialId. |
OrderLines[i].MaterialId.Value |
MaterialId value is required. |
materialId.value must be supplied. |
OrderLines[i].MaterialId.Type |
Only the 'MaterialNumber' or 'KomplettPcConfigurationId' material type is supported. |
materialId.type must be one of "MaterialNumber" or "KomplettPcConfigurationId". |
Delivery |
Delivery is required. |
delivery object must be present. |
Delivery.DeliveryAddress |
DeliveryAddress is required. |
delivery.deliveryAddress must be present. |
Delivery.DeliveryAddress.Name |
Name cannot be null or empty. |
name must be supplied. |
Delivery.DeliveryAddress.AddressLine1 |
AddressLine1 cannot be null or empty. |
addressLine1 must be supplied. |
Delivery.DeliveryAddress.PostCode |
PostCode cannot be null or empty. |
postCode must be supplied. |
Delivery.DeliveryAddress.City |
City cannot be null or empty. |
city must be supplied. |
Delivery.DeliveryAddress.Country |
Country cannot be null or empty. |
country must be supplied. |
Delivery.DeliveryAddress.Email |
Email cannot be null or empty. |
email must be supplied. |
POST /checkout/v1/submit
Section titled “POST /checkout/v1/submit”fieldName |
message |
Rule |
|---|---|---|
CheckoutId |
CheckoutId cannot be null or empty. |
checkoutId must be supplied. |
DeliveryOptionId |
The selected delivery option is not valid for this checkout. |
If supplied, deliveryOptionId must be one of the options returned by get checkout. Checked against the checkout’s prepared options, but reported the same way as a validation error. |
Errors
Section titled “Errors”All errors use the RFC 9457 / RFC 7807 Problem Details JSON format — the same model as the Orders API.
Problem Details
| Field | Type | Description |
|---|---|---|
type |
string (URI) | Identifies the error category. |
title |
string | Short, human-readable summary of the category. |
detail |
string | Human-readable explanation specific to this occurrence. |
status |
integer | HTTP status code. |
instance |
string | The request path that produced the error. |
code |
string | Stable machine-readable error code (see table below). |
traceId |
string | Correlation id; also returned in the X-Trace-Id header. Quote it to support. |
Validation errors (400) include an additional errors array, one entry per invalid field:
{ "type": "https://<store-url>/swagger#Validation", "title": "Validation Failed", "detail": "Some fields have validation errors", "status": 400, "instance": "/checkout/v1/create", "code": "ERR_VALIDATION_0001", "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01", "errors": [ { "fieldName": "OrderLines[0].Quantity", "message": "Quantity must be greater than zero." } ]}Status / code reference
| HTTP status | code |
When it happens |
|---|---|---|
400 Bad Request |
ERR_VALIDATION_0001 |
A field failed validation. See errors[]. |
401 Unauthorized |
— | Missing, malformed, or expired token / wrong auth scheme. |
403 Forbidden |
ERR_ACCESS |
You are not entitled to place orders for the soldTo you supplied. (A missing order:write scope also yields 403, from the gateway scope check.) |
404 Not Found |
ERR_NOTFOUND |
No checkout exists with the given id (get or submit). |
422 Unprocessable Entity |
ERR_PROCESSING |
The request was understood but could not be processed (create failed downstream; or submit expired / failed / already in progress). |
500 Internal Server Error |
InternalServerError |
Unexpected server error. Retry later; quote the trace id if it persists. |
Quick start
Section titled “Quick start”# 1. Create a checkout draft (returns the checkoutId)curl -s -X POST "https://<store-url>/public/checkout/v1/create" \ -H "Authorization: Bearer <access_token>" \ -H "Ocp-Apim-Subscription-Key: <subscription_key>" \ -H "Content-Type: application/json" \ -d '{ "orderLines": [ { "materialId": { "type": "MaterialNumber", "value": "1000001" }, "quantity": 1 } ], "delivery": { "deliveryAddress": { "name": "Contoso AS", "addressLine1": "Storgata 1", "postCode": "0151", "city": "Oslo", "country": "NO", "email": "orders@contoso.example" } } }'
# 2. (optional) Get the checkout to see its delivery options and choose onecurl -s "https://<store-url>/public/checkout/v1/019fd6cac2fd7383ac6d759468e7360c" \ -H "Authorization: Bearer <access_token>" \ -H "Ocp-Apim-Subscription-Key: <subscription_key>"
# 3. Submit the checkout to place the order# (use the checkoutId from step 1; optionally pin a deliveryOptionId from step 2)curl -s -X POST "https://<store-url>/public/checkout/v1/submit" \ -H "Authorization: Bearer <access_token>" \ -H "Ocp-Apim-Subscription-Key: <subscription_key>" \ -H "Content-Type: application/json" \ -d '{ "checkoutId": "019fd6cac2fd7383ac6d759468e7360c", "deliveryOptionId": "do_3f1c9a8b6d2e4f70a1b2c3d4e5f60718" }'A successful submit returns 204 No Content — the order is placed. To follow the order from there,
use the Orders API (the checkoutId appears on the order as checkoutId).
Worked examples
Section titled “Worked examples”| Guide | What it covers |
|---|---|
| Place a standard order | The default two-step path, start to finish |
| Choose a delivery option | Reading the delivery menu and pinning an option |
| Order a configured Komplett PC | Ordering a saved PC configuration |
| Handling failures and retries | Every error response, and what is safe to retry |