[{"data":1,"prerenderedAt":811},["ShallowReactive",2],{"navigation_docs":3,"-docs-proxy-idempotency-and-budgets":356,"-docs-proxy-idempotency-and-budgets-surround":806},[4,8,34,64,90,139,157,171,193,227,241,266,312,334],{"title":5,"path":6,"stem":7},"Documentation","\u002Fdocs","docs\u002Findex",{"title":9,"path":10,"stem":11,"children":12},"Getting started","\u002Fdocs\u002Fgetting-started","docs\u002F01.getting-started\u002Findex",[13,14,18,22,26,30],{"title":9,"path":10,"stem":11},{"title":15,"path":16,"stem":17},"Introduction","\u002Fdocs\u002Fgetting-started\u002Fintroduction","docs\u002F01.getting-started\u002F01.introduction",{"title":19,"path":20,"stem":21},"Concepts","\u002Fdocs\u002Fgetting-started\u002Fconcepts","docs\u002F01.getting-started\u002F02.concepts",{"title":23,"path":24,"stem":25},"Quickstart (5 minutes)","\u002Fdocs\u002Fgetting-started\u002Fquickstart","docs\u002F01.getting-started\u002F03.quickstart",{"title":27,"path":28,"stem":29},"Local development","\u002Fdocs\u002Fgetting-started\u002Flocal-development","docs\u002F01.getting-started\u002F04.local-development",{"title":31,"path":32,"stem":33},"FAQ","\u002Fdocs\u002Fgetting-started\u002Ffaq","docs\u002F01.getting-started\u002F05.faq",{"title":35,"path":36,"stem":37,"children":38},"Architecture","\u002Fdocs\u002Farchitecture","docs\u002F02.architecture\u002Findex",[39,40,44,48,52,56,60],{"title":35,"path":36,"stem":37},{"title":41,"path":42,"stem":43},"Architecture overview","\u002Fdocs\u002Farchitecture\u002Foverview","docs\u002F02.architecture\u002F01.overview",{"title":45,"path":46,"stem":47},"Services","\u002Fdocs\u002Farchitecture\u002Fservices","docs\u002F02.architecture\u002F02.services",{"title":49,"path":50,"stem":51},"Request lifecycle","\u002Fdocs\u002Farchitecture\u002Frequest-lifecycle","docs\u002F02.architecture\u002F03.request-lifecycle",{"title":53,"path":54,"stem":55},"Data model","\u002Fdocs\u002Farchitecture\u002Fdata-model","docs\u002F02.architecture\u002F04.data-model",{"title":57,"path":58,"stem":59},"Status and evidence","\u002Fdocs\u002Farchitecture\u002Fstatus-and-evidence","docs\u002F02.architecture\u002F05.status-and-evidence",{"title":61,"path":62,"stem":63},"Target architecture and authority","\u002Fdocs\u002Farchitecture\u002Ftarget-architecture","docs\u002F02.architecture\u002F06.target-architecture",{"title":65,"path":66,"stem":67,"children":68},"Auth","\u002Fdocs\u002Fauth","docs\u002F03.auth\u002Findex",[69,70,74,78,82,86],{"title":65,"path":66,"stem":67},{"title":71,"path":72,"stem":73},"Overview","\u002Fdocs\u002Fauth\u002Foverview","docs\u002F03.auth\u002F01.overview",{"title":75,"path":76,"stem":77},"Organization and agent model","\u002Fdocs\u002Fauth\u002Forg-project-model","docs\u002F03.auth\u002F02.org-project-model",{"title":79,"path":80,"stem":81},"Issuing API keys","\u002Fdocs\u002Fauth\u002Fissuing-api-keys","docs\u002F03.auth\u002F03.issuing-api-keys",{"title":83,"path":84,"stem":85},"Multi-tenant RLS","\u002Fdocs\u002Fauth\u002Fmulti-tenant-rls","docs\u002F03.auth\u002F04.multi-tenant-rls",{"title":87,"path":88,"stem":89},"Operator sessions and step-up","\u002Fdocs\u002Fauth\u002Foperator-sessions","docs\u002F03.auth\u002F05.operator-sessions",{"title":91,"path":92,"stem":93,"children":94},"Proxy","\u002Fdocs\u002Fproxy","docs\u002F04.proxy\u002Findex",[95,96,99,103,107,111,115,119,123,127,131,135],{"title":91,"path":92,"stem":93},{"title":71,"path":97,"stem":98},"\u002Fdocs\u002Fproxy\u002Foverview","docs\u002F04.proxy\u002F01.overview",{"title":100,"path":101,"stem":102},"Authentication","\u002Fdocs\u002Fproxy\u002Fauthentication","docs\u002F04.proxy\u002F02.authentication",{"title":104,"path":105,"stem":106},"Request routing","\u002Fdocs\u002Fproxy\u002Frequest-routing","docs\u002F04.proxy\u002F03.request-routing",{"title":108,"path":109,"stem":110},"Sessions","\u002Fdocs\u002Fproxy\u002Fsessions","docs\u002F04.proxy\u002F04.sessions",{"title":112,"path":113,"stem":114},"Directives","\u002Fdocs\u002Fproxy\u002Fdirectives","docs\u002F04.proxy\u002F05.directives",{"title":116,"path":117,"stem":118},"Idempotency and budgets","\u002Fdocs\u002Fproxy\u002Fidempotency-and-budgets","docs\u002F04.proxy\u002F06.idempotency-and-budgets",{"title":120,"path":121,"stem":122},"Rate limiting","\u002Fdocs\u002Fproxy\u002Frate-limiting","docs\u002F04.proxy\u002F07.rate-limiting",{"title":124,"path":125,"stem":126},"Provider adapters","\u002Fdocs\u002Fproxy\u002Fprovider-adapters","docs\u002F04.proxy\u002F08.provider-adapters",{"title":128,"path":129,"stem":130},"Auth caching","\u002Fdocs\u002Fproxy\u002Fauth-caching","docs\u002F04.proxy\u002F09.auth-caching",{"title":132,"path":133,"stem":134},"Configuration","\u002Fdocs\u002Fproxy\u002Fconfiguration","docs\u002F04.proxy\u002F10.configuration",{"title":136,"path":137,"stem":138},"Provider routing and resilience","\u002Fdocs\u002Fproxy\u002Fprovider-routing-and-resilience","docs\u002F04.proxy\u002F11.provider-routing-and-resilience",{"title":140,"path":141,"stem":142,"children":143},"Memory","\u002Fdocs\u002Fmemory","docs\u002F05.memory\u002Findex",[144,145,149,153],{"title":140,"path":141,"stem":142},{"title":146,"path":147,"stem":148},"Memory overview","\u002Fdocs\u002Fmemory\u002Foverview","docs\u002F05.memory\u002F01.overview",{"title":150,"path":151,"stem":152},"Write path","\u002Fdocs\u002Fmemory\u002Fwrite-path","docs\u002F05.memory\u002F02.write-path",{"title":154,"path":155,"stem":156},"Search and lifecycle","\u002Fdocs\u002Fmemory\u002Fsearch-and-lifecycle","docs\u002F05.memory\u002F03.search-and-lifecycle",{"title":158,"path":159,"stem":160,"children":161},"Context","\u002Fdocs\u002Fcontext","docs\u002F06.context\u002Findex",[162,163,167],{"title":158,"path":159,"stem":160},{"title":164,"path":165,"stem":166},"Assembly pipeline","\u002Fdocs\u002Fcontext\u002Foverview","docs\u002F06.context\u002F01.overview",{"title":168,"path":169,"stem":170},"Ranking and packing","\u002Fdocs\u002Fcontext\u002Franking-and-packing","docs\u002F06.context\u002F02.ranking-and-packing",{"title":172,"path":173,"stem":174,"children":175},"Intelligence","\u002Fdocs\u002Fintelligence","docs\u002F07.intelligence\u002Findex",[176,177,181,185,189],{"title":172,"path":173,"stem":174},{"title":178,"path":179,"stem":180},"Workers","\u002Fdocs\u002Fintelligence\u002Fworkers","docs\u002F07.intelligence\u002F01.workers",{"title":182,"path":183,"stem":184},"Extraction","\u002Fdocs\u002Fintelligence\u002Fextraction","docs\u002F07.intelligence\u002F02.extraction",{"title":186,"path":187,"stem":188},"Embedder","\u002Fdocs\u002Fintelligence\u002Fembedder","docs\u002F07.intelligence\u002F03.embedder",{"title":190,"path":191,"stem":192},"Extraction evaluation","\u002Fdocs\u002Fintelligence\u002Fevaluation","docs\u002F07.intelligence\u002F04.evaluation",{"title":194,"path":195,"stem":196,"children":197},"API reference","\u002Fdocs\u002Fapi-reference","docs\u002F08.api-reference\u002Findex",[198,199,203,207,211,215,219,223],{"title":194,"path":195,"stem":196},{"title":200,"path":201,"stem":202},"Chat completions","\u002Fdocs\u002Fapi-reference\u002Fchat-completions","docs\u002F08.api-reference\u002F01.chat-completions",{"title":204,"path":205,"stem":206},"Responses","\u002Fdocs\u002Fapi-reference\u002Fresponses","docs\u002F08.api-reference\u002F02.responses",{"title":208,"path":209,"stem":210},"Errors","\u002Fdocs\u002Fapi-reference\u002Ferrors","docs\u002F08.api-reference\u002F03.errors",{"title":212,"path":213,"stem":214},"Health and metrics","\u002Fdocs\u002Fapi-reference\u002Fproxy-health","docs\u002F08.api-reference\u002F04.proxy-health",{"title":216,"path":217,"stem":218},"HTTP route inventory","\u002Fdocs\u002Fapi-reference\u002Fhttp-routes","docs\u002F08.api-reference\u002F05.http-routes",{"title":220,"path":221,"stem":222},"Management API","\u002Fdocs\u002Fapi-reference\u002Fmanagement-api","docs\u002F08.api-reference\u002F06.management-api",{"title":224,"path":225,"stem":226},"Auth gRPC (ValidateToken, ValidateAgent)","\u002Fdocs\u002Fapi-reference\u002Fauth-grpc","docs\u002F08.api-reference\u002F07.auth-grpc",{"title":228,"path":229,"stem":230,"children":231},"MCP","\u002Fdocs\u002Fmcp","docs\u002F09.mcp\u002Findex",[232,233,237],{"title":228,"path":229,"stem":230},{"title":234,"path":235,"stem":236},"Memory server","\u002Fdocs\u002Fmcp\u002Fmemory-server","docs\u002F09.mcp\u002F01.memory-server",{"title":238,"path":239,"stem":240},"Operator gateway","\u002Fdocs\u002Fmcp\u002Foperator-gateway","docs\u002F09.mcp\u002F02.operator-gateway",{"title":242,"path":243,"stem":244,"children":245},"Security","\u002Fdocs\u002Fsecurity","docs\u002F10.security\u002Findex",[246,247,251,254,258,262],{"title":242,"path":243,"stem":244},{"title":248,"path":249,"stem":250},"Security overview","\u002Fdocs\u002Fsecurity\u002Foverview","docs\u002F10.security\u002F01.overview",{"title":100,"path":252,"stem":253},"\u002Fdocs\u002Fsecurity\u002Fauthentication","docs\u002F10.security\u002F02.authentication",{"title":255,"path":256,"stem":257},"Tenant isolation","\u002Fdocs\u002Fsecurity\u002Ftenant-isolation","docs\u002F10.security\u002F03.tenant-isolation",{"title":259,"path":260,"stem":261},"Secrets and keys","\u002Fdocs\u002Fsecurity\u002Fsecrets-and-keys","docs\u002F10.security\u002F04.secrets-and-keys",{"title":263,"path":264,"stem":265},"Prompt injection","\u002Fdocs\u002Fsecurity\u002Fprompt-injection","docs\u002F10.security\u002F05.prompt-injection",{"title":267,"path":268,"stem":269,"children":270},"Operations","\u002Fdocs\u002Foperations","docs\u002F11.operations\u002Findex",[271,272,276,280,284,288,292,296,300,304,308],{"title":267,"path":268,"stem":269},{"title":273,"path":274,"stem":275},"Observability","\u002Fdocs\u002Foperations\u002Fobservability","docs\u002F11.operations\u002F01.observability",{"title":277,"path":278,"stem":279},"Traces and ClickHouse","\u002Fdocs\u002Foperations\u002Ftraces-and-clickhouse","docs\u002F11.operations\u002F02.traces-and-clickhouse",{"title":281,"path":282,"stem":283},"Health checks","\u002Fdocs\u002Foperations\u002Fhealth-checks","docs\u002F11.operations\u002F03.health-checks",{"title":285,"path":286,"stem":287},"Incident response","\u002Fdocs\u002Foperations\u002Fincident-response","docs\u002F11.operations\u002F04.incident-response",{"title":289,"path":290,"stem":291},"Troubleshooting","\u002Fdocs\u002Foperations\u002Ftroubleshooting","docs\u002F11.operations\u002F05.troubleshooting",{"title":293,"path":294,"stem":295},"Billing and budgets","\u002Fdocs\u002Foperations\u002Fbilling-and-budgets","docs\u002F11.operations\u002F06.billing-and-budgets",{"title":297,"path":298,"stem":299},"Evidence and relay","\u002Fdocs\u002Foperations\u002Fevidence-and-relay","docs\u002F11.operations\u002F07.evidence-and-relay",{"title":301,"path":302,"stem":303},"Console","\u002Fdocs\u002Foperations\u002Fconsole","docs\u002F11.operations\u002F08.console",{"title":305,"path":306,"stem":307},"Failure modes and recovery","\u002Fdocs\u002Foperations\u002Ffailure-and-recovery","docs\u002F11.operations\u002F09.failure-and-recovery",{"title":309,"path":310,"stem":311},"Data lifecycle and deletion","\u002Fdocs\u002Foperations\u002Fdata-lifecycle-and-deletion","docs\u002F11.operations\u002F10.data-lifecycle-and-deletion",{"title":313,"path":314,"stem":315,"children":316},"Deployment","\u002Fdocs\u002Fdeployment","docs\u002F12.deployment\u002Findex",[317,318,322,326,330],{"title":313,"path":314,"stem":315},{"title":319,"path":320,"stem":321},"Docker Compose (dev)","\u002Fdocs\u002Fdeployment\u002Fdocker-compose","docs\u002F12.deployment\u002F01.docker-compose",{"title":323,"path":324,"stem":325},"Environment variables","\u002Fdocs\u002Fdeployment\u002Fenvironment-variables","docs\u002F12.deployment\u002F02.environment-variables",{"title":327,"path":328,"stem":329},"Kubernetes","\u002Fdocs\u002Fdeployment\u002Fkubernetes","docs\u002F12.deployment\u002F03.kubernetes",{"title":331,"path":332,"stem":333},"Production readiness","\u002Fdocs\u002Fdeployment\u002Fproduction-readiness","docs\u002F12.deployment\u002F04.production-readiness",{"title":335,"path":336,"stem":337,"children":338},"Reference","\u002Fdocs\u002Freference","docs\u002F13.reference\u002Findex",[339,340,344,348,352],{"title":335,"path":336,"stem":337},{"title":341,"path":342,"stem":343},"Glossary","\u002Fdocs\u002Freference\u002Fglossary","docs\u002F13.reference\u002F01.glossary",{"title":345,"path":346,"stem":347},"Roadmap and gates","\u002Fdocs\u002Freference\u002Froadmap","docs\u002F13.reference\u002F02.roadmap",{"title":349,"path":350,"stem":351},"Architecture decisions","\u002Fdocs\u002Freference\u002Fadr","docs\u002F13.reference\u002F03.adr",{"title":353,"path":354,"stem":355},"Compatibility and versioning","\u002Fdocs\u002Freference\u002Fcompatibility","docs\u002F13.reference\u002F04.compatibility",{"id":357,"title":116,"audience":358,"author":359,"authorUrl":359,"body":360,"coverIndex":359,"coverLabel":359,"coverTone":359,"date":359,"decisionStatus":359,"description":797,"excerpt":359,"extension":798,"featured":799,"historical":799,"meta":800,"navigation":801,"path":117,"readingTime":359,"scope":802,"seo":803,"sourceOfTruth":804,"status":371,"stem":118,"tags":359,"verifiedDate":372,"__hash__":805},"docs\u002Fdocs\u002F04.proxy\u002F06.idempotency-and-budgets.md","integrator",null,{"type":361,"value":362,"toc":787},"minimark",[363,367,373,378,476,479,483,492,564,567,571,581,644,647,656,660,667,745,755,759,765,784],[364,365,366],"p",{},"IBEX uses more than one idempotency mechanism. They do not have the same store, the same failure mode, or the same guarantee. Choose the contract that matches the surface you call.",[368,369],"page-status",{"note":370,"status":371,"verified":372},"Chat idempotency is implemented; budget reconciliation remains open","PROVISIONAL","2026-10-21",[374,375,377],"h2",{"id":376},"surface-comparison","Surface comparison",[379,380,381,403],"table",{},[382,383,384],"thead",{},[385,386,387,391,394,397,400],"tr",{},[388,389,390],"th",{},"Surface",[388,392,393],{},"Header \u002F key",[388,395,396],{},"Store",[388,398,399],{},"Duplicate behavior",[388,401,402],{},"Store outage",[404,405,406,426,445,461],"tbody",{},[385,407,408,411,417,420,423],{},[409,410,200],"td",{},[409,412,413],{},[414,415,416],"code",{},"Idempotency-Key",[409,418,419],{},"Redis",[409,421,422],{},"Replay stored response",[409,424,425],{},"Fail open; no dedupe",[385,427,428,431,436,439,442],{},[409,429,430],{},"Memory write",[409,432,433],{},[414,434,435],{},"X-Idempotency-Key",[409,437,438],{},"PostgreSQL ledger",[409,440,441],{},"Replay stored 2xx",[409,443,444],{},"Fail closed with 503",[385,446,447,450,454,456,459],{},[409,448,449],{},"Worker enqueue",[409,451,452],{},[414,453,416],{},[409,455,438],{},[409,457,458],{},"Replay original task ID",[409,460,444],{},[385,462,463,466,469,471,474],{},[409,464,465],{},"Budget hard cap",[409,467,468],{},"reservation key",[409,470,438],{},[409,472,473],{},"Typed owned\u002Fin-progress\u002Fconflict",[409,475,444],{},[364,477,478],{},"The difference is deliberate: a missed memory write or admission hold is a correctness failure, while a missed chat dedupe is a cost and duplicate-response risk.",[374,480,482],{"id":481},"chat-idempotency","Chat idempotency",[364,484,485,488,489,491],{},[414,486,487],{},"POST \u002Fv1\u002Fchat\u002Fcompletions"," accepts an opaque ",[414,490,416],{}," of at most 256 characters. The key is scoped by organization and is not forwarded upstream.",[379,493,494,504],{},[382,495,496],{},[385,497,498,501],{},[388,499,500],{},"Case",[388,502,503],{},"Result",[404,505,506,514,524,535,543,551],{},[385,507,508,511],{},[409,509,510],{},"Same key, same body fingerprint",[409,512,513],{},"Replay stored status and body; no second provider call",[385,515,516,519],{},[409,517,518],{},"Same key, different body",[409,520,521],{},[414,522,523],{},"409 IDEMPOTENCY_KEY_REUSE",[385,525,526,529],{},[409,527,528],{},"Claim still active",[409,530,531,534],{},[414,532,533],{},"409 IDEMPOTENCY_IN_PROGRESS","; retry after backoff",[385,536,537,540],{},[409,538,539],{},"Transient upstream 429\u002F5xx",[409,541,542],{},"Release the claim so the key can be retried",[385,544,545,548],{},[409,546,547],{},"Redis unavailable or timed out",[409,549,550],{},"Request proceeds without dedupe",[385,552,553,559],{},[409,554,555,558],{},[414,556,557],{},"stream=true"," with a key",[409,560,561],{},[414,562,563],{},"400 VALIDATION_ERROR",[364,565,566],{},"A replay does not create a second session checkpoint or trace.",[374,568,570],{"id":569},"memory-idempotency","Memory idempotency",[364,572,573,576,577,580],{},[414,574,575],{},"POST \u002Fv1\u002Fmemories"," uses a PostgreSQL ledger scoped by ",[414,578,579],{},"(org, agent, key)",".",[379,582,583,591],{},[382,584,585],{},[385,586,587,589],{},[388,588,500],{},[388,590,503],{},[404,592,593,601,610,623,633],{},[385,594,595,598],{},[409,596,597],{},"Same key, same body",[409,599,600],{},"Replay the stored 2xx",[385,602,603,605],{},[409,604,518],{},[409,606,607],{},[414,608,609],{},"409 IDEMPOTENCY_CONFLICT",[385,611,612,615],{},[409,613,614],{},"Claim active",[409,616,617,619,620],{},[414,618,533],{}," plus ",[414,621,622],{},"Retry-After",[385,624,625,628],{},[409,626,627],{},"PostgreSQL unavailable",[409,629,630],{},[414,631,632],{},"503 IDEMPOTENCY_UNAVAILABLE",[385,634,635,638],{},[409,636,637],{},"Row committed, claim not finalized",[409,639,640,643],{},[414,641,642],{},"503","; never report success over an unfinished claim",[374,645,449],{"id":646},"worker-enqueue",[364,648,649,650,652,653,655],{},"The extraction enqueue endpoint requires both a static bearer and an ",[414,651,416],{},". The full normalized payload, including every turn, is hashed before dispatch. A changed payload under the same key conflicts. A dispatch failure releases the claim. If dispatch succeeds but finalization fails, the endpoint returns ",[414,654,642],{}," and the 120-second lease governs the retry window.",[374,657,659],{"id":658},"budget-admission","Budget admission",[364,661,662,663,666],{},"For an organization with an active ",[414,664,665],{},"hard_cap"," period, the proxy claims a durable hold before provider work.",[379,668,669,679],{},[382,670,671],{},[385,672,673,676],{},[388,674,675],{},"Outcome",[388,677,678],{},"Behavior",[404,680,681,691,704,714,724,734],{},[385,682,683,688],{},[409,684,685],{},[414,686,687],{},"owned",[409,689,690],{},"Admit; finalize or release after the provider call",[385,692,693,698],{},[409,694,695],{},[414,696,697],{},"exceeded",[409,699,700,703],{},[414,701,702],{},"402 BUDGET_EXCEEDED","; no provider call",[385,705,706,711],{},[409,707,708],{},[414,709,710],{},"in_progress",[409,712,713],{},"Retry after backoff; do not dispatch twice",[385,715,716,721],{},[409,717,718],{},[414,719,720],{},"conflict",[409,722,723],{},"Reject the reused key with a different fingerprint",[385,725,726,731],{},[409,727,728],{},[414,729,730],{},"no_cap",[409,732,733],{},"Continue without a hold",[385,735,736,739],{},[409,737,738],{},"Ledger unavailable",[409,740,741,744],{},[414,742,743],{},"503 BUDGET_UNAVAILABLE","; fail closed",[364,746,747,748,751,752,580],{},"A provider response without usage must finalize as ",[414,749,750],{},"estimated",", not ",[414,753,754],{},"complete",[374,756,758],{"id":757},"what-is-not-guaranteed","What is not guaranteed",[760,761,764],"callout",{"title":762,"type":763},"Admission is not exactly-once","warning","Chat and worker enqueue deduplicate admission. They do not make provider or Celery execution exactly-once. Reconciliation can still find drift, and budget caps can overshoot within a bounded window.",[766,767,768,772,775,778,781],"ul",{},[769,770,771],"li",{},"No exactly-once provider call.",[769,773,774],{},"No exactly-once Celery execution.",[769,776,777],{},"No final reconciliation evidence for extraction usage.",[769,779,780],{},"No hosted\u002FHA replay evidence.",[769,782,783],{},"No cross-language canonicalization acceptance.",[364,785,786],{},"Use a stable key per logical operation, retain the key with your request record, and retry only transient failures.",{"title":788,"searchDepth":789,"depth":789,"links":790},"",2,[791,792,793,794,795,796],{"id":376,"depth":789,"text":377},{"id":481,"depth":789,"text":482},{"id":569,"depth":789,"text":570},{"id":646,"depth":789,"text":449},{"id":658,"depth":789,"text":659},{"id":757,"depth":789,"text":758},"How retries, replay, admission holds, and usage accounting differ across proxy, memory, and workers.","md",false,{},true,"provisional",{"title":116,"description":797},"services\u002Fproxy; packages\u002Fbudgetledger; services\u002Fmemory; services\u002Fworker","u7V9llZEHVuaoqjY5edYV1NCROgAIh3GeiDdtqA8q6U",[807,809],{"title":112,"path":113,"stem":114,"description":808,"children":-1},"Org-scoped directives and system-prompt injection on the proxy critical path.",{"title":120,"path":121,"stem":122,"description":810,"children":-1},"Per-minute agent, organization, and global request budgets enforced at the proxy edge.",1792875075224]