Carts & Checkout
Discount codes
Attach a discount code to a cart, understand lazy evaluation and error codes, and remove the code.
View as MarkdownA cart carries at most one discount code. The code is stored verbatim and evaluated lazily on every cart read: attaching an unusable code does not fail the request. Instead, every cart response reports the outcome through two fields:
discount_code_error: null when the code applies (or no code is set), otherwise one of the values below.discounts[]: the list of discounts currently applied to the cart, each as{id, name, code, kind, amount}wherekindis one oforder,products,shipping,bogoandamountis an integer in minor units. Automatic (codeless) discounts also appear here.
discount_code_error | Meaning |
|---|---|
invalid | No discount with this code exists (or it is inactive). |
expired | The discount's validity window has passed or not started. |
min_order | The cart total is below the discount's minimum order value. |
not_eligible | The cart or customer does not match the discount's conditions. |
usage_limit | The discount's usage limit is exhausted. |
Because evaluation is lazy, a code that is valid today can become expired or usage_limit later; re-read the cart to get the current state. Usage limits are additionally re-checked under a lock at checkout: a code exhausted between attach and checkout causes a 409 cart conflict with a discount_unavailable entry (see the Checkout page).
Both endpoints require commerce:write, an active cart, and pass the cart ownership check. Both return the full cart envelope, the same shape as GET /v1/api/commerce/carts/{id}.
A cart carries at most one discount code. The code is stored verbatim and evaluated lazily on every cart read: attaching an unusable code does not fail the request. Instead, every cart response reports the outcome through two fields:
discount_code_error: null when the code applies (or no code is set), otherwise one of the values below.discounts[]: the list of discounts currently applied to the cart, each as{id, name, code, kind, amount}wherekindis one oforder,products,shipping,bogoandamountis an integer in minor units. Automatic (codeless) discounts also appear here.
discount_code_error | Meaning |
|---|---|
invalid | No discount with this code exists (or it is inactive). |
expired | The discount's validity window has passed or not started. |
min_order | The cart total is below the discount's minimum order value. |
not_eligible | The cart or customer does not match the discount's conditions. |
usage_limit | The discount's usage limit is exhausted. |
Because evaluation is lazy, a code that is valid today can become expired or usage_limit later; re-read the cart to get the current state. Usage limits are additionally re-checked under a lock at checkout: a code exhausted between attach and checkout causes a 409 cart conflict with a discount_unavailable entry (see the Checkout page).
Both endpoints require commerce:write, an active cart, and pass the cart ownership check. Both return the full cart envelope, the same shape as GET /v1/api/commerce/carts/{id}.
PUT /v1/api/commerce/carts/{id}/discount-code
Attaches a discount code to the cart, replacing any previously attached code. The request succeeds for any well-formed code; check discount_code_error and discounts[] in the response to see whether it applied.
Parameters
Path
| Name | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | yes | Cart id. Must be an active cart. |
Body
| Name | Type | Required | Description |
|---|---|---|---|
code | string | yes | Max 100 characters, must be non-blank after trimming. |
When the code cannot apply, the response is still 200 with, for example, "discount_code": "SUMMER24", "discount_code_error": "expired", "discounts": [].
Errors
| Status | Body | When |
|---|---|---|
| 422 | {"message": "...", "errors": {"code": ["..."]}} | Code missing, blank after trim, or longer than 100 characters. |
| 404 | {"message": "..."} | Cart unknown, expired, or not active. |
| 403 | ownership, scope, module, or suspension body | See the Carts page. |
| 429 | {"message": "Too Many Attempts."} | Rate limit exceeded. |
curl -X PUT https://api.borkol.com/v1/api/commerce/carts/9d3f2a10-6b7c-4e6d-9f21-8a54c1d2e3f4/discount-code \
-H "Authorization: Bearer {api_key}" \
-H "Content-Type: application/json" \
-d '{"code": "WELCOME10"}'const res = await fetch(
`https://api.borkol.com/v1/api/commerce/carts/${cartId}/discount-code`,
{
method: "PUT",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ code: "WELCOME10" }),
}
);
const { data: cart } = await res.json();
if (cart.discount_code_error) {
// show why the code did not apply: invalid | expired | min_order | not_eligible | usage_limit
}{
"data": {
"id": "9d3f2a10-6b7c-4e6d-9f21-8a54c1d2e3f4",
"discount_code": "WELCOME10",
"discount_code_error": null,
"discounts": [
{
"id": "71c9e0aa-2f4b-4d31-9a77-0b1c2d3e4f5a",
"name": "Welcome 10%",
"code": "WELCOME10",
"kind": "order",
"amount": 450
}
],
"...": "same cart shape as GET /v1/api/commerce/carts/{id}"
}
}PUT /v1/api/commerce/carts/{id}/discount-code
Attaches a discount code to the cart, replacing any previously attached code. The request succeeds for any well-formed code; check discount_code_error and discounts[] in the response to see whether it applied.
Parameters
Path
| Name | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | yes | Cart id. Must be an active cart. |
Body
| Name | Type | Required | Description |
|---|---|---|---|
code | string | yes | Max 100 characters, must be non-blank after trimming. |
curl -X PUT https://api.borkol.com/v1/api/commerce/carts/9d3f2a10-6b7c-4e6d-9f21-8a54c1d2e3f4/discount-code \
-H "Authorization: Bearer {api_key}" \
-H "Content-Type: application/json" \
-d '{"code": "WELCOME10"}'const res = await fetch(
`https://api.borkol.com/v1/api/commerce/carts/${cartId}/discount-code`,
{
method: "PUT",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ code: "WELCOME10" }),
}
);
const { data: cart } = await res.json();
if (cart.discount_code_error) {
// show why the code did not apply: invalid | expired | min_order | not_eligible | usage_limit
}{
"data": {
"id": "9d3f2a10-6b7c-4e6d-9f21-8a54c1d2e3f4",
"discount_code": "WELCOME10",
"discount_code_error": null,
"discounts": [
{
"id": "71c9e0aa-2f4b-4d31-9a77-0b1c2d3e4f5a",
"name": "Welcome 10%",
"code": "WELCOME10",
"kind": "order",
"amount": 450
}
],
"...": "same cart shape as GET /v1/api/commerce/carts/{id}"
}
}When the code cannot apply, the response is still 200 with, for example, "discount_code": "SUMMER24", "discount_code_error": "expired", "discounts": [].
Errors
| Status | Body | When |
|---|---|---|
| 422 | {"message": "...", "errors": {"code": ["..."]}} | Code missing, blank after trim, or longer than 100 characters. |
| 404 | {"message": "..."} | Cart unknown, expired, or not active. |
| 403 | ownership, scope, module, or suspension body | See the Carts page. |
| 429 | {"message": "Too Many Attempts."} | Rate limit exceeded. |
DELETE /v1/api/commerce/carts/{id}/discount-code
Removes the discount code from the cart. Automatic (codeless) discounts are unaffected and may still appear in discounts[].
Parameters
Path
| Name | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | yes | Cart id. Must be an active cart. |
No body.
Errors
| Status | Body | When |
|---|---|---|
| 404 | {"message": "..."} | Cart unknown, expired, or not active. |
| 403 | ownership, scope, module, or suspension body | See the Carts page. |
| 429 | {"message": "Too Many Attempts."} | Rate limit exceeded. |
curl -X DELETE https://api.borkol.com/v1/api/commerce/carts/9d3f2a10-6b7c-4e6d-9f21-8a54c1d2e3f4/discount-code \
-H "Authorization: Bearer {api_key}"{
"data": {
"id": "9d3f2a10-6b7c-4e6d-9f21-8a54c1d2e3f4",
"discount_code": null,
"discount_code_error": null,
"...": "same cart shape as GET /v1/api/commerce/carts/{id}"
}
}DELETE /v1/api/commerce/carts/{id}/discount-code
Removes the discount code from the cart. Automatic (codeless) discounts are unaffected and may still appear in discounts[].
Parameters
Path
| Name | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | yes | Cart id. Must be an active cart. |
No body.
curl -X DELETE https://api.borkol.com/v1/api/commerce/carts/9d3f2a10-6b7c-4e6d-9f21-8a54c1d2e3f4/discount-code \
-H "Authorization: Bearer {api_key}"{
"data": {
"id": "9d3f2a10-6b7c-4e6d-9f21-8a54c1d2e3f4",
"discount_code": null,
"discount_code_error": null,
"...": "same cart shape as GET /v1/api/commerce/carts/{id}"
}
}Errors
| Status | Body | When |
|---|---|---|
| 404 | {"message": "..."} | Cart unknown, expired, or not active. |
| 403 | ownership, scope, module, or suspension body | See the Carts page. |
| 429 | {"message": "Too Many Attempts."} | Rate limit exceeded. |