{"openapi":"3.0.3","info":{"title":"EasyAI Rewards API","version":"1.0.0","description":"External API: POS contract, public customer API and validator API."},"servers":[{"url":"https://api.easyrewards.easyaidev.com"}],"components":{"securitySchemes":{"PosHmac":{"type":"apiKey","in":"header","name":"X-Signature","description":"HMAC-SHA256 hex of `<X-Timestamp>.<METHOD>.<path+query>.<sha256hex(body)>` using the API key secret. Send X-Api-Key-Id and X-Timestamp (unix seconds, ±300s)."},"Bearer":{"type":"http","scheme":"bearer","bearerFormat":"JWT"},"CustomerBearer":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Customer token from POST /v1/public/customers/otp/verify (audience `customer`, 60 minutes). Staff tokens are rejected."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"nullable":true},"requestId":{"type":"string"}},"required":["code","message"]}},"required":["error"]},"RedeemRewardRequest":{"type":"object","properties":{"order":{"type":"object","properties":{"context":{"type":"object","properties":{"tenantId":{"type":"string","minLength":1},"branchId":{"type":"string","minLength":1},"terminalId":{"type":"string","minLength":1},"cashierId":{"type":"string","minLength":1},"currency":{"type":"string","minLength":3,"maxLength":3,"default":"QAR"},"occurredAt":{"type":"string","format":"date-time"}},"required":["tenantId","branchId","terminalId","occurredAt"]},"posOrderId":{"type":"string","minLength":1},"channel":{"type":"string","enum":["dine_in","takeaway","delivery","online","retail"],"default":"retail"},"customerRef":{"type":"string"},"lines":{"type":"array","items":{"type":"object","properties":{"lineId":{"type":"string"},"sku":{"type":"string"},"categoryIds":{"type":"array","items":{"type":"string"},"default":[]},"quantity":{"type":"number","minimum":0,"exclusiveMinimum":true},"unitPrice":{"type":"number","minimum":0},"lineDiscount":{"type":"number","minimum":0,"default":0},"categoryName":{"type":"string","minLength":1,"maxLength":120},"categories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":120},"name":{"type":"string","minLength":1,"maxLength":120}},"required":["id","name"]},"maxItems":20}},"required":["lineId","sku","quantity","unitPrice"]},"minItems":1},"subtotal":{"type":"number","minimum":0},"paymentMethods":{"type":"array","items":{"type":"string"},"default":[]},"promotionCodes":{"type":"array","items":{"type":"string","minLength":1,"maxLength":40},"maxItems":5}},"required":["context","posOrderId","lines","subtotal"]},"rewardId":{"type":"string","minLength":1},"idempotencyKey":{"type":"string","minLength":8},"capabilities":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":20}},"required":["order","rewardId","idempotencyKey"]},"CustomerOtpRequest":{"type":"object","properties":{"tenant":{"type":"string","description":"Tenant slug (tenant or campaign is required)"},"campaign":{"type":"string","description":"Campaign publicId"},"phone":{"type":"string","pattern":"^\\+?[1-9]\\d{7,14}$"},"locale":{"type":"string","enum":["en","ar"],"default":"ar"}},"required":["phone"]},"CustomerOtpVerify":{"type":"object","properties":{"tenant":{"type":"string","description":"Tenant slug (tenant or campaign is required)"},"campaign":{"type":"string","description":"Campaign publicId"},"phone":{"type":"string","pattern":"^\\+?[1-9]\\d{7,14}$"},"code":{"type":"string","pattern":"^\\d{6}$"},"acceptTerms":{"type":"boolean"},"device":{"type":"object","properties":{"id":{"type":"string"},"platform":{"type":"string","enum":["ios","android","web"]},"name":{"type":"string"}},"required":["id","platform"],"description":"Customer app: also issue a rotating device refresh token (400-day sliding session)"}},"required":["phone","code"]},"CustomerLinkRedeem":{"type":"object","properties":{"token":{"type":"string"},"tenant":{"type":"string"},"device":{"type":"object","properties":{"id":{"type":"string"},"platform":{"type":"string","enum":["ios","android","web"]},"name":{"type":"string"}},"required":["id","platform"],"description":"Customer app: also issue a rotating device refresh token (400-day sliding session)"}},"required":["token"]},"CustomerSessionRefresh":{"type":"object","properties":{"refreshToken":{"type":"string"},"deviceId":{"type":"string"}},"required":["refreshToken","deviceId"]},"CustomerSessionSignOut":{"type":"object","properties":{"refreshToken":{"type":"string"},"deviceId":{"type":"string"}},"required":["refreshToken","deviceId"]},"CustomerDevice":{"type":"object","properties":{"platform":{"type":"string","enum":["ios","android","web"]},"pushToken":{"type":"string","minLength":8,"maxLength":512},"locale":{"type":"string","enum":["en","ar"],"default":"ar"}},"required":["platform","pushToken"]}},"parameters":{}},"paths":{"/v1/pos/whoami":{"get":{"tags":["POS"],"security":[{"PosHmac":[]}],"parameters":[{"schema":{"type":"string","description":"Tenant id or slug the POS is configured with (checked, not refused)"},"required":false,"name":"tenant","in":"query"},{"schema":{"type":"string","description":"Mapped branch (id or code) to check; repeat for several"},"required":false,"name":"branch","in":"query"}],"responses":{"200":{"description":"Tenant, key scopes, allowed branches, missing recommended scopes, clock skew and contract version (connection test)"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/catalog/sync":{"post":{"tags":["POS"],"security":[{"PosHmac":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"source":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,40}$","default":"easyaipos"},"mode":{"type":"string","enum":["full","delta"],"default":"delta"},"syncId":{"type":"string","minLength":8,"maxLength":80},"final":{"type":"boolean","default":true},"items":{"type":"array","items":{"type":"object","properties":{"sku":{"type":"string","minLength":1,"maxLength":120},"name":{"anyOf":[{"type":"string","minLength":1,"maxLength":200},{"type":"object","properties":{"en":{"type":"string","minLength":1,"maxLength":200},"ar":{"type":"string","nullable":true,"maxLength":200}},"required":["en"]}]},"price":{"type":"number","nullable":true,"minimum":0,"maximum":10000000},"categoryId":{"type":"string","nullable":true,"minLength":1,"maxLength":120},"categoryName":{"anyOf":[{"type":"string","minLength":1,"maxLength":200},{"type":"object","properties":{"en":{"type":"string","minLength":1,"maxLength":200},"ar":{"type":"string","nullable":true,"maxLength":200}},"required":["en"]},{"nullable":true}]},"active":{"type":"boolean","default":true},"barcode":{"type":"string","nullable":true,"maxLength":64},"imageUrl":{"type":"string","nullable":true,"maxLength":1000,"format":"uri"},"cost":{"type":"number","nullable":true,"minimum":0,"maximum":10000000},"itemType":{"type":"string","nullable":true,"enum":["sellable","raw_material","ingredient","modifier","combo","service","other"]},"isSellable":{"type":"boolean","nullable":true},"type":{"type":"string","nullable":true,"maxLength":60},"productType":{"type":"string","nullable":true,"maxLength":60},"sellable":{"type":"boolean","nullable":true},"isRawMaterial":{"type":"boolean","nullable":true},"trackInventoryOnly":{"type":"boolean","nullable":true},"branchIds":{"type":"array","nullable":true,"items":{"type":"string","minLength":1,"maxLength":120},"maxItems":500},"availability":{"type":"array","nullable":true,"items":{"type":"object","properties":{"branchId":{"type":"string","minLength":1,"maxLength":120},"available":{"type":"boolean","default":true},"price":{"type":"number","nullable":true,"minimum":0,"maximum":10000000}},"required":["branchId"]},"maxItems":500},"modifierGroups":{"type":"array","nullable":true,"items":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":120},"name":{"anyOf":[{"type":"string","minLength":1,"maxLength":200},{"type":"object","properties":{"en":{"type":"string","minLength":1,"maxLength":200},"ar":{"type":"string","nullable":true,"maxLength":200}},"required":["en"]}]},"min":{"type":"integer","minimum":0,"maximum":50,"default":0},"max":{"type":"integer","minimum":0,"maximum":50,"default":1},"required":{"type":"boolean","default":false},"sortOrder":{"type":"integer","nullable":true,"minimum":-10000,"maximum":10000},"modifiers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":120},"name":{"anyOf":[{"type":"string","minLength":1,"maxLength":200},{"type":"object","properties":{"en":{"type":"string","minLength":1,"maxLength":200},"ar":{"type":"string","nullable":true,"maxLength":200}},"required":["en"]}]},"price":{"type":"number","nullable":true,"minimum":-100000,"maximum":100000},"isDefault":{"type":"boolean","nullable":true},"active":{"type":"boolean","default":true},"branchIds":{"type":"array","nullable":true,"items":{"type":"string","minLength":1,"maxLength":120},"maxItems":500},"availability":{"type":"array","nullable":true,"items":{"type":"object","properties":{"branchId":{"type":"string","minLength":1,"maxLength":120},"available":{"type":"boolean","default":true},"price":{"type":"number","nullable":true,"minimum":0,"maximum":10000000}},"required":["branchId"]},"maxItems":500},"sortOrder":{"type":"integer","nullable":true,"minimum":-10000,"maximum":10000}},"required":["id","name"]},"maxItems":100,"default":[]}},"required":["id","name"]},"maxItems":30},"posItemId":{"type":"string","nullable":true,"minLength":1,"maxLength":160},"legacyIds":{"type":"array","nullable":true,"items":{"type":"string","minLength":1,"maxLength":160},"maxItems":20},"identityVersion":{"type":"integer","nullable":true,"minimum":1,"maximum":1000}},"required":["sku","name"]},"maxItems":2000,"default":[]},"categories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":120},"name":{"anyOf":[{"type":"string","minLength":1,"maxLength":200},{"type":"object","properties":{"en":{"type":"string","minLength":1,"maxLength":200},"ar":{"type":"string","nullable":true,"maxLength":200}},"required":["en"]}]},"active":{"type":"boolean","default":true},"branchIds":{"type":"array","nullable":true,"items":{"type":"string","minLength":1,"maxLength":120},"maxItems":500}},"required":["id","name"]},"maxItems":2000,"default":[]},"removed":{"type":"object","properties":{"skus":{"type":"array","items":{"type":"string","minLength":1,"maxLength":120},"maxItems":2000,"default":[]},"categoryIds":{"type":"array","items":{"type":"string","minLength":1,"maxLength":120},"maxItems":2000,"default":[]}}}}}}}},"responses":{"200":{"description":"Menu sync (2026-10-08): received, changed and deactivated counts, and the stored totals for the source. Scope pos.catalog (or pos.orders)."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/customers/sync":{"post":{"tags":["POS"],"security":[{"PosHmac":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"source":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,40}$","default":"easyaipos"},"businessId":{"type":"string","nullable":true,"maxLength":120},"syncId":{"type":"string","minLength":8,"maxLength":80},"batch":{"type":"integer","minimum":0,"maximum":100000},"openingPoints":{"type":"string","enum":["ignore","carry_over"],"default":"ignore"},"customers":{"type":"array","items":{"type":"object","properties":{"externalId":{"type":"string","minLength":1,"maxLength":120},"name":{"type":"string","nullable":true,"maxLength":200},"phone":{"type":"string","nullable":true,"maxLength":40},"email":{"type":"string","nullable":true,"maxLength":200},"birthDate":{"type":"string","nullable":true,"maxLength":40},"gender":{"type":"string","nullable":true,"enum":["male","female","other","undisclosed"]},"locale":{"type":"string","nullable":true,"enum":["ar","en"]},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":60},"maxItems":50},"customerGroup":{"type":"string","nullable":true,"maxLength":120},"totalSpent":{"type":"number","nullable":true,"minimum":0,"maximum":10000000000},"totalOrders":{"type":"number","nullable":true,"minimum":0,"maximum":1000000000},"lastOrderAt":{"type":"string","nullable":true,"format":"date-time"},"marketingConsent":{"type":"boolean","nullable":true},"rewardsCustomerId":{"type":"string","nullable":true,"maxLength":60},"memberNumber":{"type":"string","nullable":true,"maxLength":20},"points":{"type":"number","nullable":true,"minimum":0,"maximum":1000000000}},"required":["externalId"]},"minItems":1,"maxItems":1000}},"required":["customers"]}}}},"responses":{"200":{"description":"Customer sync (2026-10-09): per row created | linked | updated | conflict, member number, points and tier; auto-enrolment and opening points. Scope pos.customers."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/customers/enroll":{"post":{"tags":["POS"],"security":[{"PosHmac":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"source":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,40}$","default":"easyaipos"},"externalIds":{"type":"array","items":{"type":"string","minLength":1,"maxLength":120},"maxItems":1000},"customerIds":{"type":"array","items":{"type":"string","minLength":1,"maxLength":60},"maxItems":1000},"welcome":{"type":"boolean","default":true}}}}}},"responses":{"200":{"description":"Enrol customers by externalId or customerId (2026-10-09): per row enrolled | already_member | not_found | limit_reached | no_active_program. Scope pos.customers."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/customers/enroll-jobs":{"post":{"tags":["POS"],"security":[{"PosHmac":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"source":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,40}$","default":"easyaipos"},"syncId":{"type":"string","minLength":8,"maxLength":80},"welcome":{"type":"boolean","default":false}},"required":["syncId"]}}}},"responses":{"200":{"description":"Enrol all customers imported by one sync run (initial full sync), as a background job; once per syncId. Scope pos.customers."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/customers/enroll-jobs/{jobId}":{"get":{"tags":["POS"],"security":[{"PosHmac":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"jobId","in":"path"}],"responses":{"200":{"description":"Progress of an enrolment job. Scope pos.customers."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/customers/balances":{"post":{"tags":["POS"],"security":[{"PosHmac":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"source":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,40}$","default":"easyaipos"},"externalIds":{"type":"array","items":{"type":"string","minLength":1,"maxLength":120},"maxItems":1000},"since":{"type":"string","format":"date-time"},"after":{"type":"string","minLength":1,"maxLength":120},"limit":{"type":"integer","minimum":1,"maximum":1000,"default":500}}}}}},"responses":{"200":{"description":"Balances of synced customers by externalIds or changed since a cursor (2026-10-09). Scope pos.customers."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/sales/sync":{"post":{"tags":["POS"],"security":[{"PosHmac":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"source":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,40}$","default":"easyaipos"},"phase":{"type":"string","enum":["phase1","phase2","live","reconcile"],"default":"live"},"sales":{"type":"array","items":{"type":"object","properties":{"externalSaleId":{"type":"string","minLength":1,"maxLength":120},"posOrderId":{"type":"string","minLength":1,"maxLength":120},"invoiceNumber":{"type":"string","maxLength":80},"branchId":{"type":"string","minLength":1,"maxLength":120},"soldAt":{"type":"string","format":"date-time"},"channel":{"type":"string","enum":["dine_in","takeaway","delivery","online","retail"],"default":"retail"},"status":{"type":"string","enum":["completed","partially_refunded","refunded","voided"],"default":"completed"},"externalCustomerId":{"type":"string","nullable":true,"minLength":1,"maxLength":120},"rewardsCustomerId":{"type":"string","nullable":true,"maxLength":60},"subtotal":{"type":"number","minimum":0,"maximum":100000000},"discount":{"type":"number","minimum":0,"maximum":100000000},"tax":{"type":"number","minimum":0,"maximum":100000000},"total":{"type":"number","minimum":0,"maximum":100000000},"cogs":{"type":"number","nullable":true,"minimum":0,"maximum":100000000},"refundedNet":{"type":"number","minimum":0,"maximum":100000000},"lines":{"type":"array","items":{"type":"object","properties":{"lineNo":{"type":"integer","minimum":0,"maximum":100000},"lineId":{"type":"string","maxLength":120},"sku":{"type":"string","minLength":1,"maxLength":120},"name":{"type":"string","maxLength":200},"nameAr":{"type":"string","nullable":true,"maxLength":200},"categoryId":{"type":"string","nullable":true,"minLength":1,"maxLength":120},"categoryName":{"type":"string","nullable":true,"maxLength":120},"quantity":{"type":"number","minimum":0,"exclusiveMinimum":true,"maximum":1000000},"unitPrice":{"type":"number","minimum":0,"maximum":100000000},"discount":{"type":"number","minimum":0,"maximum":100000000,"default":0},"net":{"type":"number","minimum":-10000000,"maximum":100000000},"unitCost":{"type":"number","nullable":true,"minimum":0,"maximum":100000000},"costSource":{"type":"string","enum":["stock_movement","sale_cogs","item_cost","catalog","none"]},"costEstimated":{"type":"boolean"},"refundedQuantity":{"type":"number","minimum":0,"maximum":100000000},"refundedNet":{"type":"number","minimum":0,"maximum":100000000}},"required":["lineNo","sku","quantity","unitPrice"]},"minItems":1,"maxItems":300}},"required":["externalSaleId","branchId","soldAt","lines"]},"minItems":1,"maxItems":500}},"required":["sales"]}}}},"responses":{"200":{"description":"Sales sync (2026-10-10): up to 500 sales with lines and cost; per sale created | updated | unchanged | enriched (a loyalty commit) | rejected. Idempotent per externalSaleId; refunds and voids update the sale. Scope pos.sales."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/sales/bootstrap":{"post":{"tags":["POS"],"security":[{"PosHmac":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"source":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,40}$","default":"easyaipos"},"horizon":{"type":"string","enum":["12m","24m","all"],"default":"12m"},"state":{"type":"string","enum":["phase1","phase2","live","paused"]},"startedAt":{"type":"string","format":"date-time"},"phase1":{"type":"object","properties":{"from":{"type":"string","nullable":true,"format":"date-time"},"to":{"type":"string","format":"date-time"},"expected":{"type":"integer","minimum":0},"sent":{"type":"integer","minimum":0},"completedAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["from","to","expected","sent"]},"phase2":{"type":"object","properties":{"from":{"type":"string","nullable":true,"format":"date-time"},"to":{"type":"string","format":"date-time"},"expected":{"type":"integer","minimum":0},"sent":{"type":"integer","minimum":0},"completedAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["from","to","expected","sent"]},"throttle":{"type":"object","nullable":true,"properties":{"reason":{"type":"string","enum":["peak_hours","till_busy","slow_database","none"]},"at":{"type":"string","format":"date-time"}},"required":["reason","at"]}},"required":["state","startedAt","phase1","phase2"]}}}},"responses":{"200":{"description":"Historical import progress (90-day phase 1, deep backfill); returns the bootstrap status (DATA IMPORT, INTELLIGENCE, AI). Scope pos.sales."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/sales/reconcile":{"post":{"tags":["POS"],"security":[{"PosHmac":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"source":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,40}$","default":"easyaipos"},"days":{"type":"array","items":{"type":"object","properties":{"branchId":{"type":"string","minLength":1,"maxLength":120},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"count":{"type":"integer","minimum":0},"net":{"type":"number","minimum":-10000000,"maximum":100000000}},"required":["branchId","date","count","net"]},"minItems":1,"maxItems":800}},"required":["days"]}}}},"responses":{"200":{"description":"Nightly reconciliation: per branch and day count and net; returns the days to re-send. Scope pos.sales."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/sales/daily":{"post":{"tags":["POS"],"security":[{"PosHmac":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"source":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,40}$","default":"easyaipos"},"rows":{"type":"array","items":{"type":"object","properties":{"branchId":{"type":"string","minLength":1,"maxLength":120},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"sku":{"type":"string","minLength":1,"maxLength":120},"name":{"type":"string","maxLength":200},"quantity":{"type":"number","minimum":0},"gross":{"type":"number","minimum":-10000000,"maximum":100000000},"net":{"type":"number","minimum":-10000000,"maximum":100000000},"discount":{"type":"number","minimum":0,"maximum":100000000},"cogs":{"type":"number","nullable":true,"minimum":0,"maximum":100000000},"orders":{"type":"integer","minimum":0}},"required":["branchId","date","sku","quantity","gross","net"]},"minItems":1,"maxItems":5000}},"required":["rows"]}}}},"responses":{"200":{"description":"Fallback only: per-item daily rollups for branch-days without transactions. Scope pos.sales."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/orders/rewards/lookup":{"post":{"tags":["POS"],"security":[{"PosHmac":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","minLength":4,"maxLength":200},"branchId":{"type":"string","minLength":1,"maxLength":120}},"required":["code"]}}}},"responses":{"200":{"description":"Rewards catalogue (2026-10-12): a pickup order by scanned QR (EAO1:<token> or, 2026-10-25, the signed link https://…/o/o.<id>.<exp>.<sig>), typed pickup code or order number: items, customer (masked), status and canHandOver with a reason and EN/AR message. Scope pos.loyalty; entitlement rewards.catalog."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/orders/rewards/pickup":{"post":{"tags":["POS"],"security":[{"PosHmac":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","minLength":4,"maxLength":200},"branchId":{"type":"string","minLength":1,"maxLength":120},"cashierId":{"type":"string","minLength":1,"maxLength":120},"cashierName":{"type":"string","minLength":1,"maxLength":120},"idempotencyKey":{"type":"string","minLength":8,"maxLength":200}},"required":["code","idempotencyKey"]}}}},"responses":{"200":{"description":"Rewards catalogue (2026-10-12): hands a paid pickup order over (status picked_up). Idempotent per key (replayed: true); 409 ALREADY_PICKED_UP | NOT_PAID | WRONG_BRANCH | NOT_PICKUP | CANCELLED | REFUNDED. Scope pos.loyalty."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/orders/rewards/{orderId}/status":{"post":{"tags":["POS"],"security":[{"PosHmac":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["accepted","preparing","ready","picked_up","delivered","rejected","cancelled","extend_hold"]},"posOrderRef":{"type":"string","minLength":1,"maxLength":120},"reason":{"type":"string","minLength":1,"maxLength":500},"minutes":{"type":"integer","minimum":1,"maximum":1440},"branchId":{"type":"string","minLength":1,"maxLength":120},"cashierId":{"type":"string","minLength":1,"maxLength":120},"cashierName":{"type":"string","minLength":1,"maxLength":120},"idempotencyKey":{"type":"string","minLength":8,"maxLength":200}},"required":["status","idempotencyKey"]}}}},"responses":{"200":{"description":"Reward orders in EasyAiPOS online orders (2026-10-22): EasyAiPOS reports accepted | preparing | ready | picked_up | delivered | rejected | cancelled | extend_hold. Idempotent per idempotencyKey (replayed: true); 409 NOT_SENT_TO_POS | CANCELLED | REFUNDED | EXPIRED | INVALID_TRANSITION | CANCEL_NOT_ALLOWED; 403 BRANCH_NOT_ALLOWED. Scope pos.loyalty."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/catalog":{"get":{"tags":["Customer"],"security":[{"Bearer":[]}],"responses":{"200":{"description":"Rewards catalogue (2026-10-12): active products with this member's best Points + Cash split and affordable flags; filters type, category, affordable, sort. categories[] (2026-11-07): resolved visible categories { key, label { en, ar }, count, imageUrl }, never a raw id; items carry categoryLabel."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/catalog/quote":{"post":{"tags":["Customer"],"security":[{"Bearer":[]}],"responses":{"200":{"description":"Exact Points + Cash split for a slider position within the product rule (min cash %, max points %, step, tier overrides), the usable balance and the delivery fee."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/orders":{"post":{"tags":["Customer"],"security":[{"Bearer":[]}],"responses":{"200":{"description":"Places a Points + Cash order: points held, stock reserved; cash > 0 returns payment.paymentUrl (gateway redirect), cash 0 confirms at once. Idempotent per idempotencyKey."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/purchases":{"get":{"tags":["Customer"],"security":[{"Bearer":[]}],"responses":{"200":{"description":"In-store (till) purchases of the signed-in member, newest first: date, branch, total, item lines, points earned and used, rewards and promotions used, receipt number. Cursor pagination (take ≤ 50, cursor = nextCursor)."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tenant/catalog/products/bulk-status":{"post":{"tags":["Catalogue"],"responses":{"200":{"description":"Bulk Publish / Unpublish (draft) / Archive: {status, ids} or {status, filter: {status, createdVia}}. Products that cannot go live are reported in failed; one audit entry per change. Permission campaign.edit, entitlement rewards.catalog."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tenant/marketplace/status":{"get":{"tags":["Marketplace"],"responses":{"200":{"description":"What customers see: active and draft products, visible categories and featured, warnings (not_launched, no_active_products, drafts_waiting, no_visible_categories) and the storefront URL."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/validator/reward-orders/pickup":{"post":{"tags":["Validator"],"security":[{"Bearer":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","minLength":4,"maxLength":200},"branchId":{"type":"string","minLength":1,"maxLength":120},"cashierId":{"type":"string","minLength":1,"maxLength":120},"cashierName":{"type":"string","minLength":1,"maxLength":120},"idempotencyKey":{"type":"string","minLength":8,"maxLength":200}},"required":["code","idempotencyKey"]}}}},"responses":{"200":{"description":"Validator app pickup handover (2026-10-12), permission redemption.validate."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tenant/ai/analyse":{"post":{"tags":["AI advisor"],"responses":{"200":{"description":"Part D (2026-10-11): runs the AI Promotion Advisor now. Deterministic report (headline KPIs, detections) and ranked recommendations with simulated uplift, margin impact, guardrails and confidence; AI wording when a provider is configured, EN/AR templates otherwise. Entitlement ai.advisor."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tenant/ai/report":{"get":{"tags":["AI advisor"],"responses":{"200":{"description":"The Initial Intelligence Report (after the 90-day bootstrap; refreshed after the deep backfill)."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tenant/ai/recommendations/{id}/draft":{"post":{"tags":["AI advisor"],"responses":{"200":{"description":"Creates a draft promotion or campaign through the existing APIs, plus an experiment with a holdout."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/customers/identify":{"post":{"tags":["POS"],"security":[{"PosHmac":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"context":{"type":"object","properties":{"tenantId":{"type":"string","minLength":1},"branchId":{"type":"string","minLength":1},"terminalId":{"type":"string","minLength":1},"cashierId":{"type":"string","minLength":1},"currency":{"type":"string","minLength":3,"maxLength":3,"default":"QAR"},"occurredAt":{"type":"string","format":"date-time"}},"required":["tenantId","branchId","terminalId","occurredAt"]},"by":{"type":"string","enum":["phone","email","memberId","walletToken"]},"value":{"type":"string","minLength":1},"capabilities":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":20},"autoEnroll":{"type":"boolean"},"posCustomerId":{"type":"string","minLength":1,"maxLength":120},"source":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,40}$"}},"required":["context","by","value"]}}}},"responses":{"200":{"description":"Customer or null"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/orders/evaluate":{"post":{"tags":["POS"],"security":[{"PosHmac":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"context":{"type":"object","properties":{"tenantId":{"type":"string","minLength":1},"branchId":{"type":"string","minLength":1},"terminalId":{"type":"string","minLength":1},"cashierId":{"type":"string","minLength":1},"currency":{"type":"string","minLength":3,"maxLength":3,"default":"QAR"},"occurredAt":{"type":"string","format":"date-time"}},"required":["tenantId","branchId","terminalId","occurredAt"]},"posOrderId":{"type":"string","minLength":1},"channel":{"type":"string","enum":["dine_in","takeaway","delivery","online","retail"],"default":"retail"},"customerRef":{"type":"string"},"lines":{"type":"array","items":{"type":"object","properties":{"lineId":{"type":"string"},"sku":{"type":"string"},"categoryIds":{"type":"array","items":{"type":"string"},"default":[]},"quantity":{"type":"number","minimum":0,"exclusiveMinimum":true},"unitPrice":{"type":"number","minimum":0},"lineDiscount":{"type":"number","minimum":0,"default":0},"categoryName":{"type":"string","minLength":1,"maxLength":120},"categories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":120},"name":{"type":"string","minLength":1,"maxLength":120}},"required":["id","name"]},"maxItems":20}},"required":["lineId","sku","quantity","unitPrice"]},"minItems":1},"subtotal":{"type":"number","minimum":0},"paymentMethods":{"type":"array","items":{"type":"string"},"default":[]},"promotionCodes":{"type":"array","items":{"type":"string","minLength":1,"maxLength":40},"maxItems":5}},"required":["context","posOrderId","lines","subtotal"]}}}},"responses":{"200":{"description":"Automatic promotion effects"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/redemptions":{"post":{"tags":["POS"],"security":[{"PosHmac":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"order":{"type":"object","properties":{"context":{"type":"object","properties":{"tenantId":{"type":"string","minLength":1},"branchId":{"type":"string","minLength":1},"terminalId":{"type":"string","minLength":1},"cashierId":{"type":"string","minLength":1},"currency":{"type":"string","minLength":3,"maxLength":3,"default":"QAR"},"occurredAt":{"type":"string","format":"date-time"}},"required":["tenantId","branchId","terminalId","occurredAt"]},"posOrderId":{"type":"string","minLength":1},"channel":{"type":"string","enum":["dine_in","takeaway","delivery","online","retail"],"default":"retail"},"customerRef":{"type":"string"},"lines":{"type":"array","items":{"type":"object","properties":{"lineId":{"type":"string"},"sku":{"type":"string"},"categoryIds":{"type":"array","items":{"type":"string"},"default":[]},"quantity":{"type":"number","minimum":0,"exclusiveMinimum":true},"unitPrice":{"type":"number","minimum":0},"lineDiscount":{"type":"number","minimum":0,"default":0},"categoryName":{"type":"string","minLength":1,"maxLength":120},"categories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":120},"name":{"type":"string","minLength":1,"maxLength":120}},"required":["id","name"]},"maxItems":20}},"required":["lineId","sku","quantity","unitPrice"]},"minItems":1},"subtotal":{"type":"number","minimum":0},"paymentMethods":{"type":"array","items":{"type":"string"},"default":[]},"promotionCodes":{"type":"array","items":{"type":"string","minLength":1,"maxLength":40},"maxItems":5}},"required":["context","posOrderId","lines","subtotal"]},"code":{"type":"string","minLength":1},"idempotencyKey":{"type":"string","minLength":8}},"required":["order","code","idempotencyKey"]}}}},"responses":{"200":{"description":"Reservation or failure reason (EN/AR message)"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/loyalty/rewards":{"post":{"tags":["POS"],"security":[{"PosHmac":[]}],"description":"Redeem a loyalty reward for a member at the till (API key scope pos.loyalty).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedeemRewardRequest"}}}},"responses":{"200":{"description":"Reward issue (points deducted) or failure reason (EN/AR message)"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/loyalty/rewards/{rewardIssueId}/release":{"post":{"tags":["POS"],"security":[{"PosHmac":[]}],"description":"Give back an unused reward the cashier removed before payment: its points/stamps return to the member. Idempotent; 409 REWARD_ALREADY_USED once the sale committed (refund instead). Optional body {context?, posOrderId?}. Scope pos.loyalty.","parameters":[{"schema":{"type":"string"},"required":true,"name":"rewardIssueId","in":"path"}],"responses":{"200":{"description":"{ok, rewardIssueId, status: released | issued, restoredPoints, restoredStamps, pointsBalance, stampsBalance, replayed}"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/redemptions/{id}/release":{"post":{"tags":["POS"],"security":[{"PosHmac":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Released"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/orders/commit":{"post":{"tags":["POS"],"security":[{"PosHmac":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"idempotency-key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"order":{"type":"object","properties":{"context":{"type":"object","properties":{"tenantId":{"type":"string","minLength":1},"branchId":{"type":"string","minLength":1},"terminalId":{"type":"string","minLength":1},"cashierId":{"type":"string","minLength":1},"currency":{"type":"string","minLength":3,"maxLength":3,"default":"QAR"},"occurredAt":{"type":"string","format":"date-time"}},"required":["tenantId","branchId","terminalId","occurredAt"]},"posOrderId":{"type":"string","minLength":1},"channel":{"type":"string","enum":["dine_in","takeaway","delivery","online","retail"],"default":"retail"},"customerRef":{"type":"string"},"lines":{"type":"array","items":{"type":"object","properties":{"lineId":{"type":"string"},"sku":{"type":"string"},"categoryIds":{"type":"array","items":{"type":"string"},"default":[]},"quantity":{"type":"number","minimum":0,"exclusiveMinimum":true},"unitPrice":{"type":"number","minimum":0},"lineDiscount":{"type":"number","minimum":0,"default":0},"categoryName":{"type":"string","minLength":1,"maxLength":120},"categories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":120},"name":{"type":"string","minLength":1,"maxLength":120}},"required":["id","name"]},"maxItems":20}},"required":["lineId","sku","quantity","unitPrice"]},"minItems":1},"subtotal":{"type":"number","minimum":0},"paymentMethods":{"type":"array","items":{"type":"string"},"default":[]},"promotionCodes":{"type":"array","items":{"type":"string","minLength":1,"maxLength":40},"maxItems":5}},"required":["context","posOrderId","lines","subtotal"]},"redemptionIds":{"type":"array","items":{"type":"string"},"default":[]},"rewardIssueIds":{"type":"array","items":{"type":"string"},"default":[]},"total":{"type":"number","minimum":0},"idempotencyKey":{"type":"string","minLength":8},"occurredAt":{"type":"string","format":"date-time"},"rewardOrderId":{"type":"string","minLength":1,"maxLength":120}},"required":["order","total","idempotencyKey"]}}}},"responses":{"200":{"description":"Committed redemptions"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/pos/orders/reverse":{"post":{"tags":["POS"],"security":[{"PosHmac":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"idempotency-key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"context":{"type":"object","properties":{"tenantId":{"type":"string","minLength":1},"branchId":{"type":"string","minLength":1},"terminalId":{"type":"string","minLength":1},"cashierId":{"type":"string","minLength":1},"currency":{"type":"string","minLength":3,"maxLength":3,"default":"QAR"},"occurredAt":{"type":"string","format":"date-time"}},"required":["tenantId","branchId","terminalId","occurredAt"]},"originalPosOrderId":{"type":"string","minLength":1},"refundedLines":{"type":"array","items":{"type":"object","properties":{"lineId":{"type":"string"},"quantity":{"type":"number","minimum":0,"exclusiveMinimum":true}},"required":["lineId","quantity"]}},"refundTotal":{"type":"number","minimum":0},"idempotencyKey":{"type":"string","minLength":8}},"required":["context","originalPosOrderId","refundedLines","refundTotal","idempotencyKey"]}}}},"responses":{"200":{"description":"Reversed / released redemptions"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/public/campaigns/{publicId}":{"get":{"tags":["Public"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"publicId","in":"path"}],"responses":{"200":{"description":"Published campaign content"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/public/campaigns/{publicId}/claim":{"post":{"tags":["Public"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"publicId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"deviceId":{"type":"string"},"locale":{"type":"string","enum":["en","ar"]},"customer":{"type":"object","properties":{"phone":{"type":"string"},"email":{"type":"string"},"name":{"type":"string"},"marketingConsent":{"type":"boolean"}}}},"required":["deviceId","locale"]}}}},"responses":{"200":{"description":"Session token, code, QR payload and payment URL for paid vouchers"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/public/sessions/{token}":{"get":{"tags":["Public"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"token","in":"path"}],"responses":{"200":{"description":"Session"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/public/payments/{id}/confirm":{"post":{"tags":["Public"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Payment status confirmed with the provider"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/public/customers/otp":{"post":{"tags":["Customer"],"description":"Sends a 6-digit code (the tenant's OTP route). H2 join-before-OTP: when the tenant requires membership, a phone that is not a member of THIS tenant gets no code; the answer has the same shape and minimum time, with status \"not_a_member\" and the tenant's WhatsApp join (wa.me link). 429 OTP_RATE_LIMITED / RATE_LIMITED; 503 OTP_UNAVAILABLE when the business has no SMS provider (production).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerOtpRequest"}}}},"responses":{"200":{"description":"{ sent, status: code_sent | not_a_member, expiresInSeconds, join: { number, keyword{en,ar}, url{en,ar} } | null }"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"OTP_UNAVAILABLE","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/public/customers/otp/verify":{"post":{"tags":["Customer"],"description":"Exchanges the code for a customer token. acceptTerms records the tenant terms version on the membership consent. 400 OTP_INVALID / OTP_EXPIRED, 403 NOT_A_MEMBER, 429 OTP_LOCKED.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerOtpVerify"}}}},"responses":{"200":{"description":"{ token, tokenType, expiresIn, customerId, tenantId, identityId, refreshToken?, refreshExpiresAt? } (refresh token only when device was sent)"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/public/customers/link":{"post":{"tags":["Customer"],"description":"Redeems the one-time sign-in link sent on WhatsApp after joining (signed, single use, 15 minutes, tenant-scoped). 400 LINK_INVALID, 410 LINK_EXPIRED / LINK_USED.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerLinkRedeem"}}}},"responses":{"200":{"description":"{ token, tokenType, expiresIn, customerId, tenantId, identityId, refreshToken?, refreshExpiresAt? }"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/public/customers/session/refresh":{"post":{"tags":["Customer"],"description":"Customer app device session: a new 60-minute access token and the ROTATED refresh token (the old one stops working). Sliding 400-day expiry. Reusing a rotated token within 60 s returns the same new refresh token; later reuse revokes the whole session family. 401 REFRESH_INVALID / REFRESH_EXPIRED / REFRESH_REVOKED / REFRESH_REUSED; 429 RATE_LIMITED.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerSessionRefresh"}}}},"responses":{"200":{"description":"{ token, tokenType, expiresIn, customerId, tenantId, refreshToken, refreshExpiresAt }"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/public/customers/session/sign-out":{"post":{"tags":["Customer"],"description":"App sign-out without an access token (e.g. it expired): revokes the session family of this refresh token when it belongs to deviceId. Unknown tokens answer { revoked: 0 }.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerSessionSignOut"}}}},"responses":{"200":{"description":"{ revoked }"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/public/customers/sign-in-config":{"get":{"tags":["Customer"],"description":"What the member sign-in screens draw: brand, the tenant's operating countries only (singleCountry hides the Country row), welcome benefits, terms {url, version}, otp {length, resendSeconds}, join.","responses":{"200":{"description":"SignInConfig"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/sign-out":{"post":{"tags":["Customer"],"security":[{"CustomerBearer":[]}],"description":"Revokes this device session (body: refreshToken and/or deviceId).","responses":{"200":{"description":"{ revoked }"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/loyalty":{"get":{"tags":["Customer"],"security":[{"CustomerBearer":[]}],"responses":{"200":{"description":"Member card: account, program, tier, balance, rewards, qrPayload (EAL1:...)"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/loyalty/enroll":{"post":{"tags":["Customer"],"security":[{"CustomerBearer":[]}],"responses":{"200":{"description":"Loyalty account (idempotent)"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/loyalty/tier-details":{"get":{"tags":["Customer"],"security":[{"CustomerBearer":[]}],"responses":{"200":{"description":"Plan K3 tier details sheet: { details: TierDetailsView | null } (null without tiers)"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/loyalty/history":{"get":{"tags":["Customer"],"security":[{"CustomerBearer":[]}],"responses":{"200":{"description":"Plan K3 points history: ?type=all|earned|spent|expired&cursor= → items, totals, nextCursor"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/wallet/history":{"get":{"tags":["Customer"],"security":[{"CustomerBearer":[]}],"responses":{"200":{"description":"Plan K3 wallet: ?type=all|topup|spent&cursor= → balance, totals, items; 404 FEATURE_DISABLED when top-ups are off"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/wallet/apple":{"get":{"tags":["Customer"],"security":[{"CustomerBearer":[]}],"parameters":[{"schema":{"type":"string","description":"Coupon session id for a coupon pass; omit for the loyalty card"},"required":false,"name":"session","in":"query"}],"responses":{"200":{"description":"Signed .pkpass","content":{"application/vnd.apple.pkpass":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/wallet/google":{"get":{"tags":["Customer"],"security":[{"CustomerBearer":[]}],"parameters":[{"schema":{"type":"string","description":"Coupon session id for a coupon pass; omit for the loyalty card"},"required":false,"name":"session","in":"query"}],"responses":{"200":{"description":"{ saveUrl } Save to Google Wallet link"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/devices":{"post":{"tags":["Customer"],"security":[{"CustomerBearer":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerDevice"}}}},"responses":{"200":{"description":"Registered device"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/coupons":{"get":{"tags":["Customer"],"security":[{"CustomerBearer":[]}],"responses":{"200":{"description":"The customer's coupon sessions"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/devices/remove":{"post":{"tags":["Customer"],"security":[{"CustomerBearer":[]}],"responses":{"200":{"description":"Push off on this device: forgets { pushToken }; the last device withdraws the push consent on the membership (2026-11-07)"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/notifications":{"get":{"tags":["Customer"],"security":[{"CustomerBearer":[]}],"responses":{"200":{"description":"{ push: { configured, devices }, whatsapp: { available, enabled } } for the app Notifications section (2026-11-07)"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/notifications/whatsapp":{"put":{"tags":["Customer"],"security":[{"CustomerBearer":[]}],"responses":{"200":{"description":"{ enabled } Get updates on WhatsApp: the member WhatsApp consent (customer flag with history + membership consent)"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/inbox":{"get":{"tags":["Customer"],"security":[{"CustomerBearer":[]}],"responses":{"200":{"description":"{ data: [{ id, title, body, imageUrl, link, items, sentAt, readAt, expiresAt }], nextCursor, unread } member inbox, 90-day retention (2026-09-30); ?cursor&limit"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/inbox/unread-count":{"get":{"tags":["Customer"],"security":[{"CustomerBearer":[]}],"responses":{"200":{"description":"{ unread } for the app bar badge"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/inbox/{id}/read":{"post":{"tags":["Customer"],"security":[{"CustomerBearer":[]}],"responses":{"200":{"description":"{ unread } marks one item read; id \"all\" marks every item read"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me/push/opened":{"post":{"tags":["Customer"],"security":[{"CustomerBearer":[]}],"responses":{"200":{"description":"{ opened } the app reports a tapped notification { deliveryId?, inboxId? } (open-rate stats; marks the inbox item read)"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/messaging/campaigns/announce":{"post":{"tags":["Messaging"],"security":[{"Bearer":[]}],"responses":{"200":{"description":"{ campaigns: [{ id, name, channel, status }] } \"Announce this promotion\": { items: [{ kind: promotion|product|game, id }], mode: combined|per_offer, channel: e.g. push+whatsapp | push>whatsapp, audience: { kind: all|members|non_members|tier|segment } } creates prefilled draft message campaign(s)"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/platform/settings/push":{"get":{"tags":["Platform"],"security":[{"Bearer":[]}],"responses":{"200":{"description":"Push (FCM) status: configured, projectId, clientEmail (never the key)"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["Platform"],"security":[{"Bearer":[]}],"responses":{"200":{"description":"{ serviceAccount } Firebase service account JSON, encrypted at rest; \"\" removes it. Step-up."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Platform"],"security":[{"Bearer":[]}],"responses":{"200":{"description":"Removes the Firebase service account (push off). Step-up."},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/platform/settings/push/expected-project":{"put":{"tags":["Platform"],"security":[{"Bearer":[]}],"responses":{"200":{"description":"{ expectedProjectId } the Firebase project this environment should use; status reports mismatch"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/platform/settings/push/test":{"post":{"tags":["Platform"],"security":[{"Bearer":[]}],"responses":{"200":{"description":"{ deviceToken? } validates the key with Google (OAuth token, no message) or sends a test push; { ok, mode, error? }"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/validator/lookup":{"post":{"tags":["Validator"],"security":[{"Bearer":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"x-tenant-id","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"}},"required":["code"]}}}},"responses":{"200":{"description":"Offer preview"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/validator/redeem":{"post":{"tags":["Validator"],"security":[{"Bearer":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"x-tenant-id","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"branchId":{"type":"string"},"idempotencyKey":{"type":"string"},"amountSpent":{"type":"number"},"orderRef":{"type":"string"}},"required":["code","branchId","idempotencyKey"]}}}},"responses":{"200":{"description":"Redemption result"},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}