{"openapi":"3.0.0","info":{"version":"1.0.0","title":"Status API","description":"The Status API tracks a user's open-banking journey from first consent through to insights\nbeing generated. It is a **read-only** window; it does not trigger processing, it only\nreflects what has already happened.\n\n## Consistency\n\nThe API is **eventually consistent**: there may be a short delay between an action occurring and the status reflecting it.\n\n## Core concepts & Definitions\n\n**User** - Each end-user (person) has their journey tracked by this\nAPI, identified by the *tenantUserId* / *userId* in their auth token. The status reflects\neverything that has ever happened for that user in Ockto Open Banking across all its entities.\n\n**Session entities** - Created each time a new authentication token is requested for the user. A user can accumulate multiple sessions over time as they start new open-banking flows.\nSessions are informational — they always have status *STARTED* and serve as a timestamp marker for when a new authentication flow began.\n\n**Consent entities** - Permission a user grants to access their provider data. When a user links the provider bank accounts for a given provider, that creates one consent. If they also link another provider, that is a second consent.\nEach consent goes through its own lifecycle. Roughly: created → validated at the provider →\naccounts retrieved → transactions & balances retrieved.\n\n**Account entities** - A specific provider account under a consent, for example a current account or a\nsavings account. One consent can give access to multiple accounts. Each account has its own independent status — accounts under the same consent may be at different stages simultaneously.\n\n**Transaction set entities** - Represents a batch of transactions retrieved for one account. One account can have one or more transaction sets, each with its own lifecycle from retrieval through to processing.\n\nThe hierarchy is: **user → sessions → consents → accounts → transaction sets**.\n\n## When to use each endpoint\n\n| Endpoint | Use it for |\n|---|---|\n| `GET /user` | Check the last known state of a user's journey |\n| `GET /user/diagnostics` | Support investigation - errors, full entity tree |\n| `GET /user/history` | Step-by-step forensics - what happened and when |\n| `GET /providers` | Check the availability of every provider (bank), per region |\n| `GET /providers/{region}` | Check the availability of every provider (bank) in a region |\n| `GET /providers/{region}/{providerId}` | Check the availability of one provider (bank) in a region |\n\n## Authentication and identification\n\nEvery endpoint requires authentication. Use the same JWT token as for the other Ockto Open Banking API calls, via the header *Authorization: Bearer YOUR_SECRET_TOKEN*.\n\nFor the `/user*` endpoints the JWT is directly linked to the `userId`; every response is automatically scoped to that user. The `/providers*` endpoints return a global, non-user aggregate of bank availability, so they ignore the token's user claim — any valid token may read them, and they can be consulted before a user session exists.\n\n## Status values\n\nEach level of the hierarchy (user, session, consent, account, transaction set) has its\nown status field that reflects how far that entity has progressed.\n\n_Note: All below statuses are plain strings - not strict enums. **Statuses may be added in future without prior notice.** Always handle unknown values gracefully._\n\n### Overall user status\n\nThe top-level `status` on all three endpoints. Reflects the minimum across all active\nentities; it is only as far as the least-progressed entity. So if e.g. 3 accounts are in `INSIGHTS_GENERATED` but 1 is in `TRANSACTION_SET_RETRIEVED`, the user status can never be higher than `TRANSACTION_SET_RETRIEVED`. And if a new consent is just created, the user status will never be higher than `CONSENT_CREATED` because the new consent has not yet progressed. The current user flow:\n\n`STARTED` → `CONSENT_CREATED` → `CONSENT_VALID` → `ACCOUNTS_RETRIEVING` →\n`TRANSACTIONS_RETRIEVING` → `TRANSACTIONS_RETRIEVED` → `TRANSACTIONS_CATEGORISED` →\n`INSIGHTS_GENERATED`\n\nAlso possible: `CONSENT_CANCELLED`, `DELETED` (terminal)\n\n### Entity: consent status\n\n`CONSENT_CREATED` → `CONSENT_VALID` → `CONSENT_RETRIEVED`\n\nTerminal values: `CONSENT_TERMINATED`, `CONSENT_CANCELLED`, `CONSENT_DELETED`\n\n### Entity account status\n\nAccount status reflects the progress of its transaction sets — it is the least-progressed transaction set under that account.\n\n`ACCOUNT_RETRIEVED` → `TRANSACTION_SET_RETRIEVING` → `TRANSACTION_SET_RETRIEVED` →\n`PROCESSING_COMPLETED` → `INSIGHTS_GENERATED`\n\nAlso possible: `TRANSACTION_SET_DELETED`\n\n### Entity transaction set status\n\n`TRANSACTION_SET_RETRIEVING` → `TRANSACTION_SET_RETRIEVED` → `PROCESSING_COMPLETED` →\n`INSIGHTS_GENERATED`\n\nAlso possible: `TRANSACTION_SET_DELETED`\n\n## Known behaviors\n\n**Status can drop when a user adds a new consent.** When a user links another provider (bank account), the\nuser-level `status` drops back to `CONSENT_CREATED` for the new consent and advances again\nas processing completes. This is expected: the status is only as far as the least-progressed active entity.\n\n**Status values may be skipped.** Not all intermediate statuses are guaranteed to appear. The API always reflects the most current known state — when a step is skipped, the status advances directly to the furthest progressed value.\n\n**Deletion.** Once a user's data has been deleted, the status endpoint returns the last known state at the time of deletion.\n\n**One-time journeys only.** This API tracks one-time open-banking journeys: the user grants consent, data is retrieved and processed once, and the journey ends. It does not support continuous open consents where transactions are kept in sync over time.\n\n**Timestamps.** All timestamps reflect when the event was recorded by the API, not necessarily the exact moment the real-world action occurred."},"tags":[{"name":"User","description":"Lightweight snapshot of a user's journey status. Returns the overall status and a nested consent/account view."},{"name":"Diagnostics","description":"Full diagnostic snapshot - errors (active and cleared), all entity statuses, parent relationships. Use for support investigation when a journey has stalled."},{"name":"History","description":"Paginated event log with before/after status snapshots for every event. Use for step-by-step forensic investigation."},{"name":"Providers","description":"Per-provider (bank) availability. A status label to gate on and a 0–100 health dial. Global, non-user aggregate; authenticated like every route, but the token is not scoped to a user."}],"security":[{"BearerAuth":[]}],"components":{"schemas":{"Status":{"type":"object","properties":{"userId":{"type":"string","description":"User identifier, as extracted from the auth token.","example":"companyId_appId_3d6abdd7-374d-4670-9a80-d1949eaaee7c"},"status":{"type":"string","description":"Headline status; the minimum across all active entities. Only as far as the\nleast-progressed entity in the journey.\n\nCan temporarily drop when a user adds a second consent, as the new consent starts at\n`CONSENT_CREATED`, pulling the minimum down until it catches up.\n\nKnown values: `STARTED`, `CONSENT_CREATED`, `CONSENT_VALID`, `ACCOUNTS_RETRIEVING`,\n`TRANSACTIONS_RETRIEVING`, `TRANSACTIONS_RETRIEVED`, `TRANSACTIONS_CATEGORISED`,\n`INSIGHTS_GENERATED`, `CONSENT_CANCELLED`, `DELETED`","example":"CONSENT_CREATED"},"hasActiveErrors":{"type":"boolean","description":"`true` if at least one uncleared error exists for this user.\n\nUse this as a quick signal: if `true`, call `GET /user/diagnostics` to see\nwhat went wrong and whether it has been resolved.","example":false},"consents":{"type":"array","items":{"$ref":"#/components/schemas/Consent"},"description":"One entry per consent the user has created."}},"required":["userId","status","hasActiveErrors","consents"],"description":"The user's current open-banking status."},"Consent":{"type":"object","properties":{"consentId":{"type":"string","minLength":1,"description":"Consent identifier.","example":"0016868a-7f7a-4f5d-a0c2-5465f5f8b413"},"consentStatus":{"type":"string","minLength":1,"description":"How far this consent has progressed.\n\nKnown values: `CONSENT_CREATED`, `CONSENT_VALID`, `CONSENT_RETRIEVED`,\n`CONSENT_TERMINATED`, `CONSENT_CANCELLED`, `CONSENT_DELETED`","example":"CONSENT_RETRIEVED"},"accounts":{"type":"array","items":{"$ref":"#/components/schemas/Account"},"description":"Bank accounts under this consent. Empty until the consent reaches `CONSENT_RETRIEVED`;\naccounts are only known once the bank has confirmed the consent and returned account data."}},"required":["consentId","consentStatus","accounts"],"description":"A bank authorization. One entry per bank connection the user has granted."},"Account":{"type":"object","properties":{"accountId":{"type":"string","minLength":1,"description":"Account identifier. Can be used to look up transaction data in other APIs.","example":"0004e175-6702-56a6-bc54-0536897a0fdf"},"accountStatus":{"type":"string","minLength":1,"description":"How far processing has progressed for this account.\n\nThe status reflects the progress of its transaction sets — it is the least-progressed transaction set under the account.\n\nKnown values: `ACCOUNT_RETRIEVED`, `TRANSACTION_SET_RETRIEVING`,\n`TRANSACTION_SET_RETRIEVED`, `PROCESSING_COMPLETED`, `INSIGHTS_GENERATED`,\n`TRANSACTION_SET_DELETED`","example":"PROCESSING_COMPLETED"}},"required":["accountId","accountStatus"],"description":"One entry per account the provider returned for a given consent. For example, if a user has a current account and a savings account under the same consent, each gets its own entry."},"ErrorResponse":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code.","example":"NOT_FOUND"},"message":{"type":"string","description":"Human-readable description of what went wrong.","example":"No telemetry events found for user"}},"required":["code","message"],"description":"Standard error response returned for all 4xx and 5xx responses."},"DiagnosticsResponse":{"allOf":[{"type":"object","properties":{"userId":{"type":"string","minLength":1,"description":"User identifier, as extracted from the auth token.","example":"companyId_appId_3d6abdd7-374d-4670-9a80-d1949eaaee7c"}},"required":["userId"]},{"$ref":"#/components/schemas/StatusSnapshot"}],"description":"Full diagnostic snapshot for the user."},"StatusSnapshot":{"type":"object","properties":{"status":{"type":"string","nullable":true,"description":"Headline status at this point in time.\n\n`null` if no status exists yet for this user; this can appear as `previousStatus` for the very first event in a user's history.\n\nKnown values: `STARTED`, `CONSENT_CREATED`, `CONSENT_VALID`, `ACCOUNTS_RETRIEVING`,\n`TRANSACTIONS_RETRIEVING`, `TRANSACTIONS_RETRIEVED`, `TRANSACTIONS_CATEGORISED`,\n`INSIGHTS_GENERATED`, `CONSENT_CANCELLED`, `DELETED`","example":"CONSENT_CREATED"},"errorSummary":{"$ref":"#/components/schemas/ErrorSummary"},"errors":{"type":"array","items":{"$ref":"#/components/schemas/ErrorDetail"},"description":"All errors, both active and cleared.\n\nAn entry here does not mean something is still broken; check `clearedAt`.\n`clearedAt: null` means still active. A timestamp means the error was resolved."},"entities":{"type":"object","properties":{"sessions":{"type":"object","properties":{"status":{"type":"string","nullable":true,"description":"Aggregate session status. Always `STARTED` when sessions exist, `null` when none exist yet.","example":"STARTED"},"entries":{"type":"array","items":{"$ref":"#/components/schemas/SessionEntry"}}},"required":["status","entries"],"description":"Session entities. One entry per open-banking flow the user has started."},"consents":{"type":"object","properties":{"status":{"type":"string","nullable":true,"description":"Minimum consent status across all entries. `null` when no consents exist yet.","example":"CONSENT_CREATED"},"entries":{"type":"array","items":{"$ref":"#/components/schemas/ConsentEntry"}}},"required":["status","entries"],"description":"Consent entities. One entry per bank authorization the user has granted."},"accounts":{"type":"object","properties":{"status":{"type":"string","nullable":true,"description":"Minimum account status across all entries. `null` when no accounts exist yet.","example":"ACCOUNT_RETRIEVED"},"entries":{"type":"array","items":{"$ref":"#/components/schemas/AccountEntry"}}},"required":["status","entries"],"description":"Account entities. One entry per bank account across all consents."},"transactionSets":{"type":"object","properties":{"status":{"type":"string","nullable":true,"description":"Minimum transaction set status across all entries. `null` when no transaction sets exist yet.","example":"TRANSACTION_SET_RETRIEVED"},"entries":{"type":"array","items":{"$ref":"#/components/schemas/TransactionSetEntry"}}},"required":["status","entries"],"description":"Transaction set entities. One entry per transaction set across all accounts."}},"required":["sessions","consents","accounts","transactionSets"]}},"required":["status","errorSummary","errors","entities"],"description":"A point-in-time snapshot of the user's status."},"ErrorSummary":{"type":"object","properties":{"active":{"type":"integer","minimum":0,"description":"Number of errors that are still unresolved.\n\nIf this is greater than zero and the journey has stalled, these unresolved\nerrors might indicate the cause. Check `errors[]` for details.","example":1},"cleared":{"type":"integer","minimum":0,"description":"Number of errors that have been resolved, for example by a successful retry.\n\nThese are recorded for transparency but are no longer blocking the journey.","example":2},"total":{"type":"integer","minimum":0,"description":"Total number of errors that have ever occurred. Equal to `active + cleared`.","example":3},"lastErrorAt":{"type":"string","nullable":true,"format":"date-time","description":"When the most recent error was first registered (ISO 8601).\n`null` if no errors have ever occurred for this user.","example":"2026-04-15T14:30:00Z"}},"required":["active","cleared","total","lastErrorAt"],"description":"Counts of active and cleared errors for this user."},"ErrorDetail":{"type":"object","properties":{"entityType":{"type":"string","minLength":1,"description":"Which category of entity experienced the failure.\n\nOne of: `sessions`, `consents`, `accounts`, `transactionSets`","example":"accounts"},"entityId":{"type":"string","minLength":1,"description":"The specific entity that failed, for example an `accountId` or `consentId`.","example":"0004e175-6702-56a6-bc54-0536897a0fdf"},"taskType":{"type":"string","minLength":1,"description":"Operation code indicating what was in progress when the failure occurred. Useful for support investigation.\n\nExamples: `ACCOUNTS_RETRIEVE`, `CONSENTS_RETRIEVE`, `TRANSACTIONS_RETRIEVE_PAGE`","example":"ACCOUNTS_RETRIEVE"},"registeredAt":{"type":"string","minLength":1,"format":"date-time","description":"When this error was first recorded (ISO 8601).\n\nThere may be a short delay between the real-world failure and when it was registered.","example":"2026-04-15T14:30:00Z"},"clearedAt":{"type":"string","nullable":true,"format":"date-time","description":"When the error was resolved, for example by a successful retry (ISO 8601).\n\n`null` means the error is still active and has not been resolved.","example":null}},"required":["entityType","entityId","taskType","registeredAt","clearedAt"],"description":"A single error event, either still active or already resolved.\n\nErrors are not necessarily permanent. The system retries many operations automatically.\nWhen a retry succeeds, the original error is cleared. Use `clearedAt` to tell active\nerrors from resolved ones: `clearedAt: null` means still active."},"SessionEntry":{"type":"object","properties":{"sessionId":{"type":"string","minLength":1,"description":"Session identifier. A new session is created each time a new user token is requested.","example":"a3f7e291b84c56d92e10f847a6321c8b"},"sessionStatus":{"type":"string","minLength":1,"description":"Session status. Always `STARTED`; sessions do not advance beyond this.","example":"STARTED"}},"required":["sessionId","sessionStatus"],"description":"A single session. A new session is created each time a new user token is requested. Sessions always have status `STARTED`."},"ConsentEntry":{"type":"object","properties":{"consentId":{"type":"string","minLength":1,"description":"Consent identifier.","example":"0016868a-7f7a-4f5d-a0c2-5465f5f8b413"},"consentStatus":{"type":"string","minLength":1,"description":"Status of this consent.\n\nKnown values: `CONSENT_CREATED`, `CONSENT_VALID`, `CONSENT_RETRIEVED`,\n`CONSENT_TERMINATED`, `CONSENT_CANCELLED`, `CONSENT_DELETED`","example":"CONSENT_RETRIEVED"}},"required":["consentId","consentStatus"],"description":"A single consent in the entity tree."},"AccountEntry":{"type":"object","properties":{"accountId":{"type":"string","minLength":1,"description":"Account identifier.","example":"0004e175-6702-56a6-bc54-0536897a0fdf"},"accountStatus":{"type":"string","minLength":1,"description":"Status of this account. Reflects the progress of its transaction sets — it is the least-progressed transaction set under this account.\n\nKnown values: `ACCOUNT_RETRIEVED`, `TRANSACTION_SET_RETRIEVING`,\n`TRANSACTION_SET_RETRIEVED`, `PROCESSING_COMPLETED`, `INSIGHTS_GENERATED`,\n`TRANSACTION_SET_DELETED`","example":"PROCESSING_COMPLETED"},"parentId":{"type":"string","description":"Which consent this account belongs to. Formatted as `consent:{consentId}`.\n\nMay be absent when the account-creation event was not recorded. Use this to link the account back to its parent consent without a separate lookup.","example":"consent:0016868a-7f7a-4f5d-a0c2-5465f5f8b413"}},"required":["accountId","accountStatus"],"description":"A single account in the entity tree."},"TransactionSetEntry":{"type":"object","properties":{"transactionSetId":{"type":"string","description":"Transaction set identifier.","example":"00b1f3e2-9c4a-4d8b-ae21-7f3c1d5e6a09"},"transactionSetStatus":{"type":"string","description":"Status of this transaction set.\n\nKnown values: `TRANSACTION_SET_RETRIEVING`, `TRANSACTION_SET_RETRIEVED`,\n`PROCESSING_COMPLETED`, `INSIGHTS_GENERATED`, `TRANSACTION_SET_DELETED`","example":"PROCESSING_COMPLETED"},"parentId":{"type":"string","description":"Which account this transaction set belongs to. Formatted as `account:{accountId}`.\n\nUse this to link the transaction set back to its parent account.","example":"account:0004e175-6702-56a6-bc54-0536897a0fdf"}},"required":["transactionSetId","transactionSetStatus"],"description":"A single transaction set in the entity tree."},"HistoryResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/HistoryItem"},"description":"Events in chronological order, oldest first."},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["data","pagination"],"description":"Paginated event history for the user."},"HistoryItem":{"type":"object","properties":{"event":{"$ref":"#/components/schemas/HistoryEvent"},"previousStatus":{"allOf":[{"$ref":"#/components/schemas/StatusSnapshot"},{"description":"The full status snapshot *before* this event was applied. Compare with `currentStatus` to see exactly what changed: which entity was added, which status advanced, which error appeared or cleared.\n\n**This field is absent for the very first event in the user's history**; there was no prior state to capture."}]},"currentStatus":{"allOf":[{"$ref":"#/components/schemas/StatusSnapshot"},{"description":"The full status snapshot *after* this event was applied. Always present."}]}},"required":["currentStatus"],"description":"A single step in the user's journey: one event and its before/after status snapshots."},"HistoryEvent":{"anyOf":[{"type":"object","properties":{"userId":{"type":"string","minLength":1},"registeredAt":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"sessionId":{"type":"string","minLength":1}}},"type":{"type":"string","enum":["TOKEN_BASIC_SUCCEEDED","TOKEN_BASIC_FAILED","TOKEN_SIGNED_SUCCEEDED","TOKEN_SIGNED_FAILED"],"description":"Session-related event"}},"required":["userId","registeredAt","data","type"]},{"type":"object","properties":{"userId":{"type":"string","minLength":1},"registeredAt":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"consentId":{"type":"string","minLength":1},"status":{"type":"string"}},"required":["consentId"]},"type":{"type":"string","enum":["CONSENTS_CREATE_SUCCEEDED","CONSENTS_RETRIEVE_SUCCEEDED","CONSENTS_CANCEL_SUCCEEDED","CONSENTS_TERMINATE_SUCCEEDED","CONSENTS_REDIRECT_NOK_SUCCEEDED","CONSENTS_CREATE_FAILED","CONSENTS_RETRIEVE_FAILED","CONSENTS_CANCEL_FAILED","CONSENTS_TERMINATE_FAILED"],"description":"Consent-related event"}},"required":["userId","registeredAt","data","type"]},{"type":"object","properties":{"userId":{"type":"string","minLength":1},"registeredAt":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"accountId":{"type":"string"},"consentId":{"type":"string","minLength":1},"transactionSetId":{"type":"string","minLength":1}},"required":["consentId"]},"type":{"type":"string","enum":["ACCOUNTS_RETRIEVE_SUCCEEDED","ACCOUNTS_RETRIEVE_BALANCES_SUCCEEDED","ACCOUNTS_RETRIEVE_FAILED","ACCOUNTS_RETRIEVE_BALANCES_FAILED"],"description":"Account retrieval event"}},"required":["userId","registeredAt","data","type"]},{"type":"object","properties":{"userId":{"type":"string","minLength":1},"registeredAt":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"accountId":{"type":"string","minLength":1},"transactionSetId":{"type":"string","minLength":1},"consentId":{"type":"string","minLength":1}},"required":["accountId"]},"type":{"type":"string","enum":["TRANSACTIONS_RETRIEVE_PAGE_SUCCEEDED","TRANSACTIONS_RETRIEVE_PAGE_FAILED","TRANSACTIONS_PROCESS_PAGE_SUCCEEDED","TRANSACTIONS_PROCESS_PAGE_FAILED"],"description":"Transactions retrieval event"}},"required":["userId","registeredAt","data","type"]},{"type":"object","properties":{"userId":{"type":"string","minLength":1},"registeredAt":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"transactionSetId":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1}},"required":["transactionSetId","accountId"]},"type":{"type":"string","enum":["TRANSACTIONS_PER_ACCOUNT_INGEST_SUCCEEDED","TRANSACTIONS_PER_ACCOUNT_INGEST_FAILED","PROCESS_COMPLETED_SUCCEEDED","PROCESS_COMPLETED_FAILED","PROCESS_CALCULATE_INSIGHTS_SUCCEEDED","PROCESS_CALCULATE_INSIGHTS_FAILED"],"description":"Transactions processing event"}},"required":["userId","registeredAt","data","type"]},{"type":"object","properties":{"userId":{"type":"string","minLength":1},"registeredAt":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{}},"type":{"type":"string","enum":["ENRICHMENT_DATA_RETENTION_DELETE_SUCCEEDED","ENRICHMENT_DATA_RETENTION_DELETE_FAILED","CONSENTS_DATA_RETENTION_DELETE_SUCCEEDED","CONSENTS_DATA_RETENTION_DELETE_FAILED"],"description":"Deletion event"}},"required":["userId","registeredAt","data","type"]},{"type":"object","properties":{"userId":{"type":"string","minLength":1},"registeredAt":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{}},"type":{"type":"string","minLength":1,"description":"Event of unknown type"}},"required":["userId","registeredAt","data","type"]}],"description":"Event that triggered the status change."},"Pagination":{"type":"object","properties":{"next":{"type":"string","nullable":true,"description":"Opaque token; pass as `?offset=` to fetch the next page.\n\n`null` when you are on the last page. Treat as a black box: do not decode or construct it. Use it exactly as returned.","example":"eyJvZmZzZXQiOiIxMCIsInN0YXRlIjp7fX0="},"prev":{"type":"string","nullable":true,"description":"Opaque token for the previous page. `null` on the first page.","example":null}},"description":"Pagination metadata."},"ValidationErrorResponse":{"allOf":[{"$ref":"#/components/schemas/ErrorResponse"},{"type":"object","properties":{"details":{"nullable":true,"description":"Structured validation details. Present when specific fields failed validation."}}}],"description":"Returned for HTTP 400 responses. Extends the standard error response with field-level validation details when available."},"ProviderStatus":{"type":"object","properties":{"provider":{"type":"string","minLength":1,"description":"Provider (bank) code this health item is for.","example":"INGB"},"region":{"type":"string","minLength":2,"maxLength":2,"description":"ISO Alpha-2 country code this health item is for. A bank plus a region is one integration.","example":"NL"},"status":{"type":"string","enum":["HEALTHY","DEGRADED","INSUFFICIENT_DATA"],"description":"The verdict a consumer gates on.\n\n- `HEALTHY` — the provider is scoring well.\n- `DEGRADED` — journeys are failing at an elevated rate.\n- `INSUFFICIENT_DATA` — not enough recent volume to tell; `health` is `null`.","example":"DEGRADED"},"health":{"type":"integer","nullable":true,"minimum":0,"maximum":100,"description":"Availability dial, 0–100. `null` exactly when `status` is `INSUFFICIENT_DATA`.","example":14},"lastUpdate":{"type":"string","format":"date-time","description":"ISO-8601 instant this score was computed.","example":"2026-05-13T13:30:00.000Z"}},"required":["provider","region","status","health","lastUpdate"],"description":"One provider's latest availability: a status label and a 0–100 health dial."}},"parameters":{},"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token issued by the OOB auth service. The same token used for all other OOB API calls."}}},"paths":{"/user":{"get":{"operationId":"getUserStatus","tags":["User"],"summary":"Get user status","description":"Returns the current state of a user's journey: their overall status and a nested view\nof their consents and accounts.\n\nBecause the API is eventually consistent, this reflects the latest available state. For example, use it to look up where a journey was abandoned.\nFor errors and full entity detail, use `GET /user/diagnostics`.\n\n**The top-level `status` is the minimum across all active entities.** If a user has two\nconsents and one is just created, the overall status reflects the least-progressed one until it catches up.","responses":{"200":{"description":"Snapshot of the user's current open-banking journey: overall status, active-error flag, and a nested list of consents and their accounts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Status"}}}},"401":{"description":"Token is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No status data found for the user identified by this token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/user/diagnostics":{"get":{"operationId":"getUserDiagnostics","tags":["Diagnostics"],"summary":"Get diagnostic snapshot","description":"Returns the full diagnostic picture for a user: all errors (active and cleared after retry), the\nstatus of every entity, and parent relationships that let you navigate the hierarchy.\n\nUse this for example to support investigation when a user's journey has stalled or failed.\n\n- `errorSummary.active > 0` means at least one error is still unresolved\n- The `errors` array shows what failed, when, and whether it was resolved\n- The `entities` block shows all consents, accounts, and transaction sets for this user, along with their individual statuses\n- `parentId` on account and transaction set entries links each entity to its parent","responses":{"200":{"description":"Full diagnostic snapshot for the user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiagnosticsResponse"}}}},"401":{"description":"Token is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No data found for this user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/user/history":{"get":{"operationId":"getUserHistory","tags":["History"],"summary":"Get event history","description":"Returns the full event log for the user in chronological order. For every event you get\na `previousStatus` snapshot (the state before the event) and a `currentStatus` snapshot\n(the state after).\n\nUse this for deep forensic investigation; you can trace exactly which event caused a\nstatus change, when an error was first raised, and when it was cleared.\n\n**`previousStatus` is absent for the very first event** in the user's history, since\nthere was no prior state.\n\n**Pagination:** Pass the opaque `pagination.next` token as `?offset=` to fetch the next\npage. `pagination.next` is `null` when you are on the last page. Note: because the API is eventually consistent, paginating through results may not reflect events that arrived during pagination.\n\n**No data** Returns an empty `data` array when no history exists for this user yet.","parameters":[{"schema":{"type":"string","description":"Opaque pagination token from a previous response's pagination.next. Omit to start from the first (oldest) event.\n\nNote: this token can be a long string. Make sure your HTTP client and any intermediaries (proxies, gateways) do not impose a short limit on query string length.","example":"eyJvZmZzZXQiOiIxMCIsInN0YXRlIjp7fX0="},"required":false,"description":"Opaque pagination token from a previous response's pagination.next. Omit to start from the first (oldest) event.\n\nNote: this token can be a long string. Make sure your HTTP client and any intermediaries (proxies, gateways) do not impose a short limit on query string length.","name":"offset","in":"query"},{"schema":{"type":"integer","minimum":1,"description":"Maximum number of events to return per page.\n\nIf omitted, **all events for the user are returned in a single response**. Pass an explicit value when dealing with users who have many events and you want to page through results incrementally.","example":20},"required":false,"description":"Maximum number of events to return per page.\n\nIf omitted, **all events for the user are returned in a single response**. Pass an explicit value when dealing with users who have many events and you want to page through results incrementally.","name":"limit","in":"query"}],"responses":{"200":{"description":"Paginated event history. Returns an empty `data` array if no events have been received for this user yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HistoryResponse"}}}},"400":{"description":"The `offset` token is malformed or could not be decoded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Token is missing or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/providers":{"get":{"operationId":"listProviders","tags":["Providers"],"summary":"List provider health","description":"Returns the latest availability for every provider (bank) scored at least once, one entry\nper region a bank operates in — a bank plus a region is one integration. Each entry carries a\n`status` label to gate on and a 0–100 `health` dial.\n\nRequires the same JWT as the `/user*` routes. The data is a global, non-user aggregate of\nbank availability, so the token's user claim is ignored — any valid token may read it, and\nit can be consulted before a user session exists.\n\nGate on `status`, or threshold `health`; the two are always consistent. `health` is\n`null` exactly when `status` is `INSUFFICIENT_DATA` (not enough recent volume to tell).","responses":{"200":{"description":"Latest health for every provider scored at least once. Empty array if none have been scored.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderStatus"}}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"code":"INTERNAL_SERVER_ERROR","message":"Internal Server Error"}}}}}}},"/providers/{region}":{"get":{"operationId":"listProvidersByRegion","tags":["Providers"],"summary":"List provider health for a region","description":"Returns the latest availability for every provider (bank) scored in a single region. A bank\nplus a region is one integration — the same bank in another region is a separate entry with its\nown availability.\n\nRequires the same JWT as the `/user*` routes. The data is a global, non-user aggregate of\nbank availability, so the token's user claim is ignored — any valid token may read it, and\nit can be consulted before a user session exists.\n\nGate on `status`, or threshold `health`; the two are always consistent. `health` is\n`null` exactly when `status` is `INSUFFICIENT_DATA` (not enough recent volume to tell).","parameters":[{"schema":{"type":"string","minLength":2,"maxLength":2,"description":"ISO Alpha-2 country code, e.g. `nl`.","example":"nl"},"required":true,"description":"ISO Alpha-2 country code, e.g. `nl`.","name":"region","in":"path"}],"responses":{"200":{"description":"Latest health for every provider scored in the region. Empty array if none have been scored.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderStatus"}}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"code":"INTERNAL_SERVER_ERROR","message":"Internal Server Error"}}}}}}},"/providers/{region}/{providerId}":{"get":{"operationId":"getProvider","tags":["Providers"],"summary":"Get one provider health in a region","description":"Returns the latest availability for a single provider (bank) in one region. A bank plus a\nregion is one integration — check the region the journey will use.\n\nRequires the same JWT as the `/user*` routes; the aggregate carries no user, so the token's\nuser claim is ignored.\n\nThe returned item may legitimately be `status: INSUFFICIENT_DATA, health: null` when a\nknown provider has too little recent volume to score. A provider/region pair that has never\nbeen scored returns **404**.","parameters":[{"schema":{"type":"string","minLength":2,"maxLength":2,"description":"ISO Alpha-2 country code, e.g. `nl`.","example":"nl"},"required":true,"description":"ISO Alpha-2 country code, e.g. `nl`.","name":"region","in":"path"},{"schema":{"type":"string","minLength":1,"description":"Provider (bank) code, e.g. `INGB`.","example":"INGB"},"required":true,"description":"Provider (bank) code, e.g. `INGB`.","name":"providerId","in":"path"}],"responses":{"200":{"description":"Latest health for the requested provider in the requested region.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderStatus"}}}},"404":{"description":"No provider with this code has ever been scored in this region.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"code":"NOT_FOUND","message":"No health data for provider INGB in region NL"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"code":"INTERNAL_SERVER_ERROR","message":"Internal Server Error"}}}}}}}}}