# Kortingscodes

Een cart heeft maximaal één kortingscode. De code wordt letterlijk opgeslagen en bij elke cart-read lazy geëvalueerd: een onbruikbare code koppelen laat de request niet falen. In plaats daarvan rapporteert elke cart-response de uitkomst via twee velden:

- `discount_code_error`: null wanneer de code van toepassing is (of er geen code is gezet), anders een van de onderstaande waarden.
- `discounts[]`: de lijst met kortingen die op dit moment op de cart zijn toegepast, elk als `{id, name, code, kind, amount}` waarbij `kind` een van `order`, `products`, `shipping`, `bogo` is en `amount` een integer in minor units. Automatische (codeloze) kortingen verschijnen hier ook.

| `discount_code_error` | Betekenis |
| --- | --- |
| `invalid` | Er bestaat geen korting met deze code (of hij is inactief). |
| `expired` | Het geldigheidsvenster van de korting is verstreken of nog niet begonnen. |
| `min_order` | Het carttotaal ligt onder de minimale orderwaarde van de korting. |
| `not_eligible` | De cart of klant voldoet niet aan de voorwaarden van de korting. |
| `usage_limit` | De gebruikslimiet van de korting is uitgeput. |

Omdat de evaluatie lazy is, kan een code die vandaag geldig is later `expired` of `usage_limit` worden; lees de cart opnieuw voor de actuele status. Gebruikslimieten worden bij checkout bovendien onder een lock opnieuw gecontroleerd: een code die tussen koppelen en checkout is uitgeput veroorzaakt een 409 cart conflict met een `discount_unavailable`-vermelding (zie de pagina Checkout).

Beide endpoints vereisen `commerce:write`, een `active` cart, en doorlopen de cart-eigenaarschapscheck. Beide geven de volledige cart-envelope terug, dezelfde vorm als `GET /v1/api/commerce/carts/{id}`.

## PUT /v1/api/commerce/carts/{id}/discount-code

Koppelt een kortingscode aan de cart en vervangt een eventueel eerder gekoppelde code. De request slaagt voor elke goed gevormde code; controleer `discount_code_error` en `discounts[]` in de response om te zien of hij van toepassing is.

### Parameters

**Pad**

| Naam | Type | Verplicht | Beschrijving |
| --- | --- | --- | --- |
| `id` | string (UUID) | ja | Cart-id. Moet een `active` cart zijn. |

**Body**

| Naam | Type | Verplicht | Beschrijving |
| --- | --- | --- | --- |
| `code` | string | ja | Max 100 tekens, mag na trimmen niet leeg zijn. |

```bash title="Request"
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"}'
```

```javascript title="Request (JS)"
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
}
```

```json title="Response"
{
  "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}"
  }
}
```

Wanneer de code niet kan worden toegepast, is de response nog steeds 200 met bijvoorbeeld `"discount_code": "SUMMER24", "discount_code_error": "expired", "discounts": []`.

### Fouten

| Status | Body | Wanneer |
| --- | --- | --- |
| 422 | `{"message": "...", "errors": {"code": ["..."]}}` | Code ontbreekt, is leeg na trimmen, of langer dan 100 tekens. |
| 404 | `{"message": "..."}` | Cart onbekend, verlopen of niet `active`. |
| 403 | eigenaarschaps-, scope-, module- of schorsingsbody | Zie de pagina Carts. |
| 429 | `{"message": "Too Many Attempts."}` | Rate limit overschreden. |

## DELETE /v1/api/commerce/carts/{id}/discount-code

Verwijdert de kortingscode van de cart. Automatische (codeloze) kortingen blijven onaangetast en kunnen nog steeds in `discounts[]` verschijnen.

### Parameters

**Pad**

| Naam | Type | Verplicht | Beschrijving |
| --- | --- | --- | --- |
| `id` | string (UUID) | ja | Cart-id. Moet een `active` cart zijn. |

Geen body.

```bash title="Request"
curl -X DELETE https://api.borkol.com/v1/api/commerce/carts/9d3f2a10-6b7c-4e6d-9f21-8a54c1d2e3f4/discount-code \
  -H "Authorization: Bearer {api_key}"
```

```json title="Response"
{
  "data": {
    "id": "9d3f2a10-6b7c-4e6d-9f21-8a54c1d2e3f4",
    "discount_code": null,
    "discount_code_error": null,
    "...": "same cart shape as GET /v1/api/commerce/carts/{id}"
  }
}
```

### Fouten

| Status | Body | Wanneer |
| --- | --- | --- |
| 404 | `{"message": "..."}` | Cart onbekend, verlopen of niet `active`. |
| 403 | eigenaarschaps-, scope-, module- of schorsingsbody | Zie de pagina Carts. |
| 429 | `{"message": "Too Many Attempts."}` | Rate limit overschreden. |
