# Checkout hooks Five frozen decision points on the checkout path (ADR 0020 §4). A hook is a pure function `f(CartSnapshot, config) → HookOp[]`: JSON in, a closed union of operations out — no I/O, no SQL, no fetch. The platform applies the ops with clamps; a throwing or over-budget hook fails OPEN (pricing/shipping/payment.filter) and trips a breaker after 5 consecutive failures (`extension.hook.deactivate`, one-click re-enable). Budgets: snapshot ≤ 128 KB, ops ≤ 20 KB. ## `checkout.cart.validate` Allowed ops (JSON Schema): ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxItems": 50, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "op": { "type": "string", "const": "reject" }, "code": { "type": "string", "pattern": "^[a-z0-9_]{2,40}$" }, "messageCode": { "type": "string", "pattern": "^[a-z0-9_]{2,40}$" }, "lineId": { "type": "string", "maxLength": 16 } }, "required": [ "op", "code", "messageCode" ], "additionalProperties": false }, { "type": "object", "properties": { "op": { "type": "string", "const": "capQty" }, "lineId": { "type": "string", "maxLength": 16 }, "qty": { "type": "integer", "minimum": 1, "maximum": 99 } }, "required": [ "op", "lineId", "qty" ], "additionalProperties": false } ] } } ``` ## `checkout.pricing.adjust` Allowed ops (JSON Schema): ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxItems": 50, "type": "array", "items": { "type": "object", "properties": { "op": { "type": "string", "const": "addDiscount" }, "lineId": { "type": "string", "maxLength": 16 }, "kurus": { "type": "integer", "minimum": 0, "maximum": 10000000000000 }, "label": { "type": "string", "minLength": 1, "maxLength": 60 } }, "required": [ "op", "kurus", "label" ], "additionalProperties": false } } ``` ## `checkout.shipping.rates` Allowed ops (JSON Schema): ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxItems": 50, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "op": { "type": "string", "const": "addRate" }, "id": { "type": "string", "pattern": "^[a-z0-9_-]{1,32}$" }, "labelTR": { "type": "string", "minLength": 1, "maxLength": 60 }, "kurus": { "type": "integer", "minimum": 0, "maximum": 10000000000000 }, "etaDays": { "type": "array", "prefixItems": [ { "type": "integer", "minimum": 0, "maximum": 60 }, { "type": "integer", "minimum": 0, "maximum": 60 } ] } }, "required": [ "op", "id", "labelTR", "kurus" ], "additionalProperties": false }, { "type": "object", "properties": { "op": { "type": "string", "const": "filterRate" }, "id": { "type": "string", "pattern": "^[a-z0-9_-]{1,32}$" } }, "required": [ "op", "id" ], "additionalProperties": false }, { "type": "object", "properties": { "op": { "type": "string", "const": "renameRate" }, "id": { "type": "string", "pattern": "^[a-z0-9_-]{1,32}$" }, "labelTR": { "type": "string", "minLength": 1, "maxLength": 60 } }, "required": [ "op", "id", "labelTR" ], "additionalProperties": false } ] } } ``` ## `checkout.payment.filter` Allowed ops (JSON Schema): ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxItems": 50, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "op": { "type": "string", "const": "exclude" }, "methodId": { "type": "string", "pattern": "^[a-z0-9_]{2,32}$" } }, "required": [ "op", "methodId" ], "additionalProperties": false }, { "type": "object", "properties": { "op": { "type": "string", "const": "reorder" }, "order": { "maxItems": 10, "type": "array", "items": { "type": "string", "pattern": "^[a-z0-9_]{2,32}$" } } }, "required": [ "op", "order" ], "additionalProperties": false }, { "type": "object", "properties": { "op": { "type": "string", "const": "capTaksit" }, "methodId": { "type": "string", "pattern": "^[a-z0-9_]{2,32}$" }, "max": { "type": "integer", "minimum": 1, "maximum": 12 } }, "required": [ "op", "methodId", "max" ], "additionalProperties": false } ] } } ``` ## `checkout.order.validate` Allowed ops (JSON Schema): ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "maxItems": 50, "type": "array", "items": { "type": "object", "properties": { "op": { "type": "string", "const": "reject" }, "code": { "type": "string", "pattern": "^[a-z0-9_]{2,40}$" }, "messageCode": { "type": "string", "pattern": "^[a-z0-9_]{2,40}$" } }, "required": [ "op", "code", "messageCode" ], "additionalProperties": false } } ``` ## Shopper-facing message codes Hooks never emit prose; they emit codes the platform maps to Turkish: | code | TR | |---|---| | `out_of_stock` | Üründe yeterli stok yok. | | `insufficient_stock` | Stok, istediğin adet için yeterli değil. | | `qty_capped` | Bu ürün için adet sınırına ulaşıldı. | | `line_unavailable` | Ürün artık satışta değil ve sepetten çıkarıldı. | | `price_changed` | Fiyat güncellendi — lütfen yeni tutarı kontrol et. | | `shipping_unavailable` | Bu adrese şu anda kargo yapılamıyor. | | `payment_unavailable` | Şu anda ödeme alınamıyor — lütfen daha sonra tekrar dene. | | `digital_kapida_disallowed` | Dijital ürünler kapıda ödeme ile satın alınamaz. | | `session_expired` | Oturumun zaman aşımına uğradı. | | `amount_mismatch` | Ödeme tutarı doğrulanamadı — sipariş oluşturulmadı, kartından çekim yapıldıysa iade edilir. | | `order_rejected` | Sipariş şu anda oluşturulamıyor. | | `checkout_disabled` | Bu mağazada ödeme yakında açılıyor. | | `cart_empty` | Sepetin boş. |