From 46cb089cef2f7051eff2b9f1d2bc9336b8e72bef Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 27 Oct 2026 07:00:29 +0000 Subject: [PATCH] feat(spec): sync API spec 2026-10-27 --- api.md | 29 +- openapi/SOURCE.json | 6 +- openapi/verification.json | 1921 +++++++++++++++++++++++++++--- src/resources/date-plans.ts | 16 +- src/resources/index.ts | 3 + src/resources/pricing.ts | 33 + src/resources/sessions.ts | 181 ++- src/types/components.ts | 252 +++- src/types/sessions.ts | 125 ++ tests/generated/pricing.test.ts | 34 + tests/generated/sessions.test.ts | 169 +++ 11 files changed, 2559 insertions(+), 210 deletions(-) create mode 100644 src/resources/pricing.ts create mode 100644 tests/generated/pricing.test.ts diff --git a/api.md b/api.md index dcef817..2f44a0a 100644 --- a/api.md +++ b/api.md @@ -2,7 +2,7 @@ # API reference -Every method of `@didit-protocol/sdk-node`: 349 methods, generated from `openapi/`. Path parameters are positional, the other fields go in one `params` object, and every method takes request options as its last argument. Every type named here is exported from the package. _Application scoped_ methods need the `organizationId` and `applicationId` client options; a _page_ can be iterated with `for await`. Webhook verification and Authentication are described in the README. +Every method of `@didit-protocol/sdk-node`: 359 methods, generated from `openapi/`. Path parameters are positional, the other fields go in one `params` object, and every method takes request options as its last argument. Every type named here is exported from the package. _Application scoped_ methods need the `organizationId` and `applicationId` client options; a _page_ can be iterated with `for await`. Webhook verification and Authentication are described in the README. ## `didit.account` @@ -413,6 +413,12 @@ Every method of `@didit-protocol/sdk-node`: 349 methods, generated from `openapi | `didit.phone.checkCode(params: PhoneCheckCodeParams)` | `POST /v3/phone/check/` | `PhoneVerificationCheckResponse` | | | `didit.phone.sendCode(params: PhoneSendCodeParams)` | `POST /v3/phone/send/` | `PhoneVerificationSendResponse` | | +## `didit.pricing` + +| Method | HTTP | Returns | Notes | +| ---------------------------------- | ------------------------------------------------- | ------------------------- | ----- | +| `didit.pricing.bankVerification()` | `GET /v3/organization/bank-verification-pricing/` | `BankVerificationPricing` | | + ## `didit.proofOfAddress` | Method | HTTP | Returns | Notes | @@ -489,12 +495,21 @@ Every method of `@didit-protocol/sdk-node`: 349 methods, generated from `openapi ## `didit.sessions.imports` -| Method | HTTP | Returns | Notes | -| ----------------------------------------------------------------------------------------- | -------------------------------------------- | ---------------------------- | ------ | -| `didit.sessions.imports.create(params?: SessionsImportsCreateParams)` | `POST /v3/session/imports/` | `SessionImportJob` | upload | -| `didit.sessions.imports.listErrors(importId, params?: SessionsImportsListErrorsParams)` | `GET /v3/session/imports/{importId}/errors/` | page of `SessionImportError` | | -| `didit.sessions.imports.retrieve(importId)` | `GET /v3/session/imports/{importId}/` | `SessionImportJob` | | -| `didit.sessions.imports.retrieveTemplate(params?: SessionsImportsRetrieveTemplateParams)` | `GET /v3/session/imports/template/` | `Blob` | | +| Method | HTTP | Returns | Notes | +| ----------------------------------------------------------------------------------------- | --------------------------------------------- | --------------------------------------- | ------ | +| `didit.sessions.imports.cancel(importId)` | `POST /v3/session/imports/{importId}/cancel/` | `SessionImportJob` | | +| `didit.sessions.imports.checkProvider(params: SessionsImportsCheckProviderParams)` | `POST /v3/session/imports/providers/check/` | `SessionsImportsCheckProviderResponse` | | +| `didit.sessions.imports.create(params?: SessionsImportsCreateParams)` | `POST /v3/session/imports/` | `SessionImportJob` | upload | +| `didit.sessions.imports.listActiveJobs()` | `GET /v3/import-jobs/active/` | `SessionsImportsListActiveJobsResponse` | | +| `didit.sessions.imports.listErrors(importId, params?: SessionsImportsListErrorsParams)` | `GET /v3/session/imports/{importId}/errors/` | page of `SessionImportError` | | +| `didit.sessions.imports.listJobs(params?: SessionsImportsListJobsParams)` | `GET /v3/import-jobs/` | `SessionsImportsListJobsResponse` | | +| `didit.sessions.imports.listProviders()` | `GET /v3/session/imports/providers/` | `SessionsImportsListProvidersResponse` | | +| `didit.sessions.imports.pause(importId)` | `POST /v3/session/imports/{importId}/pause/` | `SessionImportJob` | | +| `didit.sessions.imports.resume(importId)` | `POST /v3/session/imports/{importId}/resume/` | `SessionImportJob` | | +| `didit.sessions.imports.retrieve(importId)` | `GET /v3/session/imports/{importId}/` | `SessionImportJob` | | +| `didit.sessions.imports.retrieveTemplate(params?: SessionsImportsRetrieveTemplateParams)` | `GET /v3/session/imports/template/` | `Blob` | | +| `didit.sessions.imports.retry(importId, params?: SessionsImportsRetryParams)` | `POST /v3/session/imports/{importId}/retry/` | `SessionImportJob` | upload | +| `didit.sessions.imports.start(importId, params?: SessionsImportsStartParams)` | `POST /v3/session/imports/{importId}/start/` | `SessionImportJob` | | ## `didit.sessions.reviews` diff --git a/openapi/SOURCE.json b/openapi/SOURCE.json index e817ac4..cfff748 100644 --- a/openapi/SOURCE.json +++ b/openapi/SOURCE.json @@ -1,13 +1,13 @@ { "verification.json": { "url": "https://docs.didit.me/openapi-25.json", - "sha256": "6157d174fff4e0093ca7ac8e0f064ffc777d1cfa4a7eeb2b0e88fbf86f4a060b", - "fetched_at": "2026-10-26T07:11:58Z" + "sha256": "b2658eb22e23f868d2df5fe513c8dcdadce3abf2e35d1bbebce0382c911038db", + "fetched_at": "2026-10-27T06:59:31Z" }, "account.json": { "url": "https://docs.didit.me/openapi-auth.json", "sha256": "5fafb88b306ab60c7c105b0bf00fa2a6a49b5d2ca8115eb003b332f073844b39", - "fetched_at": "2026-10-26T07:11:58Z" + "fetched_at": "2026-10-27T06:59:31Z" }, "webhook-vectors.json": { "generator": "product-automations scripts/server-sdks/make_vectors.py (seeded 2026-10-17)", diff --git a/openapi/verification.json b/openapi/verification.json index 0236ac8..1125811 100644 --- a/openapi/verification.json +++ b/openapi/verification.json @@ -1509,7 +1509,7 @@ "/v3/session/imports/": { "post": { "summary": "Create a verification import job", - "description": "Create an asynchronous import job for historical User Verification sessions, Business Verification sessions, transaction monitoring records, or workflow custom status rules. Use this to migrate from providers such as Sumsub, MetaMap, Veriff, Onfido, Persona, Trulioo, Jumio, Incode, iDenfy, or any other provider after transforming the export into Didit's canonical CSV/NDJSON format. Imports are disabled by default and must be enabled per organization by Didit.", + "description": "Create an asynchronous import job for historical User Verification sessions, Business Verification sessions, transaction monitoring records, or workflow custom status rules. Set `source=provider` to migrate from another provider: Didit reads Sumsub, Onfido, Persona and ComplyCube with your read-only key, reads Veriff, iDenfy and MetaMap records by the IDs you upload in `file`, and imports an export file in Didit's format for the other providers. Record IDs are namespaced by provider (`sumsub:`) so a re-run skips everything already in Didit. Imports are disabled by default and must be enabled per organization by Didit.", "operationId": "post_v3_session_imports_create", "x-didit-sdk": { "resource": "sessions.imports", @@ -1560,6 +1560,81 @@ "type": "string", "format": "uri", "description": "Alternative to file upload. Must be an HTTPS URL resolving to a public address (private/loopback networks are rejected). Mutually exclusive with `file`." + }, + "source": { + "type": "string", + "enum": [ + "file", + "provider" + ], + "description": "`provider` makes this a migration from another identity verification provider. Omit for a file import." + }, + "provider": { + "type": "string", + "enum": [ + "sumsub", + "jumio", + "veriff", + "onfido", + "persona", + "metamap", + "socure", + "idnow", + "shufti", + "idenfy", + "ondato", + "trulioo", + "au10tix", + "complycube", + "other" + ], + "description": "Migration source, from `GET /v3/session/imports/providers/`. Required when `source` is `provider`." + }, + "credentials": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "The provider's read-only key, with the field names `credential_fields` lists. Encrypted at rest, never returned, and erased when the import ends. Send it as a JSON string in multipart." + }, + "options": { + "type": "object", + "properties": { + "region": { + "type": "string", + "description": "The provider region, one of its `regions` (Onfido: `eu`, `us`, `ca`)." + } + } + }, + "status_mapping": { + "type": "object", + "additionalProperties": { + "type": "string", + "enum": [ + "Approved", + "Declined", + "In Review", + "Expired", + "Not Finished", + "Abandoned" + ] + }, + "description": "Edits to the provider's default status mapping: source status to Didit status. `Not Finished` and `Abandoned` are skipped and counted, never imported." + }, + "dry_run": { + "type": "boolean", + "default": false, + "description": "Count what the migration would import (by status, already in Didit, same person, not finished) and write nothing. The job ends `READY`; start it with `POST /v3/session/imports/{importId}/start/`." + }, + "face_templates": { + "type": "boolean", + "default": false, + "description": "Build face templates from the imported selfies and search them against the application's faces and blocklist. Matches are flagged for review only. Requires `lawful_basis_confirmed`." + }, + "lawful_basis_confirmed": { + "type": "boolean", + "default": false, + "description": "Confirms you have a lawful basis to share these selfies with Didit as processor." } } } @@ -1599,6 +1674,81 @@ "type": "string", "format": "uri", "description": "Alternative to file upload. Must be an HTTPS URL resolving to a public address (private/loopback networks are rejected). Mutually exclusive with `file`." + }, + "source": { + "type": "string", + "enum": [ + "file", + "provider" + ], + "description": "`provider` makes this a migration from another identity verification provider. Omit for a file import." + }, + "provider": { + "type": "string", + "enum": [ + "sumsub", + "jumio", + "veriff", + "onfido", + "persona", + "metamap", + "socure", + "idnow", + "shufti", + "idenfy", + "ondato", + "trulioo", + "au10tix", + "complycube", + "other" + ], + "description": "Migration source, from `GET /v3/session/imports/providers/`. Required when `source` is `provider`." + }, + "credentials": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "The provider's read-only key, with the field names `credential_fields` lists. Encrypted at rest, never returned, and erased when the import ends. Send it as a JSON string in multipart." + }, + "options": { + "type": "object", + "properties": { + "region": { + "type": "string", + "description": "The provider region, one of its `regions` (Onfido: `eu`, `us`, `ca`)." + } + } + }, + "status_mapping": { + "type": "object", + "additionalProperties": { + "type": "string", + "enum": [ + "Approved", + "Declined", + "In Review", + "Expired", + "Not Finished", + "Abandoned" + ] + }, + "description": "Edits to the provider's default status mapping: source status to Didit status. `Not Finished` and `Abandoned` are skipped and counted, never imported." + }, + "dry_run": { + "type": "boolean", + "default": false, + "description": "Count what the migration would import (by status, already in Didit, same person, not finished) and write nothing. The job ends `READY`; start it with `POST /v3/session/imports/{importId}/start/`." + }, + "face_templates": { + "type": "boolean", + "default": false, + "description": "Build face templates from the imported selfies and search them against the application's faces and blocklist. Matches are flagged for review only. Requires `lawful_basis_confirmed`." + }, + "lawful_basis_confirmed": { + "type": "boolean", + "default": false, + "description": "Confirms you have a lawful basis to share these selfies with Didit as processor." } } }, @@ -1650,7 +1800,7 @@ } }, "400": { - "description": "Invalid workflow, file type, file size, source URL, or selector combination.", + "description": "Invalid workflow, file type, file size, source URL, or selector combination. A migration whose key the provider refuses answers `code` (`invalid_credentials`, `missing_permission`, `wrong_region`, `provider_unavailable`, `rate_limited`, `ids_required`, `record_not_found`), `missing_permissions` and `suggested_region`.", "content": { "application/json": { "examples": { @@ -68276,217 +68426,118 @@ } } }, - "/v3/session/{sessionId}/simulate/": { - "post": { - "summary": "Simulate a sandbox session's status", - "description": "Force a terminal status on a sandbox session after the fact, from your backend, without running the flow. Sandbox applications only: a live session returns `404`. Works for User Verification (KYC) and Business Verification (KYB) sessions.\n\nSet `new_status`, or let `scenario` or `risk` supply it. `risk` (or the first risk the scenario's magic values carry) adds that warning to the session. The change is recorded in the session's activity.\n\n`send_webhooks` (default `true`) sends exactly the webhooks a real status change sends. With `false` the status still changes and the console still updates live, but no webhook is logged or sent, the missed-webhook recovery never re-sends that decision, and the next status change sends webhooks as usual. The response echoes the value applied.\n\nRequires the `write:sessions` privilege; a scoped API key needs write access to sessions. An unknown `session_id` returns `404` and another application's session returns `403`, both before the body is read; a live session returns `404` only after the body is validated. To simulate from the hosted flow with the session's own token, use `POST /v3/session/{sessionId}/sandbox/simulate/`. See [Sandbox & Test Data](/integration/sandbox-testing) for the scenario catalog.", - "operationId": "post_v3_session_simulate", + "/v3/organization/bank-verification-pricing/": { + "get": { + "summary": "Get bank verification prices (public, unauthenticated)", + "description": "Returns the list price of each Bank Verification method in every country: bank sign-in with its balance and transactions add-ons, and the account check. Use it to quote a bank step before you build a workflow, or to show bank prices in your own product.\n\nPublic: send no auth header. The response contains no organization data and is the same for every caller. It is cached publicly for one hour and carries an `ETag`, so send `If-None-Match` to get a `304 Not Modified` when nothing changed.\n\nA method is `available` only where Didit serves it in production today, and its `price_usd` is `null` everywhere else, so the feed never shows a price you cannot buy. `available: false` covers a country with no approved price, a method the country does not support, and a route that is not switched on yet.\n\nThese are list prices before your plan discount. Your plan discount applies to the whole bank price, and a negotiated or contract price replaces the list price for your organization.", + "operationId": "get_v3_bank_verification_pricing", "tags": [ - "Sessions" + "Pricing" ], "security": [ - { - "ApiKeyAuth": [] - } + {} ], - "parameters": [ + "parameters": [], + "x-codeSamples": [ { - "in": "path", - "name": "sessionId", - "required": true, - "description": "UUID of the sandbox verification session. Accepts both user (KYC) and business (KYB) session IDs.", - "schema": { - "type": "string", - "format": "uuid", - "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6" - } + "lang": "curl", + "label": "curl", + "source": "curl -fsS https://verification.didit.me/v3/organization/bank-verification-pricing/" + }, + { + "lang": "python", + "label": "Python", + "source": "import requests\n\nresp = requests.get('https://verification.didit.me/v3/organization/bank-verification-pricing/', timeout=10)\nresp.raise_for_status()\nfeed = resp.json()\nfor iso3, country in feed['countries'].items():\n sign_in = country['methods']['open_banking']\n if sign_in['available']:\n print(iso3, country['name'], sign_in['price_usd'])" + }, + { + "lang": "javascript", + "label": "JavaScript", + "source": "const feed = await fetch('https://verification.didit.me/v3/organization/bank-verification-pricing/').then((r) => r.json());\nconst gbr = feed.countries.GBR.methods;\nconsole.log(gbr.open_banking.available ? gbr.open_banking.price_usd : 'Not available');\nconsole.log(gbr.account_lookup.available ? gbr.account_lookup.price_usd : 'Not available');" } ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SandboxSimulateRequest" - }, - "examples": { - "Scenario Without Webhooks": { - "summary": "Decline through a scenario without sending webhooks", - "value": { - "scenario": "decline_aml_hit", - "send_webhooks": false - } - }, - "Status Only": { - "summary": "Approve and send the usual webhooks", - "value": { - "new_status": "Approved" - } - } - } - } - } + "x-didit-sdk": { + "resource": "pricing", + "method": "bank_verification", + "auth": "none", + "server": true }, "responses": { "200": { - "description": "The status changed.", + "description": "Bank Verification list prices by country.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboxSimulateResponse" + "$ref": "#/components/schemas/BankVerificationPricing" }, "examples": { - "Simulated": { - "summary": "Declined through a scenario, webhooks not sent", - "value": { - "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", - "previous_status": "In Progress", - "status": "Declined", - "scenario": "decline_aml_hit", - "risk": "POSSIBLE_MATCH_FOUND", - "send_webhooks": false - } - } - } - } - } - }, - "400": { - "description": "Validation error: an unknown scenario or risk, no `new_status` when neither `scenario` nor `risk` supplies one, a status this endpoint does not set, or the session already has the requested status (a bare JSON array).", - "content": { - "application/json": { - "examples": { - "Unknown Scenario": { - "summary": "scenario is not in the catalog", - "value": { - "scenario": [ - "Unknown sandbox scenario: 'not-a-scenario'." - ] - } - }, - "Unknown Risk": { - "summary": "risk is not in the catalog", - "value": { - "risk": [ - "Unknown sandbox risk case: 'NOT_A_RISK'." - ] - } - }, - "Missing new_status": { - "summary": "No new_status, scenario or risk", - "value": { - "new_status": [ - "This field is required." - ] - } - }, - "Invalid new_status": { - "summary": "A status the simulation does not set", - "value": { - "new_status": [ - "\"Resubmitted\" is not a valid choice." - ] - } - }, - "Same Status": { - "summary": "The session already has this status", - "value": [ - "The new status is the same as the current status." - ] - } - } - } - } - }, - "401": { - "description": "The scoped API key has expired.", - "content": { - "application/json": { - "examples": { - "Expired API Key": { - "summary": "Scoped API key past its expiry date", + "Two countries": { + "summary": "One country with both methods, one with neither", "value": { - "detail": "This API key has expired." - } - } - } - } - } - }, - "403": { - "description": "Missing or invalid credentials, a caller without the `write:sessions` privilege, a scoped API key without the access this endpoint needs, or a `session_id` that belongs to another application.", - "content": { - "application/json": { - "examples": { - "Invalid Credentials": { - "summary": "Missing or invalid x-api-key", - "value": { - "detail": "Authentication credentials were not provided or are invalid." - } - }, - "Missing Privilege": { - "summary": "Caller lacks write:sessions", - "value": { - "detail": "You do not have permission to perform this action." - } - }, - "Scoped Key Without Access": { - "summary": "Scoped API key without this access", - "value": { - "detail": "This API key has no write access to sessions." - } - } - } - } - } - }, - "404": { - "description": "No session with this `session_id` exists, or it is a live (non-sandbox) session.", - "content": { - "application/json": { - "examples": { - "Not Found": { - "summary": "Unknown or live session", - "value": { - "detail": "Not found." + "currency": "USD", + "statement_upload": { + "price_usd": "0.0000", + "included_after_charged_bank_attempt": true, + "standalone_available": false + }, + "own_provider_fee_usd": "0.0200", + "countries": { + "GBR": { + "name": "United Kingdom", + "methods": { + "open_banking": { + "available": true, + "market": "UK and EEA", + "price_usd": "0.7900", + "add_ons": { + "balance": "0.3500", + "transactions": "1.3000" + } + }, + "account_lookup": { + "available": true, + "price_usd": "0.4000" + } + } + }, + "CAN": { + "name": "Canada", + "methods": { + "open_banking": { + "available": false, + "market": null, + "price_usd": null, + "add_ons": {} + }, + "account_lookup": { + "available": false, + "price_usd": null + } + } + } + } } } } } } - } - }, - "x-codeSamples": [ - { - "lang": "curl", - "label": "curl", - "source": "curl -X POST \\\n https://verification.didit.me/v3/session/3fa85f64-5717-4562-b3fc-2c963f66afa6/simulate/ \\\n -H 'x-api-key: YOUR_API_KEY' \\\n -H 'Content-Type: application/json' \\\n -d '{\"scenario\": \"decline_aml_hit\", \"send_webhooks\": false}'" }, - { - "lang": "python", - "label": "Python", - "source": "import requests\n\nresponse = requests.post(\n \"https://verification.didit.me/v3/session/3fa85f64-5717-4562-b3fc-2c963f66afa6/simulate/\",\n headers={\"x-api-key\": \"YOUR_API_KEY\"},\n json={\"scenario\": \"decline_aml_hit\", \"send_webhooks\": False},\n)\nresponse.raise_for_status()\nprint(response.json())" + "304": { + "description": "Not modified: the `ETag` you sent in `If-None-Match` still matches. No body." } - ], - "x-didit-sdk": { - "resource": "sessions", - "method": "simulate", - "auth": "api_key", - "server": true } } }, - "/v3/session/{sessionId}/sandbox/simulate/": { + "/v3/session/{sessionId}/simulate/": { "post": { - "summary": "Simulate a sandbox session's status from the client", - "description": "The same simulation as `POST /v3/session/{sessionId}/simulate/`, authenticated with the session's own `Session-Token` (returned in `session_token` by [Create Session](/sessions-api/create-session)) instead of your API key, so a test harness or the hosted flow can call it from the client. The body, the response and `send_webhooks` behave exactly as on that endpoint.\n\nA `Session-Token` of a live (non-sandbox) application, or one that does not match the `sessionId` in the path, returns `404`. See [Sandbox & Test Data](/integration/sandbox-testing).", - "operationId": "post_v3_session_sandbox_simulate", + "summary": "Simulate a sandbox session's status", + "description": "Force a terminal status on a sandbox session after the fact, from your backend, without running the flow. Sandbox applications only: a live session returns `404`. Works for User Verification (KYC) and Business Verification (KYB) sessions.\n\nSet `new_status`, or let `scenario` or `risk` supply it. `risk` (or the first risk the scenario's magic values carry) adds that warning to the session. The change is recorded in the session's activity.\n\n`send_webhooks` (default `true`) sends exactly the webhooks a real status change sends. With `false` the status still changes and the console still updates live, but no webhook is logged or sent, the missed-webhook recovery never re-sends that decision, and the next status change sends webhooks as usual. The response echoes the value applied.\n\nRequires the `write:sessions` privilege; a scoped API key needs write access to sessions. An unknown `session_id` returns `404` and another application's session returns `403`, both before the body is read; a live session returns `404` only after the body is validated. To simulate from the hosted flow with the session's own token, use `POST /v3/session/{sessionId}/sandbox/simulate/`. See [Sandbox & Test Data](/integration/sandbox-testing) for the scenario catalog.", + "operationId": "post_v3_session_simulate", "tags": [ "Sessions" ], "security": [ { - "SessionTokenAuth": [] + "ApiKeyAuth": [] } ], "parameters": [ @@ -68494,7 +68545,207 @@ "in": "path", "name": "sessionId", "required": true, - "description": "UUID of the sandbox verification session. Must match the session encoded in the Session-Token used to authenticate.", + "description": "UUID of the sandbox verification session. Accepts both user (KYC) and business (KYB) session IDs.", + "schema": { + "type": "string", + "format": "uuid", + "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxSimulateRequest" + }, + "examples": { + "Scenario Without Webhooks": { + "summary": "Decline through a scenario without sending webhooks", + "value": { + "scenario": "decline_aml_hit", + "send_webhooks": false + } + }, + "Status Only": { + "summary": "Approve and send the usual webhooks", + "value": { + "new_status": "Approved" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "The status changed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxSimulateResponse" + }, + "examples": { + "Simulated": { + "summary": "Declined through a scenario, webhooks not sent", + "value": { + "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "previous_status": "In Progress", + "status": "Declined", + "scenario": "decline_aml_hit", + "risk": "POSSIBLE_MATCH_FOUND", + "send_webhooks": false + } + } + } + } + } + }, + "400": { + "description": "Validation error: an unknown scenario or risk, no `new_status` when neither `scenario` nor `risk` supplies one, a status this endpoint does not set, or the session already has the requested status (a bare JSON array).", + "content": { + "application/json": { + "examples": { + "Unknown Scenario": { + "summary": "scenario is not in the catalog", + "value": { + "scenario": [ + "Unknown sandbox scenario: 'not-a-scenario'." + ] + } + }, + "Unknown Risk": { + "summary": "risk is not in the catalog", + "value": { + "risk": [ + "Unknown sandbox risk case: 'NOT_A_RISK'." + ] + } + }, + "Missing new_status": { + "summary": "No new_status, scenario or risk", + "value": { + "new_status": [ + "This field is required." + ] + } + }, + "Invalid new_status": { + "summary": "A status the simulation does not set", + "value": { + "new_status": [ + "\"Resubmitted\" is not a valid choice." + ] + } + }, + "Same Status": { + "summary": "The session already has this status", + "value": [ + "The new status is the same as the current status." + ] + } + } + } + } + }, + "401": { + "description": "The scoped API key has expired.", + "content": { + "application/json": { + "examples": { + "Expired API Key": { + "summary": "Scoped API key past its expiry date", + "value": { + "detail": "This API key has expired." + } + } + } + } + } + }, + "403": { + "description": "Missing or invalid credentials, a caller without the `write:sessions` privilege, a scoped API key without the access this endpoint needs, or a `session_id` that belongs to another application.", + "content": { + "application/json": { + "examples": { + "Invalid Credentials": { + "summary": "Missing or invalid x-api-key", + "value": { + "detail": "Authentication credentials were not provided or are invalid." + } + }, + "Missing Privilege": { + "summary": "Caller lacks write:sessions", + "value": { + "detail": "You do not have permission to perform this action." + } + }, + "Scoped Key Without Access": { + "summary": "Scoped API key without this access", + "value": { + "detail": "This API key has no write access to sessions." + } + } + } + } + } + }, + "404": { + "description": "No session with this `session_id` exists, or it is a live (non-sandbox) session.", + "content": { + "application/json": { + "examples": { + "Not Found": { + "summary": "Unknown or live session", + "value": { + "detail": "Not found." + } + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "curl", + "label": "curl", + "source": "curl -X POST \\\n https://verification.didit.me/v3/session/3fa85f64-5717-4562-b3fc-2c963f66afa6/simulate/ \\\n -H 'x-api-key: YOUR_API_KEY' \\\n -H 'Content-Type: application/json' \\\n -d '{\"scenario\": \"decline_aml_hit\", \"send_webhooks\": false}'" + }, + { + "lang": "python", + "label": "Python", + "source": "import requests\n\nresponse = requests.post(\n \"https://verification.didit.me/v3/session/3fa85f64-5717-4562-b3fc-2c963f66afa6/simulate/\",\n headers={\"x-api-key\": \"YOUR_API_KEY\"},\n json={\"scenario\": \"decline_aml_hit\", \"send_webhooks\": False},\n)\nresponse.raise_for_status()\nprint(response.json())" + } + ], + "x-didit-sdk": { + "resource": "sessions", + "method": "simulate", + "auth": "api_key", + "server": true + } + } + }, + "/v3/session/{sessionId}/sandbox/simulate/": { + "post": { + "summary": "Simulate a sandbox session's status from the client", + "description": "The same simulation as `POST /v3/session/{sessionId}/simulate/`, authenticated with the session's own `Session-Token` (returned in `session_token` by [Create Session](/sessions-api/create-session)) instead of your API key, so a test harness or the hosted flow can call it from the client. The body, the response and `send_webhooks` behave exactly as on that endpoint.\n\nA `Session-Token` of a live (non-sandbox) application, or one that does not match the `sessionId` in the path, returns `404`. See [Sandbox & Test Data](/integration/sandbox-testing).", + "operationId": "post_v3_session_sandbox_simulate", + "tags": [ + "Sessions" + ], + "security": [ + { + "SessionTokenAuth": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "sessionId", + "required": true, + "description": "UUID of the sandbox verification session. Must match the session encoded in the Session-Token used to authenticate.", "schema": { "type": "string", "format": "uuid", @@ -72665,6 +72916,717 @@ } } } + }, + "/v3/session/imports/providers/": { + "get": { + "summary": "List migration providers", + "description": "The 15 providers you can migrate verifications from: what each needs to connect, whether its API can list records, the permissions its key needs and its default status mapping.", + "operationId": "get_v3_session_imports_providers_list", + "x-didit-sdk": { + "resource": "sessions.imports", + "method": "list_providers", + "auth": "api_key", + "server": true + }, + "tags": [ + "Sessions" + ], + "responses": { + "200": { + "description": "Migration providers.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "providers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImportProvider" + } + }, + "mapping_targets": { + "type": "array", + "items": { + "type": "string" + } + }, + "skipped_statuses": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + }, + "403": { + "description": "Missing, invalid, or revoked API key, or the caller cannot import verifications for this application.", + "content": { + "application/json": { + "examples": { + "Forbidden": { + "value": { + "detail": "You do not have permission to perform this action." + } + } + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/v3/session/imports/providers/check/": { + "post": { + "summary": "Check a provider key", + "description": "Read the provider with your key before creating a migration. Nothing is stored.", + "operationId": "post_v3_session_imports_providers_check", + "x-didit-sdk": { + "resource": "sessions.imports", + "method": "check_provider", + "auth": "api_key", + "server": true + }, + "tags": [ + "Sessions" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "provider": { + "type": "string", + "enum": [ + "sumsub", + "jumio", + "veriff", + "onfido", + "persona", + "metamap", + "socure", + "idnow", + "shufti", + "idenfy", + "ondato", + "trulioo", + "au10tix", + "complycube", + "other" + ], + "description": "Migration source, from `GET /v3/session/imports/providers/`. Required when `source` is `provider`." + }, + "credentials": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "The provider's read-only key, with the field names `credential_fields` lists. Encrypted at rest, never returned, and erased when the import ends. Send it as a JSON string in multipart." + }, + "options": { + "type": "object", + "properties": { + "region": { + "type": "string", + "description": "The provider region, one of its `regions` (Onfido: `eu`, `us`, `ca`)." + } + } + }, + "record_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "For `api_ids` providers: the first record ID of your export." + } + }, + "required": [ + "provider", + "credentials" + ] + } + } + } + }, + "responses": { + "200": { + "description": "The key can read records.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "ok": { + "type": "boolean" + }, + "provider": { + "type": "string" + }, + "credential_hint": { + "type": "string", + "nullable": true + } + } + } + } + } + }, + "400": { + "description": "The provider refused the key: `code`, `detail`, `missing_permissions`, `suggested_region`." + }, + "403": { + "description": "Missing, invalid, or revoked API key, or the caller cannot import verifications for this application.", + "content": { + "application/json": { + "examples": { + "Forbidden": { + "value": { + "detail": "You do not have permission to perform this action." + } + } + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/v3/session/imports/{importId}/start/": { + "post": { + "summary": "Start a dry run", + "description": "Start a migration whose dry run finished (`READY`): the same job imports for real, with the status mapping and face templates choice as sent now.", + "operationId": "post_v3_session_imports_start", + "x-didit-sdk": { + "resource": "sessions.imports", + "method": "start", + "auth": "api_key", + "server": true + }, + "tags": [ + "Sessions" + ], + "parameters": [ + { + "name": "importId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status_mapping": { + "type": "object", + "additionalProperties": { + "type": "string", + "enum": [ + "Approved", + "Declined", + "In Review", + "Expired", + "Not Finished", + "Abandoned" + ] + }, + "description": "Edits to the provider's default status mapping: source status to Didit status. `Not Finished` and `Abandoned` are skipped and counted, never imported." + }, + "face_templates": { + "type": "boolean", + "default": false, + "description": "Build face templates from the imported selfies and search them against the application's faces and blocklist. Matches are flagged for review only. Requires `lawful_basis_confirmed`." + }, + "lawful_basis_confirmed": { + "type": "boolean", + "default": false, + "description": "Confirms you have a lawful basis to share these selfies with Didit as processor." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "The import job.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionImportJob" + } + } + } + }, + "400": { + "description": "The job is not in a state this action applies to." + }, + "403": { + "description": "Missing, invalid, or revoked API key, or the caller cannot import verifications for this application.", + "content": { + "application/json": { + "examples": { + "Forbidden": { + "value": { + "detail": "You do not have permission to perform this action." + } + } + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/v3/session/imports/{importId}/pause/": { + "post": { + "summary": "Pause an import job", + "description": "Pause a queued or running import.", + "operationId": "post_v3_session_imports_pause", + "x-didit-sdk": { + "resource": "sessions.imports", + "method": "pause", + "auth": "api_key", + "server": true + }, + "tags": [ + "Sessions" + ], + "parameters": [ + { + "name": "importId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "The import job.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionImportJob" + } + } + } + }, + "400": { + "description": "The job is not in a state this action applies to." + }, + "403": { + "description": "Missing, invalid, or revoked API key, or the caller cannot import verifications for this application.", + "content": { + "application/json": { + "examples": { + "Forbidden": { + "value": { + "detail": "You do not have permission to perform this action." + } + } + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/v3/session/imports/{importId}/resume/": { + "post": { + "summary": "Resume an import job", + "description": "Resume an import you paused. A job paused by the provider's rate limit resumes by itself.", + "operationId": "post_v3_session_imports_resume", + "x-didit-sdk": { + "resource": "sessions.imports", + "method": "resume", + "auth": "api_key", + "server": true + }, + "tags": [ + "Sessions" + ], + "parameters": [ + { + "name": "importId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "The import job.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionImportJob" + } + } + } + }, + "400": { + "description": "The job is not in a state this action applies to." + }, + "403": { + "description": "Missing, invalid, or revoked API key, or the caller cannot import verifications for this application.", + "content": { + "application/json": { + "examples": { + "Forbidden": { + "value": { + "detail": "You do not have permission to perform this action." + } + } + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/v3/session/imports/{importId}/cancel/": { + "post": { + "summary": "Cancel an import job", + "description": "Cancel an import. What was imported stays; the uploaded file and the key are erased.", + "operationId": "post_v3_session_imports_cancel", + "x-didit-sdk": { + "resource": "sessions.imports", + "method": "cancel", + "auth": "api_key", + "server": true + }, + "tags": [ + "Sessions" + ], + "parameters": [ + { + "name": "importId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "The import job.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionImportJob" + } + } + } + }, + "400": { + "description": "The job is not in a state this action applies to." + }, + "403": { + "description": "Missing, invalid, or revoked API key, or the caller cannot import verifications for this application.", + "content": { + "application/json": { + "examples": { + "Forbidden": { + "value": { + "detail": "You do not have permission to perform this action." + } + } + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/v3/session/imports/{importId}/retry/": { + "post": { + "summary": "Retry a migration", + "description": "Run a migration that ended again as a new job, with a new key (the old one was erased). It keeps the provider, workflow, region, status mapping and face templates choice; everything already in Didit is skipped.", + "operationId": "post_v3_session_imports_retry", + "x-didit-sdk": { + "resource": "sessions.imports", + "method": "retry", + "auth": "api_key", + "server": true + }, + "tags": [ + "Sessions" + ], + "parameters": [ + { + "name": "importId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "required": false, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "credentials": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "The provider's read-only key, with the field names `credential_fields` lists. Encrypted at rest, never returned, and erased when the import ends. Send it as a JSON string in multipart." + }, + "file": { + "type": "string", + "format": "binary", + "description": "The record IDs or export file again, for `api_ids` and `export_file` providers." + } + } + } + } + } + }, + "responses": { + "201": { + "description": "The new import job.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionImportJob" + } + } + } + }, + "400": { + "description": "Not a migration, not ended, or the provider refused the key." + }, + "403": { + "description": "Missing, invalid, or revoked API key, or the caller cannot import verifications for this application.", + "content": { + "application/json": { + "examples": { + "Forbidden": { + "value": { + "detail": "You do not have permission to perform this action." + } + } + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/v3/import-jobs/": { + "get": { + "summary": "List import jobs", + "description": "Every import of the application in one shape: verification imports and migrations, people and businesses.", + "operationId": "get_v3_import_jobs_list", + "x-didit-sdk": { + "resource": "sessions.imports", + "method": "list_jobs", + "auth": "api_key", + "server": true + }, + "tags": [ + "Sessions" + ], + "parameters": [ + { + "name": "scope", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "all", + "sessions", + "users", + "businesses" + ], + "default": "all" + } + }, + { + "name": "limit", + "in": "query", + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50 + } + } + ], + "responses": { + "200": { + "description": "Import jobs, newest first.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImportJobSummary" + } + }, + "counts": { + "type": "object", + "properties": { + "all": { + "type": "integer" + }, + "running_and_waiting": { + "type": "integer" + }, + "needs_attention": { + "type": "integer" + }, + "done": { + "type": "integer" + } + } + } + } + } + } + } + }, + "403": { + "description": "Missing, invalid, or revoked API key, or the caller cannot import verifications for this application.", + "content": { + "application/json": { + "examples": { + "Forbidden": { + "value": { + "detail": "You do not have permission to perform this action." + } + } + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } + }, + "/v3/import-jobs/active/": { + "get": { + "summary": "List active import jobs", + "description": "What is running or waiting, plus what just ended, for a progress indicator.", + "operationId": "get_v3_import_jobs_active", + "x-didit-sdk": { + "resource": "sessions.imports", + "method": "list_active_jobs", + "auth": "api_key", + "server": true + }, + "tags": [ + "Sessions" + ], + "responses": { + "200": { + "description": "Active import jobs.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImportJobSummary" + } + }, + "running": { + "type": "integer" + } + } + } + } + } + }, + "403": { + "description": "Missing, invalid, or revoked API key, or the caller cannot import verifications for this application.", + "content": { + "application/json": { + "examples": { + "Forbidden": { + "value": { + "detail": "You do not have permission to perform this action." + } + } + } + } + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + } + ] + } } }, "components": { @@ -72774,7 +73736,8 @@ "COMPLETED", "FAILED", "PAUSED", - "CANCELLED" + "CANCELLED", + "READY" ] }, "import_type": { @@ -72849,6 +73812,99 @@ "type": "string", "format": "date-time", "nullable": true + }, + "state": { + "type": "string", + "enum": [ + "ready", + "queued", + "running", + "paused", + "completed", + "errors", + "failed", + "cancelled" + ], + "description": "The job's state as the console shows it; `errors` is a completed job with rejected rows." + }, + "source": { + "type": "string", + "enum": [ + "file", + "api", + "provider" + ] + }, + "provider": { + "type": "string", + "description": "Migration source; empty for a file or API import." + }, + "provider_options": { + "type": "object" + }, + "credential_hint": { + "type": "string", + "description": "The first characters of the key the migration holds. The key itself is never returned." + }, + "credentials_expires_at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "resumes_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When a job paused by the provider's rate limit resumes by itself." + }, + "status_mapping": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "is_dry_run": { + "type": "boolean" + }, + "dry_run_summary": { + "type": "object", + "description": "What a dry run found: `total`, `by_status`, `already_in_didit`, `same_person`, `not_finished`, `failed`, `unmapped_statuses`." + }, + "face_templates_enabled": { + "type": "boolean" + }, + "lawful_basis_confirmed_at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "not_finished_count": { + "type": "integer", + "format": "int64" + }, + "same_person_count": { + "type": "integer", + "format": "int64" + }, + "face_templates_count": { + "type": "integer", + "format": "int64" + }, + "face_duplicates_count": { + "type": "integer", + "format": "int64" + }, + "face_blocklist_hits_count": { + "type": "integer", + "format": "int64" + }, + "created_by_name": { + "type": "string", + "nullable": true + }, + "created_by_email": { + "type": "string", + "nullable": true } } }, @@ -92295,7 +93351,7 @@ "bank_verifications": { "type": "array", "nullable": true, - "description": "Bank Verification results, one item per Bank Verification step, for User and Business Verification. `null` until a step produces one. Each item's `method` says how the account was verified: `open_banking` (bank sign-in) or `account_lookup` (account check), or a `microdeposits` or `statement` fallback. See [Bank verification methods](/core-technology/bank-verification/verification-methods).", + "description": "Bank Verification results, one item per Bank Verification step, for User and Business Verification. `null` until a step produces one. Each item's `method` says how the account was verified: `open_banking` (bank sign-in) or `account_lookup` (account check), or a `statement` or `microdeposits` fallback, and `none` when the person continued without a bank before any attempt was evaluated (`continued_without_bank`). See [Bank verification methods](/core-technology/bank-verification/verification-methods).", "items": { "$ref": "#/components/schemas/BankVerificationResult" } @@ -94735,6 +95791,26 @@ "updated_at": { "type": "string", "format": "date-time" + }, + "is_bank_verification_enabled": { + "type": "boolean", + "description": "Whether a simple KYC or KYB workflow runs Bank verification. It runs after the contact steps and before database validation, AML and IP analysis. Set in the console." + }, + "bank_verification_config": { + "type": "object", + "additionalProperties": true, + "description": "Bank verification settings of a simple workflow, with the same keys a `BANK_VERIFICATION` node takes (for example `bank_countries` and `bank_method_order`). Every key is optional and an absent key keeps its default, so `{}` means all defaults. See [Bank verification settings](/management-api/workflows/feature-configs#bank-verification).", + "example": {} + }, + "is_geolocation_enabled": { + "type": "boolean", + "description": "Whether a simple KYC workflow runs Location verification. It runs after the contact steps and before Bank verification. Never on KYB workflows. Set in the console." + }, + "geolocation_config": { + "type": "object", + "additionalProperties": true, + "description": "Location verification settings of a simple workflow, with the same keys a `GEOLOCATION` node takes (for example `is_geolocation_geofencing_enabled` and `geolocation_max_attempts`). Every key is optional and an absent key keeps its default, so `{}` means all defaults.", + "example": {} } }, "additionalProperties": true @@ -104141,7 +105217,7 @@ }, "BankVerificationResult": { "type": "object", - "description": "One Bank Verification step's result, for User and Business Verification. `method` says how the account was verified. See [Bank verification methods](/core-technology/bank-verification/verification-methods).", + "description": "One Bank Verification step's result, for User and Business Verification. `method` says how the account was verified, and `none` that the person continued without a bank before any attempt was evaluated. `continued_without_bank` says the person continued without a bank, also after an evaluated attempt. See [Bank verification methods](/core-technology/bank-verification/verification-methods) and [When the person cannot verify their bank](/core-technology/bank-verification/fallbacks).", "properties": { "schema_version": { "type": "integer", @@ -104179,9 +105255,10 @@ "open_banking", "account_lookup", "microdeposits", - "statement" + "statement", + "none" ], - "description": "How the account was verified: `open_banking` (bank sign-in: the person signed in at their bank), `account_lookup` (account check: the person typed the account details and the bank confirmed the name), `microdeposits` or `statement` (a statement upload). `null` until an account is evaluated. Workflow rules read the same value as `bank.method`." + "description": "How the account was verified: `open_banking` (bank sign-in: the person signed in at their bank), `account_lookup` (account check: the person typed the account details and the bank confirmed the name), `microdeposits` or `statement` (a statement upload). `none` when the person continued without a bank before any attempt was evaluated, so no account was verified. After an evaluated attempt, it stays the method of that attempt. `null` until an account is evaluated, and when the workflow narrows the data it returns. Workflow rules read the same value as `bank.method`." }, "provider": { "type": "string", @@ -104552,7 +105629,7 @@ "usage_type": { "type": "string", "nullable": true, - "description": "The usage line the charge was booked on." + "description": "The usage line the charge was booked on: `bank_verification` for a bank sign-in or an account check, `bank_statement_upload` for a statement upload with no charged bank attempt before it, and `bank_byok_fee` for the marketplace fee on your own provider. `null` when nothing was billed." } } }, @@ -104574,7 +105651,61 @@ "not_covered": { "type": "boolean", "nullable": true, - "description": "Whether the person's bank or country could not be reached on this step." + "description": "Whether the person's bank or country could not be reached on this step. Also `true` when the person continued without a bank because no method could verify their country or bank." + }, + "continued_without_bank": { + "type": "boolean", + "description": "Whether the person left the step with **Continue without your bank**. `continuation` then says why. `method` is `none` when no attempt was evaluated before they continued. After an evaluated attempt, such as a holder that does not match, `method` stays the method of that attempt and its verdict and reason codes stand. Returned even when the workflow narrows the data it returns." + }, + "continuation": { + "type": "object", + "nullable": true, + "description": "How the person continued without a bank. `null` when they did not. When the workflow narrows the data it returns, `reason` is still returned and every other key is `null`.", + "properties": { + "reason": { + "type": "string", + "enum": [ + "no_route", + "institution_unsupported", + "attempts_exhausted", + "person_choice" + ], + "description": "Why, as Didit worked it out when the person continued: `no_route` (no bank sign-in or account check serves their country), `institution_unsupported` (the bank they picked cannot be used on this step), `attempts_exhausted` (every attempt was already spent and none was in progress), or `person_choice` (a way to verify was there and they chose to continue, also when their bank could not be reached right now). `no_route` and `institution_unsupported` follow `bank_unsupported_action`, `attempts_exhausted` follows `bank_attempts_exhausted_action`, and `person_choice` follows `bank_skipped_action`, unless an evaluated attempt already decided the step." + }, + "country": { + "type": "string", + "nullable": true, + "description": "The country the person was verifying in, ISO 3166-1 alpha-3. `null` when they continued before picking one." + }, + "offered": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "statement", + "microdeposits" + ] + }, + "nullable": true, + "description": "The other ways to verify that country offered the person when they continued, in the order it offered them: `statement` (a statement upload), then `microdeposits`. Empty when it offered none." + }, + "institution_id": { + "type": "string", + "nullable": true, + "description": "For `institution_unsupported`, the ID of the bank the person could not use: the bank they picked, or the bank their last attempt ended on. Didit takes it from its own list of banks, never from the person's device, so a bank that list does not have is `null`. `null` for every other reason." + }, + "institution_name": { + "type": "string", + "nullable": true, + "description": "For `institution_unsupported`, the name of that bank, from the same list as `institution_id`. `null` when that list does not have the bank, and for every other reason." + }, + "continued_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the person continued." + } + } }, "evidence_purged_at": { "type": "string", @@ -104594,7 +105725,7 @@ "items": { "type": "string" }, - "description": "Why the verdict came out the way it did, for example `OWNER_NAME_PARTIAL`. Several may apply." + "description": "Why the verdict came out the way it did, for example `OWNER_NAME_PARTIAL`. Several may apply. `NOT_COVERED`: the person continued without a bank because no method could verify their country or bank. `SKIPPED`: the person chose to continue without a bank while a way to verify was there. Neither is added when an evaluated attempt already decided the step." }, "created_at": { "type": "string", @@ -104634,6 +105765,416 @@ "description": "The name of the company that should hold the account. Checks a business account." } } + }, + "BankVerificationPricing": { + "type": "object", + "description": "Public Bank Verification list prices: the statement upload, the own provider key fee and each country's methods.", + "required": [ + "currency", + "statement_upload", + "own_provider_fee_usd", + "countries" + ], + "properties": { + "currency": { + "type": "string", + "enum": [ + "USD" + ], + "description": "Currency of every price in the response.", + "example": "USD" + }, + "statement_upload": { + "$ref": "#/components/schemas/BankStatementUploadPricing" + }, + "own_provider_fee_usd": { + "type": "string", + "description": "Fee for each billable ownership check on a route that uses your own provider contract instead of Didit's, charged whatever the result. A cancelled, timed out or abandoned connection is not billed. Decimal string with 4 decimals, in USD.", + "example": "0.0200" + }, + "countries": { + "type": "object", + "description": "Every country, keyed by ISO 3166-1 alpha-3 code.", + "additionalProperties": { + "$ref": "#/components/schemas/BankVerificationPricingCountry" + } + } + } + }, + "BankStatementUploadPricing": { + "type": "object", + "description": "How the bank statement upload is priced.", + "required": [ + "price_usd", + "included_after_charged_bank_attempt", + "standalone_available" + ], + "properties": { + "price_usd": { + "type": "string", + "description": "Price of a statement upload after a charged bank attempt. Decimal string with 4 decimals, in USD.", + "example": "0.0000" + }, + "included_after_charged_bank_attempt": { + "type": "boolean", + "description": "`true` when the upload is included at no extra charge after a charged bank attempt in the same session.", + "example": true + }, + "standalone_available": { + "type": "boolean", + "description": "`true` when a statement upload can run on its own, with no bank attempt first. `false` in production; sandbox sessions can test it without billing.", + "example": false + } + } + }, + "BankVerificationPricingCountry": { + "type": "object", + "description": "One country's Bank Verification methods and their list prices.", + "required": [ + "name", + "methods" + ], + "properties": { + "name": { + "type": "string", + "description": "Country name in English.", + "example": "United Kingdom" + }, + "methods": { + "$ref": "#/components/schemas/BankVerificationPricingMethods" + } + } + }, + "BankVerificationPricingMethods": { + "type": "object", + "description": "The two Bank Verification methods in a country.", + "required": [ + "open_banking", + "account_lookup" + ], + "properties": { + "open_banking": { + "$ref": "#/components/schemas/BankSignInPricing" + }, + "account_lookup": { + "$ref": "#/components/schemas/BankAccountCheckPricing" + } + } + }, + "BankSignInPricing": { + "type": "object", + "description": "Bank sign-in: the person signs in to their bank. Priced by market, the same for every bank in it.", + "required": [ + "available", + "market", + "price_usd", + "add_ons" + ], + "properties": { + "available": { + "type": "boolean", + "description": "`true` only where Didit serves bank sign-in in this country in production.", + "example": true + }, + "market": { + "type": "string", + "nullable": true, + "description": "The market whose price applies. `null` when not available.", + "example": "UK and EEA" + }, + "price_usd": { + "type": "string", + "nullable": true, + "description": "List price of one bank sign-in. `null` when not available. Decimal string with 4 decimals, in USD.", + "example": "0.7900" + }, + "add_ons": { + "type": "object", + "description": "Add-ons priced in this country, each a decimal string with 4 decimals in USD, added to the bank sign-in price. Only the add-ons the country offers are listed; empty when bank sign-in is not available.", + "properties": { + "balance": { + "type": "string", + "description": "Account balance add-on.", + "example": "0.3500" + }, + "transactions": { + "type": "string", + "description": "Transactions add-on.", + "example": "1.3000" + } + } + } + } + }, + "BankAccountCheckPricing": { + "type": "object", + "description": "Account check: the person types their account number and Didit checks it with the bank. Priced per country.", + "required": [ + "available", + "price_usd" + ], + "properties": { + "available": { + "type": "boolean", + "description": "`true` only where Didit serves the account check in this country in production.", + "example": true + }, + "price_usd": { + "type": "string", + "nullable": true, + "description": "List price of one account check the bank answers. `null` when not available. Decimal string with 4 decimals, in USD.", + "example": "0.4000" + } + } + }, + "ImportProvider": { + "type": "object", + "properties": { + "key": { + "type": "string", + "enum": [ + "sumsub", + "jumio", + "veriff", + "onfido", + "persona", + "metamap", + "socure", + "idnow", + "shufti", + "idenfy", + "ondato", + "trulioo", + "au10tix", + "complycube", + "other" + ] + }, + "name": { + "type": "string" + }, + "mode": { + "type": "string", + "enum": [ + "api_list", + "api_ids", + "export_file" + ], + "description": "`api_list`: Didit lists records with the key. `api_ids`: upload the record IDs from an export. `export_file`: upload an export in Didit's format." + }, + "record_noun": { + "type": "string" + }, + "credential_fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "label": { + "type": "string" + }, + "secret": { + "type": "boolean" + } + } + } + }, + "regions": { + "type": "array", + "items": { + "type": "string" + } + }, + "required_permissions": { + "type": "array", + "items": { + "type": "string" + } + }, + "docs_url": { + "type": "string", + "nullable": true + }, + "status_mapping": { + "type": "object", + "additionalProperties": { + "type": "string", + "enum": [ + "Approved", + "Declined", + "In Review", + "Expired", + "Not Finished", + "Abandoned" + ] + } + } + } + }, + "ImportJobSummary": { + "type": "object", + "description": "One import job of any kind, in the shape the console's Import jobs drawer reads.", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "kind": { + "type": "string", + "enum": [ + "sessions", + "businesses", + "users", + "status_rules", + "transactions" + ] + }, + "source": { + "type": "string", + "enum": [ + "file", + "api", + "provider" + ] + }, + "provider": { + "type": "string", + "nullable": true + }, + "provider_name": { + "type": "string", + "nullable": true + }, + "filename": { + "type": "string", + "nullable": true + }, + "state": { + "type": "string", + "enum": [ + "ready", + "queued", + "running", + "paused", + "completed", + "errors", + "failed", + "cancelled" + ], + "description": "The job's state as the console shows it; `errors` is a completed job with rejected rows." + }, + "status": { + "type": "string" + }, + "is_dry_run": { + "type": "boolean" + }, + "credential_hint": { + "type": "string", + "nullable": true + }, + "resumes_at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "last_error": { + "type": "string", + "nullable": true + }, + "started_by": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "email": { + "type": "string", + "nullable": true + } + } + }, + "progress": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "processed": { + "type": "integer", + "format": "int64" + }, + "imported": { + "type": "integer", + "format": "int64" + }, + "updated": { + "type": "integer", + "format": "int64" + }, + "already_in_didit": { + "type": "integer", + "format": "int64" + }, + "failed": { + "type": "integer", + "format": "int64" + }, + "not_finished": { + "type": "integer", + "format": "int64" + }, + "same_person": { + "type": "integer", + "format": "int64" + } + } + }, + "face_templates": { + "type": "object", + "nullable": true, + "properties": { + "enabled": { + "type": "boolean" + }, + "built": { + "type": "integer", + "format": "int64" + }, + "duplicates": { + "type": "integer", + "format": "int64" + }, + "blocklisted": { + "type": "integer", + "format": "int64" + } + } + }, + "eta_seconds": { + "type": "integer", + "nullable": true + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "started_at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "completed_at": { + "type": "string", + "format": "date-time", + "nullable": true + } + } } }, "securitySchemes": { diff --git a/src/resources/date-plans.ts b/src/resources/date-plans.ts index 514f2a4..08802dd 100644 --- a/src/resources/date-plans.ts +++ b/src/resources/date-plans.ts @@ -50,6 +50,7 @@ export const DATE_PLANS: Readonly> = { p: { connection: { p: { connected_at: 1, consent_expires_at: 1, last_refreshed_at: 1 } }, ownership: { p: { evaluated_at: 1 } }, + continuation: { p: { continued_at: 1 } }, evidence_purged_at: 1, created_at: 1, updated_at: 1, @@ -169,6 +170,7 @@ export const DATE_PLANS: Readonly> = { FraudCheckResponse: { p: { created_at: 1, completed_at: 1 } }, IPRiskResponse: { p: { created_at: 1 } }, IdVerificationVerifyResponse: { p: { created_at: 1 } }, + ImportJobSummary: { p: { resumes_at: 1, created_at: 1, started_at: 1, completed_at: 1 } }, InvestigatorBlock: { p: { prepared_at: 1, decision: "InvestigatorDecision" } }, InvestigatorDecision: { p: { @@ -376,13 +378,25 @@ export const DATE_PLANS: Readonly> = { SessionDeletionJob: { p: { created_at: 1, completed_at: 1 } }, SessionEvent: { p: { created_at: 1 } }, SessionImportError: { p: { created_at: 1 } }, - SessionImportJob: { p: { created_at: 1, updated_at: 1, started_at: 1, completed_at: 1 } }, + SessionImportJob: { + p: { + created_at: 1, + updated_at: 1, + started_at: 1, + completed_at: 1, + credentials_expires_at: 1, + resumes_at: 1, + lawful_basis_confirmed_at: 1, + }, + }, SessionWebhookDelivery: { p: { created_at: 1 } }, SessionsBatchDeleteResponse: { p: { results: { i: { p: { biometric_template_expires_at: 1 } } } }, }, SessionsDeleteResponse: { p: { biometric_template_expires_at: 1 } }, + SessionsImportsListActiveJobsResponse: { p: { results: { i: "ImportJobSummary" } } }, SessionsImportsListErrorsResponse: { p: { results: { i: "SessionImportError" } } }, + SessionsImportsListJobsResponse: { p: { results: { i: "ImportJobSummary" } } }, SessionsListAmlScreeningHistoryResponse: { p: { results: { i: "AMLScreeningRun" } } }, SessionsListEventsResponse: { p: { results: { i: "SessionEvent" } } }, SessionsListFeatureOverridesResponse: { diff --git a/src/resources/index.ts b/src/resources/index.ts index 77d2d82..86b9d74 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -32,6 +32,7 @@ import { MonitoringEvents } from "./monitoring-events.js"; import { Networks } from "./networks.js"; import { PassiveLiveness } from "./passive-liveness.js"; import { Phone } from "./phone.js"; +import { Pricing } from "./pricing.js"; import { ProofOfAddress } from "./proof-of-address.js"; import { Questionnaires } from "./questionnaires.js"; import { RegulatoryReports } from "./regulatory-reports.js"; @@ -76,6 +77,7 @@ export abstract class DiditResources extends APIClient { readonly networks: Networks = new Networks(this); readonly passiveLiveness: PassiveLiveness = new PassiveLiveness(this); readonly phone: Phone = new Phone(this); + readonly pricing: Pricing = new Pricing(this); readonly proofOfAddress: ProofOfAddress = new ProofOfAddress(this); readonly questionnaires: Questionnaires = new Questionnaires(this); readonly regulatoryReports: RegulatoryReports = new RegulatoryReports(this); @@ -128,6 +130,7 @@ export { MonitoringEvents } from "./monitoring-events.js"; export { Networks, NetworksNotes } from "./networks.js"; export { PassiveLiveness } from "./passive-liveness.js"; export { Phone } from "./phone.js"; +export { Pricing } from "./pricing.js"; export { ProofOfAddress } from "./proof-of-address.js"; export { Questionnaires } from "./questionnaires.js"; export { RegulatoryReports } from "./regulatory-reports.js"; diff --git a/src/resources/pricing.ts b/src/resources/pricing.ts new file mode 100644 index 0000000..301d5bc --- /dev/null +++ b/src/resources/pricing.ts @@ -0,0 +1,33 @@ +// Code generated by codegen from openapi/*.json. DO NOT EDIT. + +import type { APIPromise } from "../core/api-promise.js"; +import type { OperationSpec } from "../core/operation.js"; +import type { RequestOptions } from "../core/request-options.js"; +import { APIResource } from "../core/resource.js"; +import type { BankVerificationPricing } from "../types/components.js"; + +const PRICING_BANK_VERIFICATION: OperationSpec = { + method: "GET", + path: "/v3/organization/bank-verification-pricing/", + auth: "none", +}; + +/** `pricing` */ +export class Pricing extends APIResource { + /** + * Get bank verification prices (public, unauthenticated) + * + * Returns the list price of each Bank Verification method in every country: bank sign-in with its balance and transactions add-ons, and the account check. Use it to quote a bank step before you build a workflow, or to show bank prices in your own product. + * + * Public: send no auth header. The response contains no organization data and is the same for every caller. It is cached publicly for one hour and carries an `ETag`, so send `If-None-Match` to get a `304 Not Modified` when nothing changed. + * + * A method is `available` only where Didit serves it in production today, and its `price_usd` is `null` everywhere else, so the feed never shows a price you cannot buy. `available: false` covers a country with no approved price, a method the country does not support, and a route that is not switched on yet. + * + * These are list prices before your plan discount. Your plan discount applies to the whole bank price, and a negotiated or contract price replaces the list price for your organization. + * + * `GET /v3/organization/bank-verification-pricing/` + */ + bankVerification(options?: RequestOptions): APIPromise { + return this._client.request(PRICING_BANK_VERIFICATION, [], undefined, options); + } +} diff --git a/src/resources/sessions.ts b/src/resources/sessions.ts index 143e4b3..b1f333e 100644 --- a/src/resources/sessions.ts +++ b/src/resources/sessions.ts @@ -34,10 +34,18 @@ import type { SessionsDeleteResponse, SessionsExportAmlScreeningHistoryParams, SessionsImportSharedParams, + SessionsImportsCheckProviderParams, + SessionsImportsCheckProviderResponse, SessionsImportsCreateParams, + SessionsImportsListActiveJobsResponse, SessionsImportsListErrorsParams, SessionsImportsListErrorsResponse, + SessionsImportsListJobsParams, + SessionsImportsListJobsResponse, + SessionsImportsListProvidersResponse, SessionsImportsRetrieveTemplateParams, + SessionsImportsRetryParams, + SessionsImportsStartParams, SessionsListAmlScreeningHistoryParams, SessionsListAmlScreeningHistoryResponse, SessionsListEventsParams, @@ -80,6 +88,16 @@ import type { SessionsUpdateStatusResponse, } from "../types/sessions.js"; +const SESSIONS_IMPORTS_CANCEL: OperationSpec = { + method: "POST", + path: "/v3/session/imports/{importId}/cancel/", + dates: "SessionImportJob", +}; +const SESSIONS_IMPORTS_CHECK_PROVIDER: OperationSpec = { + method: "POST", + path: "/v3/session/imports/providers/check/", + body: "json", +}; const SESSIONS_IMPORTS_CREATE: OperationSpec = { method: "POST", path: "/v3/session/imports/", @@ -87,12 +105,37 @@ const SESSIONS_IMPORTS_CREATE: OperationSpec = { files: ["file"], dates: "SessionImportJob", }; +const SESSIONS_IMPORTS_LIST_ACTIVE_JOBS: OperationSpec = { + method: "GET", + path: "/v3/import-jobs/active/", + dates: { p: { results: { i: "ImportJobSummary" } } }, +}; const SESSIONS_IMPORTS_LIST_ERRORS: OperationSpec = { method: "GET", path: "/v3/session/imports/{importId}/errors/", query: ["limit", "offset"], dates: { p: { results: { i: "SessionImportError" } } }, }; +const SESSIONS_IMPORTS_LIST_JOBS: OperationSpec = { + method: "GET", + path: "/v3/import-jobs/", + query: ["scope", "limit"], + dates: { p: { results: { i: "ImportJobSummary" } } }, +}; +const SESSIONS_IMPORTS_LIST_PROVIDERS: OperationSpec = { + method: "GET", + path: "/v3/session/imports/providers/", +}; +const SESSIONS_IMPORTS_PAUSE: OperationSpec = { + method: "POST", + path: "/v3/session/imports/{importId}/pause/", + dates: "SessionImportJob", +}; +const SESSIONS_IMPORTS_RESUME: OperationSpec = { + method: "POST", + path: "/v3/session/imports/{importId}/resume/", + dates: "SessionImportJob", +}; const SESSIONS_IMPORTS_RETRIEVE: OperationSpec = { method: "GET", path: "/v3/session/imports/{importId}/", @@ -105,6 +148,19 @@ const SESSIONS_IMPORTS_RETRIEVE_TEMPLATE: OperationSpec = { response: "binary", accept: "text/csv", }; +const SESSIONS_IMPORTS_RETRY: OperationSpec = { + method: "POST", + path: "/v3/session/imports/{importId}/retry/", + body: "multipart", + files: ["file"], + dates: "SessionImportJob", +}; +const SESSIONS_IMPORTS_START: OperationSpec = { + method: "POST", + path: "/v3/session/imports/{importId}/start/", + body: "json", + dates: "SessionImportJob", +}; const SESSIONS_REVIEWS_CREATE: OperationSpec = { method: "POST", path: "/v3/sessions/{session_id}/reviews/", @@ -347,10 +403,37 @@ const SESSIONS_UPDATE_STATUS: OperationSpec = { /** `sessions.imports` */ export class SessionsImports extends APIResource { + /** + * Cancel an import job + * + * Cancel an import. What was imported stays; the uploaded file and the key are erased. + * + * `POST /v3/session/imports/{importId}/cancel/` + * + * @param importId importId + */ + cancel(importId: string, options?: RequestOptions): APIPromise { + return this._client.request(SESSIONS_IMPORTS_CANCEL, [importId], undefined, options); + } + + /** + * Check a provider key + * + * Read the provider with your key before creating a migration. Nothing is stored. + * + * `POST /v3/session/imports/providers/check/` + */ + checkProvider( + params: SessionsImportsCheckProviderParams, + options?: RequestOptions, + ): APIPromise { + return this._client.request(SESSIONS_IMPORTS_CHECK_PROVIDER, [], params, options); + } + /** * Create a verification import job * - * Create an asynchronous import job for historical User Verification sessions, Business Verification sessions, transaction monitoring records, or workflow custom status rules. Use this to migrate from providers such as Sumsub, MetaMap, Veriff, Onfido, Persona, Trulioo, Jumio, Incode, iDenfy, or any other provider after transforming the export into Didit's canonical CSV/NDJSON format. Imports are disabled by default and must be enabled per organization by Didit. + * Create an asynchronous import job for historical User Verification sessions, Business Verification sessions, transaction monitoring records, or workflow custom status rules. Set `source=provider` to migrate from another provider: Didit reads Sumsub, Onfido, Persona and ComplyCube with your read-only key, reads Veriff, iDenfy and MetaMap records by the IDs you upload in `file`, and imports an export file in Didit's format for the other providers. Record IDs are namespaced by provider (`sumsub:`) so a re-run skips everything already in Didit. Imports are disabled by default and must be enabled per organization by Didit. * * `POST /v3/session/imports/` */ @@ -361,6 +444,17 @@ export class SessionsImports extends APIResource { return this._client.request(SESSIONS_IMPORTS_CREATE, [], params, options); } + /** + * List active import jobs + * + * What is running or waiting, plus what just ended, for a progress indicator. + * + * `GET /v3/import-jobs/active/` + */ + listActiveJobs(options?: RequestOptions): APIPromise { + return this._client.request(SESSIONS_IMPORTS_LIST_ACTIVE_JOBS, [], undefined, options); + } + /** * List verification import row errors * @@ -378,6 +472,57 @@ export class SessionsImports extends APIResource { return this._client.requestPage(SESSIONS_IMPORTS_LIST_ERRORS, [importId], params, options); } + /** + * List import jobs + * + * Every import of the application in one shape: verification imports and migrations, people and businesses. + * + * `GET /v3/import-jobs/` + */ + listJobs( + params: SessionsImportsListJobsParams = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.request(SESSIONS_IMPORTS_LIST_JOBS, [], params, options); + } + + /** + * List migration providers + * + * The 15 providers you can migrate verifications from: what each needs to connect, whether its API can list records, the permissions its key needs and its default status mapping. + * + * `GET /v3/session/imports/providers/` + */ + listProviders(options?: RequestOptions): APIPromise { + return this._client.request(SESSIONS_IMPORTS_LIST_PROVIDERS, [], undefined, options); + } + + /** + * Pause an import job + * + * Pause a queued or running import. + * + * `POST /v3/session/imports/{importId}/pause/` + * + * @param importId importId + */ + pause(importId: string, options?: RequestOptions): APIPromise { + return this._client.request(SESSIONS_IMPORTS_PAUSE, [importId], undefined, options); + } + + /** + * Resume an import job + * + * Resume an import you paused. A job paused by the provider's rate limit resumes by itself. + * + * `POST /v3/session/imports/{importId}/resume/` + * + * @param importId importId + */ + resume(importId: string, options?: RequestOptions): APIPromise { + return this._client.request(SESSIONS_IMPORTS_RESUME, [importId], undefined, options); + } + /** * Retrieve a verification import job * @@ -404,6 +549,40 @@ export class SessionsImports extends APIResource { ): APIPromise { return this._client.request(SESSIONS_IMPORTS_RETRIEVE_TEMPLATE, [], params, options); } + + /** + * Retry a migration + * + * Run a migration that ended again as a new job, with a new key (the old one was erased). It keeps the provider, workflow, region, status mapping and face templates choice; everything already in Didit is skipped. + * + * `POST /v3/session/imports/{importId}/retry/` + * + * @param importId importId + */ + retry( + importId: string, + params: SessionsImportsRetryParams = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.request(SESSIONS_IMPORTS_RETRY, [importId], params, options); + } + + /** + * Start a dry run + * + * Start a migration whose dry run finished (`READY`): the same job imports for real, with the status mapping and face templates choice as sent now. + * + * `POST /v3/session/imports/{importId}/start/` + * + * @param importId importId + */ + start( + importId: string, + params: SessionsImportsStartParams = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.request(SESSIONS_IMPORTS_START, [importId], params, options); + } } /** `sessions.reviews` */ diff --git a/src/types/components.ts b/src/types/components.ts index 64dffd5..51e326e 100644 --- a/src/types/components.ts +++ b/src/types/components.ts @@ -1048,6 +1048,14 @@ export interface BankAccountCheckPersonHolder { full_name: string; } +/** Account check: the person types their account number and Didit checks it with the bank. Priced per country. */ +export interface BankAccountCheckPricing { + /** `true` only where Didit serves the account check in this country in production. */ + available: boolean; + /** List price of one account check the bank answers. `null` when not available. Decimal string with 4 decimals, in USD. */ + price_usd: string | null; +} + export interface BankAccountCheckResponse { /** The ID of this check. */ request_id: string; @@ -1063,7 +1071,65 @@ export interface BankAccountCheckResponse { created_at: Date; } -/** One Bank Verification step's result, for User and Business Verification. `method` says how the account was verified. See [Bank verification methods](/core-technology/bank-verification/verification-methods). */ +/** Bank sign-in: the person signs in to their bank. Priced by market, the same for every bank in it. */ +export interface BankSignInPricing { + /** `true` only where Didit serves bank sign-in in this country in production. */ + available: boolean; + /** The market whose price applies. `null` when not available. */ + market: string | null; + /** List price of one bank sign-in. `null` when not available. Decimal string with 4 decimals, in USD. */ + price_usd: string | null; + /** Add-ons priced in this country, each a decimal string with 4 decimals in USD, added to the bank sign-in price. Only the add-ons the country offers are listed; empty when bank sign-in is not available. */ + add_ons: BankSignInPricingAddOns; +} + +/** Add-ons priced in this country, each a decimal string with 4 decimals in USD, added to the bank sign-in price. Only the add-ons the country offers are listed; empty when bank sign-in is not available. */ +export interface BankSignInPricingAddOns { + /** Account balance add-on. */ + balance?: string; + /** Transactions add-on. */ + transactions?: string; +} + +/** How the bank statement upload is priced. */ +export interface BankStatementUploadPricing { + /** Price of a statement upload after a charged bank attempt. Decimal string with 4 decimals, in USD. */ + price_usd: string; + /** `true` when the upload is included at no extra charge after a charged bank attempt in the same session. */ + included_after_charged_bank_attempt: boolean; + /** `true` when a statement upload can run on its own, with no bank attempt first. `false` in production; sandbox sessions can test it without billing. */ + standalone_available: boolean; +} + +/** Public Bank Verification list prices: the statement upload, the own provider key fee and each country's methods. */ +export interface BankVerificationPricing { + /** Currency of every price in the response. */ + currency: "USD" | (string & {}); + /** How the bank statement upload is priced. */ + statement_upload: BankStatementUploadPricing; + /** Fee for each billable ownership check on a route that uses your own provider contract instead of Didit's, charged whatever the result. A cancelled, timed out or abandoned connection is not billed. Decimal string with 4 decimals, in USD. */ + own_provider_fee_usd: string; + /** Every country, keyed by ISO 3166-1 alpha-3 code. */ + countries: Record; +} + +/** One country's Bank Verification methods and their list prices. */ +export interface BankVerificationPricingCountry { + /** Country name in English. */ + name: string; + /** The two Bank Verification methods in a country. */ + methods: BankVerificationPricingMethods; +} + +/** The two Bank Verification methods in a country. */ +export interface BankVerificationPricingMethods { + /** Bank sign-in: the person signs in to their bank. Priced by market, the same for every bank in it. */ + open_banking: BankSignInPricing; + /** Account check: the person types their account number and Didit checks it with the bank. Priced per country. */ + account_lookup: BankAccountCheckPricing; +} + +/** One Bank Verification step's result, for User and Business Verification. `method` says how the account was verified, and `none` that the person continued without a bank before any attempt was evaluated. `continued_without_bank` says the person continued without a bank, also after an evaluated attempt. See [Bank verification methods](/core-technology/bank-verification/verification-methods) and [When the person cannot verify their bank](/core-technology/bank-verification/fallbacks). */ export interface BankVerificationResult { /** Version of this result shape. `1` today. */ schema_version?: number; @@ -1075,8 +1141,15 @@ export interface BankVerificationResult { status?: "Not Finished" | "Approved" | "Declined" | "In Review" | "Expired" | (string & {}); /** The first verdict the step reached, before any later change such as a manual review. */ original_status?: string | null; - /** How the account was verified: `open_banking` (bank sign-in: the person signed in at their bank), `account_lookup` (account check: the person typed the account details and the bank confirmed the name), `microdeposits` or `statement` (a statement upload). `null` until an account is evaluated. Workflow rules read the same value as `bank.method`. */ - method?: "open_banking" | "account_lookup" | "microdeposits" | "statement" | (string & {}) | null; + /** How the account was verified: `open_banking` (bank sign-in: the person signed in at their bank), `account_lookup` (account check: the person typed the account details and the bank confirmed the name), `microdeposits` or `statement` (a statement upload). `none` when the person continued without a bank before any attempt was evaluated, so no account was verified. After an evaluated attempt, it stays the method of that attempt. `null` until an account is evaluated, and when the workflow narrows the data it returns. Workflow rules read the same value as `bank.method`. */ + method?: + | "open_banking" + | "account_lookup" + | "microdeposits" + | "statement" + | "none" + | (string & {}) + | null; /** The key of the route that ran the connection. Read `method`, not this key, to tell how the account was verified. */ provider?: string | null; /** `native`: Didit's own route, billed to your Didit balance. `byok`: a marketplace provider you connected with your own credentials. */ @@ -1098,13 +1171,17 @@ export interface BankVerificationResult { signals?: Record | null; /** Whether the step ended without a match after the person left at their bank. */ connection_abandoned?: boolean | null; - /** Whether the person's bank or country could not be reached on this step. */ + /** Whether the person's bank or country could not be reached on this step. Also `true` when the person continued without a bank because no method could verify their country or bank. */ not_covered?: boolean | null; + /** Whether the person left the step with **Continue without your bank**. `continuation` then says why. `method` is `none` when no attempt was evaluated before they continued. After an evaluated attempt, such as a holder that does not match, `method` stays the method of that attempt and its verdict and reason codes stand. Returned even when the workflow narrows the data it returns. */ + continued_without_bank?: boolean; + /** How the person continued without a bank. `null` when they did not. When the workflow narrows the data it returns, `reason` is still returned and every other key is `null`. */ + continuation?: BankVerificationResultContinuation | null; /** When the bank evidence was deleted under `bank_evidence_retention_days`. `null` otherwise. */ evidence_purged_at?: Date | null; /** Informational codes, for example `holder_declared`. A warning never changes the status on its own. */ warnings?: string[]; - /** Why the verdict came out the way it did, for example `OWNER_NAME_PARTIAL`. Several may apply. */ + /** Why the verdict came out the way it did, for example `OWNER_NAME_PARTIAL`. Several may apply. `NOT_COVERED`: the person continued without a bank because no method could verify their country or bank. `SKIPPED`: the person chose to continue without a bank while a way to verify was there. Neither is added when an evaluated attempt already decided the step. */ reason_codes?: string[]; created_at?: Date; updated_at?: Date; @@ -1136,7 +1213,7 @@ export interface BankVerificationResultBilling { billed?: boolean; /** The marketplace platform fee charged, for `byok`. */ marketplace_fee?: string | null; - /** The usage line the charge was booked on. */ + /** The usage line the charge was booked on: `bank_verification` for a bank sign-in or an account check, `bank_statement_upload` for a statement upload with no charged bank attempt before it, and `bank_byok_fee` for the marketplace fee on your own provider. `null` when nothing was billed. */ usage_type?: string | null; } @@ -1172,6 +1249,23 @@ export interface BankVerificationResultConnection { reason_code?: string | null; } +/** How the person continued without a bank. `null` when they did not. When the workflow narrows the data it returns, `reason` is still returned and every other key is `null`. */ +export interface BankVerificationResultContinuation { + /** Why, as Didit worked it out when the person continued: `no_route` (no bank sign-in or account check serves their country), `institution_unsupported` (the bank they picked cannot be used on this step), `attempts_exhausted` (every attempt was already spent and none was in progress), or `person_choice` (a way to verify was there and they chose to continue, also when their bank could not be reached right now). `no_route` and `institution_unsupported` follow `bank_unsupported_action`, `attempts_exhausted` follows `bank_attempts_exhausted_action`, and `person_choice` follows `bank_skipped_action`, unless an evaluated attempt already decided the step. */ + reason?: + "no_route" | "institution_unsupported" | "attempts_exhausted" | "person_choice" | (string & {}); + /** The country the person was verifying in, ISO 3166-1 alpha-3. `null` when they continued before picking one. */ + country?: string | null; + /** The other ways to verify that country offered the person when they continued, in the order it offered them: `statement` (a statement upload), then `microdeposits`. Empty when it offered none. */ + offered?: ("statement" | "microdeposits" | (string & {}))[] | null; + /** For `institution_unsupported`, the ID of the bank the person could not use: the bank they picked, or the bank their last attempt ended on. Didit takes it from its own list of banks, never from the person's device, so a bank that list does not have is `null`. `null` for every other reason. */ + institution_id?: string | null; + /** For `institution_unsupported`, the name of that bank, from the same list as `institution_id`. `null` when that list does not have the bank, and for every other reason. */ + institution_name?: string | null; + /** When the person continued. */ + continued_at?: Date | null; +} + /** The financial data the step read. Only bank sign-in reads it. */ export interface BankVerificationResultFinancialData { /** With the `balances` scope. */ @@ -3441,6 +3535,100 @@ export interface IPRiskResponseIp { threat: Record; } +/** One import job of any kind, in the shape the console's Import jobs drawer reads. */ +export interface ImportJobSummary { + id?: string; + kind?: "sessions" | "businesses" | "users" | "status_rules" | "transactions" | (string & {}); + source?: "file" | "api" | "provider" | (string & {}); + provider?: string | null; + provider_name?: string | null; + filename?: string | null; + /** The job's state as the console shows it; `errors` is a completed job with rejected rows. */ + state?: + | "ready" + | "queued" + | "running" + | "paused" + | "completed" + | "errors" + | "failed" + | "cancelled" + | (string & {}); + status?: string; + is_dry_run?: boolean; + credential_hint?: string | null; + resumes_at?: Date | null; + last_error?: string | null; + started_by?: ImportJobSummaryStartedBy; + progress?: ImportJobSummaryProgress; + face_templates?: ImportJobSummaryFaceTemplates | null; + eta_seconds?: number | null; + created_at?: Date; + started_at?: Date | null; + completed_at?: Date | null; +} + +export interface ImportJobSummaryFaceTemplates { + enabled?: boolean; + built?: number; + duplicates?: number; + blocklisted?: number; +} + +export interface ImportJobSummaryProgress { + total?: number; + processed?: number; + imported?: number; + updated?: number; + already_in_didit?: number; + failed?: number; + not_finished?: number; + same_person?: number; +} + +export interface ImportJobSummaryStartedBy { + name?: string | null; + email?: string | null; +} + +export interface ImportProvider { + key?: + | "sumsub" + | "jumio" + | "veriff" + | "onfido" + | "persona" + | "metamap" + | "socure" + | "idnow" + | "shufti" + | "idenfy" + | "ondato" + | "trulioo" + | "au10tix" + | "complycube" + | "other" + | (string & {}); + name?: string; + /** `api_list`: Didit lists records with the key. `api_ids`: upload the record IDs from an export. `export_file`: upload an export in Didit's format. */ + mode?: "api_list" | "api_ids" | "export_file" | (string & {}); + record_noun?: string; + credential_fields?: ImportProviderCredentialFields[]; + regions?: string[]; + required_permissions?: string[]; + docs_url?: string | null; + status_mapping?: Record< + string, + "Approved" | "Declined" | "In Review" | "Expired" | "Not Finished" | "Abandoned" | (string & {}) + >; +} + +export interface ImportProviderCredentialFields { + name?: string; + label?: string; + secret?: boolean; +} + export interface InvestigatorBatchAcceptResponse { accepted?: number; skipped?: number; @@ -5733,7 +5921,7 @@ export interface SessionDecision { document_ai_documents?: SessionDecisionDocumentAiDocuments[] | null; /** **Array of questionnaire response reports** - always a JSON array, never a singular `questionnaire` object. `null` until at least one questionnaire step has produced data. Each item is the full report, including `node_id`, the questionnaire metadata, sections with form elements, and the user's answers. */ questionnaire_responses?: SessionDecisionQuestionnaireResponses[] | null; - /** Bank Verification results, one item per Bank Verification step, for User and Business Verification. `null` until a step produces one. Each item's `method` says how the account was verified: `open_banking` (bank sign-in) or `account_lookup` (account check), or a `microdeposits` or `statement` fallback. See [Bank verification methods](/core-technology/bank-verification/verification-methods). */ + /** Bank Verification results, one item per Bank Verification step, for User and Business Verification. `null` until a step produces one. Each item's `method` says how the account was verified: `open_banking` (bank sign-in) or `account_lookup` (account check), or a `statement` or `microdeposits` fallback, and `none` when the person continued without a bank before any attempt was evaluated (`continued_without_bank`). See [Bank verification methods](/core-technology/bank-verification/verification-methods). */ bank_verifications?: BankVerificationResult[] | null; /** Electronic Signature results, one item per signer and signature step, for User and Business Verification. Present only when the workflow has an Electronic Signature step; an empty array until a signer reaches it. See the [Electronic Signature report](/core-technology/electronic-signature/report-electronic-signature). */ signatures?: SignatureResult[]; @@ -8222,7 +8410,14 @@ export interface SessionImportJob { /** Import job id. Use this value to poll progress and fetch row errors. */ uuid: string; status: - "PENDING" | "PROCESSING" | "COMPLETED" | "FAILED" | "PAUSED" | "CANCELLED" | (string & {}); + | "PENDING" + | "PROCESSING" + | "COMPLETED" + | "FAILED" + | "PAUSED" + | "CANCELLED" + | "READY" + | (string & {}); import_type: "user_verification" | "business_verification" | "status_rules" | "transactions" | (string & {}); source_format: "csv" | "ndjson" | (string & {}); @@ -8240,6 +8435,39 @@ export interface SessionImportJob { updated_at?: Date; started_at?: Date | null; completed_at?: Date | null; + /** The job's state as the console shows it; `errors` is a completed job with rejected rows. */ + state?: + | "ready" + | "queued" + | "running" + | "paused" + | "completed" + | "errors" + | "failed" + | "cancelled" + | (string & {}); + source?: "file" | "api" | "provider" | (string & {}); + /** Migration source; empty for a file or API import. */ + provider?: string; + provider_options?: Record; + /** The first characters of the key the migration holds. The key itself is never returned. */ + credential_hint?: string; + credentials_expires_at?: Date | null; + /** When a job paused by the provider's rate limit resumes by itself. */ + resumes_at?: Date | null; + status_mapping?: Record; + is_dry_run?: boolean; + /** What a dry run found: `total`, `by_status`, `already_in_didit`, `same_person`, `not_finished`, `failed`, `unmapped_statuses`. */ + dry_run_summary?: Record; + face_templates_enabled?: boolean; + lawful_basis_confirmed_at?: Date | null; + not_finished_count?: number; + same_person_count?: number; + face_templates_count?: number; + face_duplicates_count?: number; + face_blocklist_hits_count?: number; + created_by_name?: string | null; + created_by_email?: string | null; } export interface SessionSignDocument { @@ -11156,6 +11384,14 @@ export interface WorkflowDetail { kyb_role_settings?: Record[]; created_at?: Date; updated_at?: Date; + /** Whether a simple KYC or KYB workflow runs Bank verification. It runs after the contact steps and before database validation, AML and IP analysis. Set in the console. */ + is_bank_verification_enabled?: boolean; + /** Bank verification settings of a simple workflow, with the same keys a `BANK_VERIFICATION` node takes (for example `bank_countries` and `bank_method_order`). Every key is optional and an absent key keeps its default, so `{}` means all defaults. See [Bank verification settings](/management-api/workflows/feature-configs#bank-verification). */ + bank_verification_config?: Record; + /** Whether a simple KYC workflow runs Location verification. It runs after the contact steps and before Bank verification. Never on KYB workflows. Set in the console. */ + is_geolocation_enabled?: boolean; + /** Location verification settings of a simple workflow, with the same keys a `GEOLOCATION` node takes (for example `is_geolocation_geofencing_enabled` and `geolocation_max_attempts`). Every key is optional and an absent key keeps its default, so `{}` means all defaults. */ + geolocation_config?: Record; [key: string]: unknown; } diff --git a/src/types/sessions.ts b/src/types/sessions.ts index 67d2262..540ae93 100644 --- a/src/types/sessions.ts +++ b/src/types/sessions.ts @@ -5,6 +5,8 @@ import type { AMLScreeningRun, BusinessSessionListItem, FeatureStatusOverride, + ImportJobSummary, + ImportProvider, ReviewItem, SessionEvent, SessionImportError, @@ -396,6 +398,43 @@ export interface SessionsImportSharedParams { vendor_data?: string | null; } +export interface SessionsImportsCheckProviderParams { + /** Migration source, from `GET /v3/session/imports/providers/`. Required when `source` is `provider`. */ + provider: + | "sumsub" + | "jumio" + | "veriff" + | "onfido" + | "persona" + | "metamap" + | "socure" + | "idnow" + | "shufti" + | "idenfy" + | "ondato" + | "trulioo" + | "au10tix" + | "complycube" + | "other" + | (string & {}); + /** The provider's read-only key, with the field names `credential_fields` lists. Encrypted at rest, never returned, and erased when the import ends. Send it as a JSON string in multipart. */ + credentials: Record; + options?: SessionsImportsCheckProviderParamsOptions; + /** For `api_ids` providers: the first record ID of your export. */ + record_ids?: string[]; +} + +export interface SessionsImportsCheckProviderParamsOptions { + /** The provider region, one of its `regions` (Onfido: `eu`, `us`, `ca`). */ + region?: string; +} + +export interface SessionsImportsCheckProviderResponse { + ok?: boolean; + provider?: string; + credential_hint?: string | null; +} + export interface SessionsImportsCreateParams { /** What to import: historical User Verification sessions, historical Business Verification sessions, workflow custom status rules, or historical transaction monitoring records. */ import_type?: @@ -406,10 +445,54 @@ export interface SessionsImportsCreateParams { source_format?: "csv" | "ndjson" | (string & {}); /** Alternative to file upload. Must be an HTTPS URL resolving to a public address (private/loopback networks are rejected). Mutually exclusive with `file`. */ source_file_url?: string; + /** `provider` makes this a migration from another identity verification provider. Omit for a file import. */ + source?: "file" | "provider" | (string & {}); + /** Migration source, from `GET /v3/session/imports/providers/`. Required when `source` is `provider`. */ + provider?: + | "sumsub" + | "jumio" + | "veriff" + | "onfido" + | "persona" + | "metamap" + | "socure" + | "idnow" + | "shufti" + | "idenfy" + | "ondato" + | "trulioo" + | "au10tix" + | "complycube" + | "other" + | (string & {}); + /** The provider's read-only key, with the field names `credential_fields` lists. Encrypted at rest, never returned, and erased when the import ends. Send it as a JSON string in multipart. */ + credentials?: Record; + options?: SessionsImportsCreateParamsOptions; + /** Edits to the provider's default status mapping: source status to Didit status. `Not Finished` and `Abandoned` are skipped and counted, never imported. */ + status_mapping?: Record< + string, + "Approved" | "Declined" | "In Review" | "Expired" | "Not Finished" | "Abandoned" | (string & {}) + >; + /** Count what the migration would import (by status, already in Didit, same person, not finished) and write nothing. The job ends `READY`; start it with `POST /v3/session/imports/{importId}/start/`. */ + dry_run?: boolean; + /** Build face templates from the imported selfies and search them against the application's faces and blocklist. Matches are flagged for review only. Requires `lawful_basis_confirmed`. */ + face_templates?: boolean; + /** Confirms you have a lawful basis to share these selfies with Didit as processor. */ + lawful_basis_confirmed?: boolean; /** Canonical CSV or NDJSON file. Use NDJSON for large imports. Maximum upload size 25 MB (use `source_file_url` for bigger files). Mutually exclusive with `source_file_url`. */ file?: Uploadable; } +export interface SessionsImportsCreateParamsOptions { + /** The provider region, one of its `regions` (Onfido: `eu`, `us`, `ca`). */ + region?: string; +} + +export interface SessionsImportsListActiveJobsResponse { + results?: ImportJobSummary[]; + running?: number; +} + export interface SessionsImportsListErrorsParams { /** Page size. Defaults to 50 when omitted. */ limit?: number; @@ -427,11 +510,53 @@ export interface SessionsImportsListErrorsResponse { results?: SessionImportError[]; } +export interface SessionsImportsListJobsParams { + scope?: "all" | "sessions" | "users" | "businesses" | (string & {}); + limit?: number; +} + +export interface SessionsImportsListJobsResponse { + results?: ImportJobSummary[]; + counts?: SessionsImportsListJobsResponseCounts; +} + +export interface SessionsImportsListJobsResponseCounts { + all?: number; + running_and_waiting?: number; + needs_attention?: number; + done?: number; +} + +export interface SessionsImportsListProvidersResponse { + providers?: ImportProvider[]; + mapping_targets?: string[]; + skipped_statuses?: string[]; +} + export interface SessionsImportsRetrieveTemplateParams { import_type?: "user_verification" | "business_verification" | "status_rules" | "transactions" | (string & {}); } +export interface SessionsImportsRetryParams { + /** The provider's read-only key, with the field names `credential_fields` lists. Encrypted at rest, never returned, and erased when the import ends. Send it as a JSON string in multipart. */ + credentials?: Record; + /** The record IDs or export file again, for `api_ids` and `export_file` providers. */ + file?: Uploadable; +} + +export interface SessionsImportsStartParams { + /** Edits to the provider's default status mapping: source status to Didit status. `Not Finished` and `Abandoned` are skipped and counted, never imported. */ + status_mapping?: Record< + string, + "Approved" | "Declined" | "In Review" | "Expired" | "Not Finished" | "Abandoned" | (string & {}) + >; + /** Build face templates from the imported selfies and search them against the application's faces and blocklist. Matches are flagged for review only. Requires `lawful_basis_confirmed`. */ + face_templates?: boolean; + /** Confirms you have a lawful basis to share these selfies with Didit as processor. */ + lawful_basis_confirmed?: boolean; +} + export interface SessionsListAmlScreeningHistoryParams { /** Workflow graph node ID of the AML check. Needed only when the session ran more than one AML step; without it the most recent AML check is used. An unknown node returns `404`. */ node_id?: string; diff --git a/tests/generated/pricing.test.ts b/tests/generated/pricing.test.ts new file mode 100644 index 0000000..e42f3c6 --- /dev/null +++ b/tests/generated/pricing.test.ts @@ -0,0 +1,34 @@ +// Code generated by codegen from openapi/*.json. DO NOT EDIT. + +import { describe, expect, it } from "vitest"; + +import { + API_ORIGIN, + expectAuth, + expectMatchesExample, + mockClient, + responseExample, +} from "../helpers/mock-api.js"; + +describe("pricing", () => { + it("pricing.bank_verification: GET /v3/organization/bank-verification-pricing/", async () => { + const { client, calls } = mockClient({ + status: 200, + json: responseExample("GET /v3/organization/bank-verification-pricing/"), + }); + const result = await client.pricing.bankVerification(); + expect(calls).toHaveLength(1); + const request = calls[0]!; + expect(request.method).toBe("GET"); + expect(request.origin).toBe(API_ORIGIN); + expect(request.path).toBe("/v3/organization/bank-verification-pricing/"); + expect(request.query).toEqual({}); + expectAuth(request, "none"); + expect(request.headers.get("accept")).toBe("application/json"); + expect(request.bodyText).toBe(""); + expectMatchesExample( + result, + responseExample("GET /v3/organization/bank-verification-pricing/"), + ); + }); +}); diff --git a/tests/generated/sessions.test.ts b/tests/generated/sessions.test.ts index eeb25da..60d2af1 100644 --- a/tests/generated/sessions.test.ts +++ b/tests/generated/sessions.test.ts @@ -229,6 +229,46 @@ describe("sessions", () => { expectMatchesExample(result, responseExample("POST /v3/session/import-shared/")); }); + it("sessions.imports.cancel: POST /v3/session/imports/{importId}/cancel/", async () => { + const { client, calls } = mockClient({ + status: 200, + json: responseExample("POST /v3/session/imports/{importId}/cancel/"), + }); + const result = await client.sessions.imports.cancel("importId-1"); + expect(calls).toHaveLength(1); + const request = calls[0]!; + expect(request.method).toBe("POST"); + expect(request.origin).toBe(API_ORIGIN); + expect(request.path).toBe("/v3/session/imports/importId-1/cancel/"); + expect(request.query).toEqual({}); + expectAuth(request, "api_key"); + expect(request.headers.get("accept")).toBe("application/json"); + expect(request.bodyText).toBe(""); + expectMatchesExample(result, responseExample("POST /v3/session/imports/{importId}/cancel/")); + }); + + it("sessions.imports.check_provider: POST /v3/session/imports/providers/check/", async () => { + const { client, calls } = mockClient({ + status: 200, + json: responseExample("POST /v3/session/imports/providers/check/"), + }); + const result = await client.sessions.imports.checkProvider({ + provider: "sumsub", + credentials: {}, + }); + expect(calls).toHaveLength(1); + const request = calls[0]!; + expect(request.method).toBe("POST"); + expect(request.origin).toBe(API_ORIGIN); + expect(request.path).toBe("/v3/session/imports/providers/check/"); + expect(request.query).toEqual({}); + expectAuth(request, "api_key"); + expect(request.headers.get("accept")).toBe("application/json"); + expect(request.contentType).toBe("application/json"); + expect(request.json).toEqual({ provider: "sumsub", credentials: {} }); + expectMatchesExample(result, responseExample("POST /v3/session/imports/providers/check/")); + }); + it("sessions.imports.create: POST /v3/session/imports/", async () => { const { client, calls } = mockClient({ status: 201, @@ -248,6 +288,24 @@ describe("sessions", () => { expectMatchesExample(result, responseExample("POST /v3/session/imports/")); }); + it("sessions.imports.list_active_jobs: GET /v3/import-jobs/active/", async () => { + const { client, calls } = mockClient({ + status: 200, + json: responseExample("GET /v3/import-jobs/active/"), + }); + const result = await client.sessions.imports.listActiveJobs(); + expect(calls).toHaveLength(1); + const request = calls[0]!; + expect(request.method).toBe("GET"); + expect(request.origin).toBe(API_ORIGIN); + expect(request.path).toBe("/v3/import-jobs/active/"); + expect(request.query).toEqual({}); + expectAuth(request, "api_key"); + expect(request.headers.get("accept")).toBe("application/json"); + expect(request.bodyText).toBe(""); + expectMatchesExample(result, responseExample("GET /v3/import-jobs/active/")); + }); + it("sessions.imports.list_errors: GET /v3/session/imports/{importId}/errors/", async () => { const { client, calls } = mockClient({ status: 200, @@ -270,6 +328,78 @@ describe("sessions", () => { expect(page.hasNextPage()).toBe(false); }); + it("sessions.imports.list_jobs: GET /v3/import-jobs/", async () => { + const { client, calls } = mockClient({ + status: 200, + json: responseExample("GET /v3/import-jobs/"), + }); + const result = await client.sessions.imports.listJobs(); + expect(calls).toHaveLength(1); + const request = calls[0]!; + expect(request.method).toBe("GET"); + expect(request.origin).toBe(API_ORIGIN); + expect(request.path).toBe("/v3/import-jobs/"); + expect(request.query).toEqual({}); + expectAuth(request, "api_key"); + expect(request.headers.get("accept")).toBe("application/json"); + expect(request.bodyText).toBe(""); + expectMatchesExample(result, responseExample("GET /v3/import-jobs/")); + }); + + it("sessions.imports.list_providers: GET /v3/session/imports/providers/", async () => { + const { client, calls } = mockClient({ + status: 200, + json: responseExample("GET /v3/session/imports/providers/"), + }); + const result = await client.sessions.imports.listProviders(); + expect(calls).toHaveLength(1); + const request = calls[0]!; + expect(request.method).toBe("GET"); + expect(request.origin).toBe(API_ORIGIN); + expect(request.path).toBe("/v3/session/imports/providers/"); + expect(request.query).toEqual({}); + expectAuth(request, "api_key"); + expect(request.headers.get("accept")).toBe("application/json"); + expect(request.bodyText).toBe(""); + expectMatchesExample(result, responseExample("GET /v3/session/imports/providers/")); + }); + + it("sessions.imports.pause: POST /v3/session/imports/{importId}/pause/", async () => { + const { client, calls } = mockClient({ + status: 200, + json: responseExample("POST /v3/session/imports/{importId}/pause/"), + }); + const result = await client.sessions.imports.pause("importId-1"); + expect(calls).toHaveLength(1); + const request = calls[0]!; + expect(request.method).toBe("POST"); + expect(request.origin).toBe(API_ORIGIN); + expect(request.path).toBe("/v3/session/imports/importId-1/pause/"); + expect(request.query).toEqual({}); + expectAuth(request, "api_key"); + expect(request.headers.get("accept")).toBe("application/json"); + expect(request.bodyText).toBe(""); + expectMatchesExample(result, responseExample("POST /v3/session/imports/{importId}/pause/")); + }); + + it("sessions.imports.resume: POST /v3/session/imports/{importId}/resume/", async () => { + const { client, calls } = mockClient({ + status: 200, + json: responseExample("POST /v3/session/imports/{importId}/resume/"), + }); + const result = await client.sessions.imports.resume("importId-1"); + expect(calls).toHaveLength(1); + const request = calls[0]!; + expect(request.method).toBe("POST"); + expect(request.origin).toBe(API_ORIGIN); + expect(request.path).toBe("/v3/session/imports/importId-1/resume/"); + expect(request.query).toEqual({}); + expectAuth(request, "api_key"); + expect(request.headers.get("accept")).toBe("application/json"); + expect(request.bodyText).toBe(""); + expectMatchesExample(result, responseExample("POST /v3/session/imports/{importId}/resume/")); + }); + it("sessions.imports.retrieve: GET /v3/session/imports/{importId}/", async () => { const { client, calls } = mockClient({ status: 200, @@ -305,6 +435,45 @@ describe("sessions", () => { expect([...new Uint8Array(await result.arrayBuffer())]).toEqual([...BINARY]); }); + it("sessions.imports.retry: POST /v3/session/imports/{importId}/retry/", async () => { + const { client, calls } = mockClient({ + status: 201, + json: responseExample("POST /v3/session/imports/{importId}/retry/"), + }); + const result = await client.sessions.imports.retry("importId-1"); + expect(calls).toHaveLength(1); + const request = calls[0]!; + expect(request.method).toBe("POST"); + expect(request.origin).toBe(API_ORIGIN); + expect(request.path).toBe("/v3/session/imports/importId-1/retry/"); + expect(request.query).toEqual({}); + expectAuth(request, "api_key"); + expect(request.headers.get("accept")).toBe("application/json"); + expect(request.contentType).toMatch(/^multipart\/form-data; boundary=/); + expect(request.form).toEqual({}); + expect(Object.keys(request.files).sort()).toEqual([]); + expectMatchesExample(result, responseExample("POST /v3/session/imports/{importId}/retry/")); + }); + + it("sessions.imports.start: POST /v3/session/imports/{importId}/start/", async () => { + const { client, calls } = mockClient({ + status: 200, + json: responseExample("POST /v3/session/imports/{importId}/start/"), + }); + const result = await client.sessions.imports.start("importId-1"); + expect(calls).toHaveLength(1); + const request = calls[0]!; + expect(request.method).toBe("POST"); + expect(request.origin).toBe(API_ORIGIN); + expect(request.path).toBe("/v3/session/imports/importId-1/start/"); + expect(request.query).toEqual({}); + expectAuth(request, "api_key"); + expect(request.headers.get("accept")).toBe("application/json"); + expect(request.contentType).toBe("application/json"); + expect(request.json).toEqual({}); + expectMatchesExample(result, responseExample("POST /v3/session/imports/{importId}/start/")); + }); + it("sessions.list: GET /v3/sessions/", async () => { const { client, calls } = mockClient({ status: 200,