{"openapi":"3.1.0","info":{"title":"Cashfactory Emulator","description":"External-redirect emulator (bank + registrar legs) — dev/staging/e2e only, never production.","version":"0.1.0"},"paths":{"/healthz":{"get":{"summary":"Liveness probe — always 200 (§3.1)","operationId":"healthz_healthz_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Healthz Healthz Get"}}}}}}},"/api/bank/v1/intents":{"post":{"tags":["bank"],"summary":"Create intent (bank leg, §3.2/§3.3)","operationId":"create_intent_api_bank_v1_intents_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"platform_request_id":{"type":"string","maxLength":64,"pattern":"^[A-Za-z0-9._-]{1,64}$","description":"Platform idempotency reference — unique per (leg, value) (§3.2)."},"type":{"type":"string","enum":["account_opening_clearance"],"description":"Intent type for this leg (§3.2)."},"customer_key":{"type":"string","maxLength":64},"applicant":{"properties":{"full_name":{"type":"string","maxLength":256},"date_of_birth":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},"additionalProperties":true,"type":"object","required":["full_name","date_of_birth"],"description":"Platform-KYC-verified facts, rendered read-only; optional statutory keys are additive (§3.2)."},"return_urls":{"properties":{"success_url":{"type":"string"},"fail_url":{"type":"string"}},"type":"object","required":["success_url","fail_url"]},"notification_url":{"type":"string","description":"Absolute http(s) URL the emulator POSTs the `intent.updated` callback to (§3.7/§4.1)."},"redirect_due_seconds":{"type":"integer","maximum":86400.0,"minimum":0.0,"default":900}},"type":"object","required":["platform_request_id","type","customer_key","applicant","return_urls","notification_url"],"title":"BankCreateIntentRequest","description":"§3.2 create body. The `mode` field is NOT accepted (400 MODE_NOT_ALLOWED)."}}},"required":true},"responses":{"200":{"description":"Idempotent re-create — the SAME intent, CURRENT state (§3.3).","content":{"application/json":{"schema":{"properties":{"intent_id":{"type":"string","description":"`<leg>_<32 lowercase hex>` (§3.3)."},"status":{"type":"string","enum":["CLEARED","EXPIRED","NEW","PENDING_APPLICATION","PROCESSING","REJECTED"]},"redirect_url":{"type":"string","description":"The ONLY browser-facing artifact; carries the §2.4 return token."},"expires_at":{"type":"string"}},"type":"object","required":["intent_id","status","redirect_url","expires_at"],"title":"CreateIntentResponse"}}}},"201":{"description":"New intent (§3.3).","content":{"application/json":{"schema":{"properties":{"intent_id":{"type":"string","description":"`<leg>_<32 lowercase hex>` (§3.3)."},"status":{"type":"string","enum":["CLEARED","EXPIRED","NEW","PENDING_APPLICATION","PROCESSING","REJECTED"]},"redirect_url":{"type":"string","description":"The ONLY browser-facing artifact; carries the §2.4 return token."},"expires_at":{"type":"string"}},"type":"object","required":["intent_id","status","redirect_url","expires_at"],"title":"CreateIntentResponse"}}}},"409":{"description":"IDEMPOTENCY_CONFLICT — same platform_request_id, different payload (§3.3/§3.13).","content":{"application/json":{"schema":{"properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"items":{"type":"string"},"type":"array"}},"type":"object","required":["code","message"],"title":"ErrorEnvelope"}}}}}}},"/api/bank/v1/intents/{intent_id}":{"get":{"tags":["bank"],"summary":"Status poll (GetState role, §3.9)","operationId":"poll_intent_api_bank_v1_intents__intent_id__get","parameters":[{"name":"intent_id","in":"path","required":true,"schema":{"type":"string","title":"Intent Id"}}],"responses":{"200":{"description":"Intent state (§3.9). `outcome` present only on terminal CLEARED/REJECTED.","content":{"application/json":{"schema":{"title":"IntentStateResponse","type":"object","required":["intent_id","platform_request_id","leg","type","status","expires_at","updated_at"],"properties":{"intent_id":{"type":"string"},"platform_request_id":{"type":"string"},"leg":{"type":"string","enum":["bank","registrar"]},"type":{"type":"string"},"status":{"type":"string","enum":["CLEARED","EXPIRED","NEW","PENDING_APPLICATION","PROCESSING","REJECTED"]},"expires_at":{"type":"string"},"updated_at":{"type":"string"},"outcome":{"type":"object","nullable":true,"description":"Terminal outcome (§3.7/§3.8); present only on CLEARED/REJECTED."}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"INTENT_NOT_FOUND — unknown intent for this leg (§3.13).","content":{"application/json":{"schema":{"title":"ErrorEnvelope","type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"string"}}}}}}}}}},"/api/registrar/v1/intents":{"post":{"tags":["registrar"],"summary":"Create intent (registrar leg, §3.2/§3.3)","operationId":"create_intent_api_registrar_v1_intents_post","requestBody":{"content":{"application/json":{"schema":{"properties":{"platform_request_id":{"type":"string","maxLength":64,"pattern":"^[A-Za-z0-9._-]{1,64}$","description":"Platform idempotency reference — unique per (leg, value) (§3.2)."},"type":{"type":"string","enum":["clearance"],"description":"Intent type for this leg (§3.2)."},"customer_key":{"type":"string","maxLength":64},"applicant":{"properties":{"full_name":{"type":"string","maxLength":256},"date_of_birth":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},"additionalProperties":true,"type":"object","required":["full_name","date_of_birth"],"description":"Platform-KYC-verified facts, rendered read-only; optional statutory keys are additive (§3.2)."},"return_urls":{"properties":{"success_url":{"type":"string"},"fail_url":{"type":"string"}},"type":"object","required":["success_url","fail_url"]},"notification_url":{"type":"string","description":"Absolute http(s) URL the emulator POSTs the `intent.updated` callback to (§3.7/§4.1)."},"redirect_due_seconds":{"type":"integer","maximum":86400.0,"minimum":0.0,"default":900}},"type":"object","required":["platform_request_id","type","customer_key","applicant","return_urls","notification_url"],"title":"RegistrarCreateIntentRequest","description":"§3.2 create body. The `mode` field is NOT accepted (400 MODE_NOT_ALLOWED)."}}},"required":true},"responses":{"200":{"description":"Idempotent re-create — the SAME intent, CURRENT state (§3.3).","content":{"application/json":{"schema":{"properties":{"intent_id":{"type":"string","description":"`<leg>_<32 lowercase hex>` (§3.3)."},"status":{"type":"string","enum":["CLEARED","EXPIRED","NEW","PENDING_APPLICATION","PROCESSING","REJECTED"]},"redirect_url":{"type":"string","description":"The ONLY browser-facing artifact; carries the §2.4 return token."},"expires_at":{"type":"string"}},"type":"object","required":["intent_id","status","redirect_url","expires_at"],"title":"CreateIntentResponse"}}}},"201":{"description":"New intent (§3.3).","content":{"application/json":{"schema":{"properties":{"intent_id":{"type":"string","description":"`<leg>_<32 lowercase hex>` (§3.3)."},"status":{"type":"string","enum":["CLEARED","EXPIRED","NEW","PENDING_APPLICATION","PROCESSING","REJECTED"]},"redirect_url":{"type":"string","description":"The ONLY browser-facing artifact; carries the §2.4 return token."},"expires_at":{"type":"string"}},"type":"object","required":["intent_id","status","redirect_url","expires_at"],"title":"CreateIntentResponse"}}}},"409":{"description":"IDEMPOTENCY_CONFLICT — same platform_request_id, different payload (§3.3/§3.13).","content":{"application/json":{"schema":{"properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"items":{"type":"string"},"type":"array"}},"type":"object","required":["code","message"],"title":"ErrorEnvelope"}}}}}}},"/api/registrar/v1/intents/{intent_id}":{"get":{"tags":["registrar"],"summary":"Status poll (GetState role, §3.9)","operationId":"poll_intent_api_registrar_v1_intents__intent_id__get","parameters":[{"name":"intent_id","in":"path","required":true,"schema":{"type":"string","title":"Intent Id"}}],"responses":{"200":{"description":"Intent state (§3.9). `outcome` present only on terminal CLEARED/REJECTED.","content":{"application/json":{"schema":{"title":"IntentStateResponse","type":"object","required":["intent_id","platform_request_id","leg","type","status","expires_at","updated_at"],"properties":{"intent_id":{"type":"string"},"platform_request_id":{"type":"string"},"leg":{"type":"string","enum":["bank","registrar"]},"type":{"type":"string"},"status":{"type":"string","enum":["CLEARED","EXPIRED","NEW","PENDING_APPLICATION","PROCESSING","REJECTED"]},"expires_at":{"type":"string"},"updated_at":{"type":"string"},"outcome":{"type":"object","nullable":true,"description":"Terminal outcome (§3.7/§3.8); present only on CLEARED/REJECTED."}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"INTENT_NOT_FOUND — unknown intent for this leg (§3.13).","content":{"application/json":{"schema":{"title":"ErrorEnvelope","type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"string"}}}}}}}}}},"/api/registrar/v1/intents/{intent_id}/queue/complete":{"post":{"tags":["registrar"],"summary":"Queue step completion — PROCESSING → terminal (§3.10)","operationId":"queue_complete_api_registrar_v1_intents__intent_id__queue_complete_post","parameters":[{"name":"intent_id","in":"path","required":true,"schema":{"type":"string","title":"Intent Id"}}],"responses":{"200":{"description":"Terminal state after the queue completion (§3.10) — the §3.9 body.","content":{"application/json":{"schema":{"title":"IntentStateResponse","type":"object","required":["intent_id","platform_request_id","leg","type","status","expires_at","updated_at"],"properties":{"intent_id":{"type":"string"},"platform_request_id":{"type":"string"},"leg":{"type":"string","enum":["bank","registrar"]},"type":{"type":"string"},"status":{"type":"string","enum":["CLEARED","EXPIRED","NEW","PENDING_APPLICATION","PROCESSING","REJECTED"]},"expires_at":{"type":"string"},"updated_at":{"type":"string"},"outcome":{"type":"object","nullable":true,"description":"Terminal outcome (§3.7/§3.8); present only on CLEARED/REJECTED."}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"409":{"description":"STATE_CONFLICT — queue action on a non-PROCESSING/terminal intent (§3.13).","content":{"application/json":{"schema":{"title":"ErrorEnvelope","type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"string"}}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"title":"QueueCompleteRequest","type":"object","required":["decision"],"properties":{"decision":{"type":"string","enum":["cleared","rejected"]},"rejected_reason":{"type":"object","nullable":true,"properties":{"code":{"type":"string"},"text":{"type":"string"}},"description":"Reason content when decision=rejected (§3.10)."}}}}}}}},"/forms/bank/{intent_id}":{"get":{"tags":["bank-forms"],"summary":"Bank ONE-form page (§3.4)","operationId":"bank_form_forms_bank__intent_id__get","parameters":[{"name":"intent_id","in":"path","required":true,"schema":{"type":"string","title":"Intent Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["bank-forms"],"summary":"Bank form submit (§3.5)","operationId":"bank_submit_forms_bank__intent_id__post","parameters":[{"name":"intent_id","in":"path","required":true,"schema":{"type":"string","title":"Intent Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/forms/registrar/{intent_id}":{"get":{"tags":["registrar-forms"],"summary":"Registrar form page (§3.1)","operationId":"registrar_form_forms_registrar__intent_id__get","parameters":[{"name":"intent_id","in":"path","required":true,"schema":{"type":"string","title":"Intent Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["registrar-forms"],"summary":"Registrar form submit (§3.5/§3.10)","operationId":"registrar_submit_forms_registrar__intent_id__post","parameters":[{"name":"intent_id","in":"path","required":true,"schema":{"type":"string","title":"Intent Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/_control/v1/intents":{"get":{"tags":["control"],"summary":"Introspect: list intents (filters leg/status/platform_request_id — §3.11)","operationId":"list_intents__control_v1_intents_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"parameters":[{"name":"leg","in":"query","required":false,"schema":{"type":"string","enum":["bank","registrar"]},"description":"Exact-match filter (§3.11)."},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["CLEARED","EXPIRED","NEW","PENDING_APPLICATION","PROCESSING","REJECTED"]},"description":"Exact-match filter on the §3.6 status."},{"name":"platform_request_id","in":"query","required":false,"schema":{"type":"string","maxLength":64,"pattern":"^[A-Za-z0-9._-]{1,64}$"},"description":"Exact-match filter (§3.2 charset)."}]}},"/_control/v1/intents/{intent_id}":{"get":{"tags":["control"],"summary":"Introspect: intent detail + delivery log (§3.11, F-4)","operationId":"intent_detail__control_v1_intents__intent_id__get","parameters":[{"name":"intent_id","in":"path","required":true,"schema":{"type":"string","title":"Intent Id"}}],"responses":{"200":{"description":"Intent detail + delivery log (F-4: `delivery_log`, ordered by attempt_no, [] when empty).","content":{"application/json":{"schema":{"title":"ControlIntentDetail","type":"object","required":["intent_id","platform_request_id","leg","type","status","expires_at","updated_at","mode","delivery_log"],"properties":{"intent_id":{"type":"string"},"platform_request_id":{"type":"string"},"leg":{"type":"string","enum":["bank","registrar"]},"type":{"type":"string"},"status":{"type":"string","enum":["CLEARED","EXPIRED","NEW","PENDING_APPLICATION","PROCESSING","REJECTED"]},"expires_at":{"type":"string"},"updated_at":{"type":"string"},"outcome":{"type":"object","nullable":true},"mode":{"type":"object","nullable":true,"description":"The stored mode `{mode, params}`; null when unset (default behaviour)."},"delivery_log":{"type":"array","items":{"title":"DeliveryAttempt","type":"object","required":["attempt_no","at","http_status","note"],"properties":{"attempt_no":{"type":"integer","description":"1-based per intent (§4.1)."},"at":{"type":"string","description":"ISO-8601 UTC of the attempt (§3.7 style)."},"http_status":{"type":"string","description":"`ok` for 2xx; the numeric code for non-2xx; `timeout`; else the transport error-class name (§4.1)."},"note":{"type":"string"}}},"description":"§4.1 attempt entries ordered by attempt_no ascending; [] when nothing was attempted (F-4)."}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/_control/v1/intents/{intent_id}/mode":{"put":{"tags":["control"],"summary":"Set failure-injection mode (§3.11) — honored only before submit/queue completion","operationId":"set_intent_mode__control_v1_intents__intent_id__mode_put","parameters":[{"name":"intent_id","in":"path","required":true,"schema":{"type":"string","title":"Intent Id"}}],"responses":{"200":{"description":"Mode stored. Terminal intent → 409 STATE_CONFLICT; mode/params invalid → 400 VALIDATION_ERROR.","content":{"application/json":{"schema":{"title":"SetIntentModeResponse","type":"object","required":["intent_id","status","mode"],"properties":{"intent_id":{"type":"string"},"status":{"type":"string","enum":["CLEARED","EXPIRED","NEW","PENDING_APPLICATION","PROCESSING","REJECTED"]},"mode":{"type":"object","nullable":true,"description":"The stored mode `{mode, params}`."}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"409":{"description":"STATE_CONFLICT — mode set on a terminal intent (§3.13).","content":{"application/json":{"schema":{"title":"ErrorEnvelope","type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"string"}}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"title":"SetIntentModeRequest","type":"object","required":["mode"],"properties":{"mode":{"type":"string","description":"§3.11 mode name, valid for the intent's leg."},"params":{"type":"object","description":"Mode parameters (delay_seconds, count, code/text, fixed values).","default":{}}}}}}}}},"/_control/v1/intents/{intent_id}/deliver-callback":{"post":{"tags":["control"],"summary":"Force an immediate webhook delivery attempt (§3.11 — deploy-gate smoke)","operationId":"deliver_callback__control_v1_intents__intent_id__deliver_callback_post","parameters":[{"name":"intent_id","in":"path","required":true,"schema":{"type":"string","title":"Intent Id"}}],"responses":{"200":{"description":"The forced attempt's delivery-log entry.","content":{"application/json":{"schema":{"title":"DeliverCallbackResponse","allOf":[{"type":"object","required":["intent_id"],"properties":{"intent_id":{"type":"string"}}},{"title":"DeliveryAttempt","type":"object","required":["attempt_no","at","http_status","note"],"properties":{"attempt_no":{"type":"integer","description":"1-based per intent (§4.1)."},"at":{"type":"string","description":"ISO-8601 UTC of the attempt (§3.7 style)."},"http_status":{"type":"string","description":"`ok` for 2xx; the numeric code for non-2xx; `timeout`; else the transport error-class name (§4.1)."},"note":{"type":"string"}}}]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"INTENT_NOT_FOUND — unknown intent (§3.13).","content":{"application/json":{"schema":{"title":"ErrorEnvelope","type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"string"}}}}}}}}}},"/hub":{"get":{"tags":["hub"],"summary":"Hub landing (alias of /)","operationId":"landing_hub_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/":{"get":{"tags":["hub"],"summary":"Hub landing (§3.12)","operationId":"landing__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/hub/bank":{"get":{"tags":["hub"],"summary":"Hub leg page — bank (§5.2)","operationId":"leg_page_bank_hub_bank_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["hub"],"summary":"Hub scratch form — create test intent (§5.6)","operationId":"create_test_intent_bank_hub_bank_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/hub/registrar":{"get":{"tags":["hub"],"summary":"Hub leg page — registrar (§5.2)","operationId":"leg_page_registrar_hub_registrar_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["hub"],"summary":"Hub scratch form — create test intent (§5.6)","operationId":"create_test_intent_registrar_hub_registrar_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/hub/intents/{intent_id}":{"get":{"tags":["hub"],"summary":"Hub intent detail + delivery log (§5.3)","operationId":"intent_detail_hub_intents__intent_id__get","parameters":[{"name":"intent_id","in":"path","required":true,"schema":{"type":"string","title":"Intent Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/hub/intents/{intent_id}/deliver-callback":{"post":{"tags":["hub"],"summary":"Hub: force a delivery attempt (§5.3)","operationId":"force_delivery_hub_intents__intent_id__deliver_callback_post","parameters":[{"name":"intent_id","in":"path","required":true,"schema":{"type":"string","title":"Intent Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/hub/intents/{intent_id}/decision":{"post":{"tags":["hub"],"summary":"Hub: registrar queue action (§3.10 path 1)","operationId":"queue_decision_hub_intents__intent_id__decision_post","parameters":[{"name":"intent_id","in":"path","required":true,"schema":{"type":"string","title":"Intent Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/hub/registrar/queue":{"get":{"tags":["hub"],"summary":"Hub registrar queue (§5.4)","operationId":"queue_page_hub_registrar_queue_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}