From 37ed69be587481eee8b29a7f512ee6e552a9b015 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:05:18 +0000 Subject: [PATCH] chore(spec): sync API spec 2026-10-27 Synced openapi/verification.json from the published API contract (docs/DESIGN.md section 3.1). Operations: 10 added, 0 removed, 0 renamed, 0 moved, 7 changed. Regenerated the SDK. --- lib/didit/resources.rb | 6 + lib/didit/resources/pricing.rb | 40 + lib/didit/resources/sessions.rb | 256 +++- lib/didit/types.rb | 36 + lib/didit/types/components.rb | 296 ++++- lib/didit/types/sessions.rb | 113 ++ openapi/SOURCE.json | 4 +- openapi/verification.json | 1921 +++++++++++++++++++++++++++--- sig/didit/resources.rbs | 1 + sig/didit/resources/pricing.rbs | 9 + sig/didit/resources/sessions.rbs | 11 +- sig/didit/types/components.rbs | 252 ++++ sig/didit/types/sessions.rbs | 119 +- spec/generated/pricing_spec.rb | 70 ++ spec/generated/sessions_spec.rb | 550 ++++++++- spec/generated/workflows_spec.rb | 6 +- 16 files changed, 3485 insertions(+), 205 deletions(-) create mode 100644 lib/didit/resources/pricing.rb create mode 100644 sig/didit/resources/pricing.rbs create mode 100644 spec/generated/pricing_spec.rb diff --git a/lib/didit/resources.rb b/lib/didit/resources.rb index aec727e..2dd05fe 100644 --- a/lib/didit/resources.rb +++ b/lib/didit/resources.rb @@ -33,6 +33,7 @@ module Resources autoload :Networks, "didit/resources/networks" autoload :PassiveLiveness, "didit/resources/passive_liveness" autoload :Phone, "didit/resources/phone" + autoload :Pricing, "didit/resources/pricing" autoload :ProofOfAddress, "didit/resources/proof_of_address" autoload :Questionnaires, "didit/resources/questionnaires" autoload :RegulatoryReports, "didit/resources/regulatory_reports" @@ -192,6 +193,11 @@ def phone @phone ||= Resources::Phone.new(self) end + # @return [Didit::Resources::Pricing] + def pricing + @pricing ||= Resources::Pricing.new(self) + end + # @return [Didit::Resources::ProofOfAddress] def proof_of_address @proof_of_address ||= Resources::ProofOfAddress.new(self) diff --git a/lib/didit/resources/pricing.rb b/lib/didit/resources/pricing.rb new file mode 100644 index 0000000..aab8d00 --- /dev/null +++ b/lib/didit/resources/pricing.rb @@ -0,0 +1,40 @@ +# Code generated by codegen from openapi/*.json. DO NOT EDIT. +# frozen_string_literal: true + +module Didit + module Resources + # The +pricing+ resource. + class Pricing < Didit::Resource + # 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/+ + # + # @param request_options [Hash, nil] :timeout, :max_retries, :extra_headers, :extra_query, :extra_body + # @return [Didit::Types::BankVerificationPricing] + def bank_verification(request_options: nil) + @client.request( + :get, + "/v3/organization/bank-verification-pricing/", + auth: :none, + response: Types::BankVerificationPricing, + request_options: request_options + ) + end + end + end +end diff --git a/lib/didit/resources/sessions.rb b/lib/didit/resources/sessions.rb index f8fa781..31ddb74 100644 --- a/lib/didit/resources/sessions.rb +++ b/lib/didit/resources/sessions.rb @@ -2127,13 +2127,63 @@ def update_status( # The +sessions.imports+ resource. class Imports < Didit::Resource + # 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 import_id [String] + # @param request_options [Hash, nil] :timeout, :max_retries, :extra_headers, :extra_query, :extra_body + # @return [Didit::Types::SessionImportJob] + def cancel(import_id, request_options: nil) + @client.request( + :post, + "/v3/session/imports/{importId}/cancel/", + path_params: { "importId" => import_id }, + response: Types::SessionImportJob, + request_options: request_options + ) + end + + # Check a provider key + # + # Read the provider with your key before creating a migration. Nothing is stored. + # + # +POST /v3/session/imports/providers/check/+ + # + # @param provider [String] Migration source, from `GET /v3/session/imports/providers/`. Required when `source` + # is `provider`. + # @param credentials [Hash{String => 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. + # @param options [Hash] + # @param record_ids [Array] For `api_ids` providers: the first record ID of your export. + # @param request_options [Hash, nil] :timeout, :max_retries, :extra_headers, :extra_query, :extra_body + # @return [Didit::Types::SessionsImportsCheckProviderResponse] + def check_provider(provider:, credentials:, options: OMIT, record_ids: OMIT, request_options: nil) + @client.request( + :post, + "/v3/session/imports/providers/check/", + body: { + "provider" => provider, + "credentials" => credentials, + "options" => options, + "record_ids" => record_ids + }, + response: Types::SessionsImportsCheckProviderResponse, + request_options: request_options + ) + end + # 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. + # 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/+ # @@ -2144,6 +2194,23 @@ class Imports < Didit::Resource # @param source_format [String] Optional. Inferred from the URL's file extension when omitted. # @param source_file_url [String] Alternative to file upload. Must be an HTTPS URL resolving to a public # address (private/loopback networks are rejected). Mutually exclusive with `file`. + # @param source [String] `provider` makes this a migration from another identity verification provider. Omit + # for a file import. + # @param provider [String] Migration source, from `GET /v3/session/imports/providers/`. Required when `source` + # is `provider`. + # @param credentials [Hash{String => 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. + # @param options [Hash] + # @param status_mapping [Hash{String => String}] Edits to the provider's default status mapping: source status + # to Didit status. `Not Finished` and `Abandoned` are skipped and counted, never imported. + # @param dry_run [Boolean] 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/`. + # @param face_templates [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`. + # @param lawful_basis_confirmed [Boolean] Confirms you have a lawful basis to share these selfies with Didit + # as processor. # @param file [Pathname, IO, String, Didit::FilePart] 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`. @@ -2154,6 +2221,14 @@ def create( workflow_id: OMIT, source_format: OMIT, source_file_url: OMIT, + source: OMIT, + provider: OMIT, + credentials: OMIT, + options: OMIT, + status_mapping: OMIT, + dry_run: OMIT, + face_templates: OMIT, + lawful_basis_confirmed: OMIT, file: OMIT, request_options: nil ) @@ -2165,6 +2240,14 @@ def create( "workflow_id" => workflow_id, "source_format" => source_format, "source_file_url" => source_file_url, + "source" => source, + "provider" => provider, + "credentials" => credentials, + "options" => options, + "status_mapping" => status_mapping, + "dry_run" => dry_run, + "face_templates" => face_templates, + "lawful_basis_confirmed" => lawful_basis_confirmed, "file" => file }, encoding: :auto, @@ -2174,6 +2257,23 @@ def create( ) end + # List active import jobs + # + # What is running or waiting, plus what just ended, for a progress indicator. + # + # +GET /v3/import-jobs/active/+ + # + # @param request_options [Hash, nil] :timeout, :max_retries, :extra_headers, :extra_query, :extra_body + # @return [Didit::Types::SessionsImportsListActiveJobsResponse] + def list_active_jobs(request_options: nil) + @client.request( + :get, + "/v3/import-jobs/active/", + response: Types::SessionsImportsListActiveJobsResponse, + request_options: request_options + ) + end + # List verification import row errors # # List row-level errors for a verification import job, ordered by `row_number`. Use this endpoint to produce a @@ -2200,6 +2300,85 @@ def list_errors(import_id, limit: OMIT, offset: OMIT, request_options: nil) ) end + # List import jobs + # + # Every import of the application in one shape: verification imports and migrations, people and businesses. + # + # +GET /v3/import-jobs/+ + # + # @param scope [String] + # @param limit [Integer] + # @param request_options [Hash, nil] :timeout, :max_retries, :extra_headers, :extra_query, :extra_body + # @return [Didit::Types::SessionsImportsListJobsResponse] + def list_jobs(scope: OMIT, limit: OMIT, request_options: nil) + @client.request( + :get, + "/v3/import-jobs/", + query: { + "scope" => scope, + "limit" => limit + }, + response: Types::SessionsImportsListJobsResponse, + request_options: request_options + ) + end + + # 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/+ + # + # @param request_options [Hash, nil] :timeout, :max_retries, :extra_headers, :extra_query, :extra_body + # @return [Didit::Types::SessionsImportsListProvidersResponse] + def list_providers(request_options: nil) + @client.request( + :get, + "/v3/session/imports/providers/", + response: Types::SessionsImportsListProvidersResponse, + request_options: request_options + ) + end + + # Pause an import job + # + # Pause a queued or running import. + # + # +POST /v3/session/imports/{importId}/pause/+ + # + # @param import_id [String] + # @param request_options [Hash, nil] :timeout, :max_retries, :extra_headers, :extra_query, :extra_body + # @return [Didit::Types::SessionImportJob] + def pause(import_id, request_options: nil) + @client.request( + :post, + "/v3/session/imports/{importId}/pause/", + path_params: { "importId" => import_id }, + response: Types::SessionImportJob, + request_options: request_options + ) + end + + # 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 import_id [String] + # @param request_options [Hash, nil] :timeout, :max_retries, :extra_headers, :extra_query, :extra_body + # @return [Didit::Types::SessionImportJob] + def resume(import_id, request_options: nil) + @client.request( + :post, + "/v3/session/imports/{importId}/resume/", + path_params: { "importId" => import_id }, + response: Types::SessionImportJob, + request_options: request_options + ) + end + # Retrieve a verification import job # # Retrieve import progress counters and terminal status for one job. Poll until `status` is `COMPLETED` or @@ -2242,6 +2421,75 @@ def retrieve_template(import_type: OMIT, request_options: nil, &block) request_options: request_options, &block ) end + + # 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 import_id [String] + # @param credentials [Hash{String => 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. + # @param file [Pathname, IO, String, Didit::FilePart] The record IDs or export file again, for `api_ids` and + # `export_file` providers. + # @param request_options [Hash, nil] :timeout, :max_retries, :extra_headers, :extra_query, :extra_body + # @return [Didit::Types::SessionImportJob] + def retry(import_id, credentials: OMIT, file: OMIT, request_options: nil) + @client.request( + :post, + "/v3/session/imports/{importId}/retry/", + path_params: { "importId" => import_id }, + body: { + "credentials" => credentials, + "file" => file + }, + encoding: :multipart, + file_fields: %w[file], + response: Types::SessionImportJob, + request_options: request_options + ) + end + + # 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 import_id [String] + # @param status_mapping [Hash{String => String}] Edits to the provider's default status mapping: source status + # to Didit status. `Not Finished` and `Abandoned` are skipped and counted, never imported. + # @param face_templates [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`. + # @param lawful_basis_confirmed [Boolean] Confirms you have a lawful basis to share these selfies with Didit + # as processor. + # @param request_options [Hash, nil] :timeout, :max_retries, :extra_headers, :extra_query, :extra_body + # @return [Didit::Types::SessionImportJob] + def start( + import_id, + status_mapping: OMIT, + face_templates: OMIT, + lawful_basis_confirmed: OMIT, + request_options: nil + ) + @client.request( + :post, + "/v3/session/imports/{importId}/start/", + path_params: { "importId" => import_id }, + body: { + "status_mapping" => status_mapping, + "face_templates" => face_templates, + "lawful_basis_confirmed" => lawful_basis_confirmed + }, + response: Types::SessionImportJob, + request_options: request_options + ) + end end # The +sessions.reviews+ resource. diff --git a/lib/didit/types.rb b/lib/didit/types.rb index f2454b1..64cf477 100644 --- a/lib/didit/types.rb +++ b/lib/didit/types.rb @@ -124,8 +124,16 @@ module Types autoload :ApplicationProduct, "didit/types/account_components" autoload :ApplicationProductProduct, "didit/types/account_components" autoload :ApplicationProductStatus, "didit/types/account_components" + autoload :BankAccountCheckPricing, "didit/types/components" autoload :BankAccountCheckResponse, "didit/types/components" autoload :BankAccountCheckResponseResult, "didit/types/components" + autoload :BankSignInPricing, "didit/types/components" + autoload :BankSignInPricingAddOns, "didit/types/components" + autoload :BankStatementUploadPricing, "didit/types/components" + autoload :BankVerificationPricing, "didit/types/components" + autoload :BankVerificationPricingCountry, "didit/types/components" + autoload :BankVerificationPricingCurrency, "didit/types/components" + autoload :BankVerificationPricingMethods, "didit/types/components" autoload :BankVerificationResult, "didit/types/components" autoload :BankVerificationResultAccount, "didit/types/components" autoload :BankVerificationResultAccountHolderType, "didit/types/components" @@ -134,6 +142,9 @@ module Types autoload :BankVerificationResultBillingRoute, "didit/types/components" autoload :BankVerificationResultConnection, "didit/types/components" autoload :BankVerificationResultConnectionStatus, "didit/types/components" + autoload :BankVerificationResultContinuation, "didit/types/components" + autoload :BankVerificationResultContinuationOffered, "didit/types/components" + autoload :BankVerificationResultContinuationReason, "didit/types/components" autoload :BankVerificationResultCredentialSource, "didit/types/components" autoload :BankVerificationResultFinancialData, "didit/types/components" autoload :BankVerificationResultFinancialDataNotCollected, "didit/types/components" @@ -499,6 +510,18 @@ module Types autoload :IdVerificationVerifyResponseIdVerificationWarnings, "didit/types/id_verification" autoload :IdVerificationVerifyResponseIdVerificationWarningsFeature, "didit/types/id_verification" autoload :IdVerificationVerifyResponseIdVerificationWarningsLogType, "didit/types/id_verification" + autoload :ImportJobSummary, "didit/types/components" + autoload :ImportJobSummaryFaceTemplates, "didit/types/components" + autoload :ImportJobSummaryKind, "didit/types/components" + autoload :ImportJobSummaryProgress, "didit/types/components" + autoload :ImportJobSummarySource, "didit/types/components" + autoload :ImportJobSummaryStartedBy, "didit/types/components" + autoload :ImportJobSummaryState, "didit/types/components" + autoload :ImportProvider, "didit/types/components" + autoload :ImportProviderCredentialFields, "didit/types/components" + autoload :ImportProviderKey, "didit/types/components" + autoload :ImportProviderMode, "didit/types/components" + autoload :ImportProviderStatusMappingValue, "didit/types/components" autoload :InvestigatorBatchAcceptResponse, "didit/types/components" autoload :InvestigatorBatchAcceptResponseResults, "didit/types/components" autoload :InvestigatorBatchAcceptResponseResultsReason, "didit/types/components" @@ -1103,7 +1126,9 @@ module Types autoload :SessionImportError, "didit/types/components" autoload :SessionImportJob, "didit/types/components" autoload :SessionImportJobImportType, "didit/types/components" + autoload :SessionImportJobSource, "didit/types/components" autoload :SessionImportJobSourceFormat, "didit/types/components" + autoload :SessionImportJobState, "didit/types/components" autoload :SessionImportJobStatus, "didit/types/components" autoload :SessionWebhookDelivery, "didit/types/components" autoload :SessionsAddImagesParamsModelType, "didit/types/sessions" @@ -1124,10 +1149,21 @@ module Types autoload :SessionsDeleteParamsDeletionInstruction, "didit/types/sessions" autoload :SessionsDeleteResponse, "didit/types/sessions" autoload :SessionsDeleteResponseFaceRetentionOutcome, "didit/types/sessions" + autoload :SessionsImportsCheckProviderParamsProvider, "didit/types/sessions" + autoload :SessionsImportsCheckProviderResponse, "didit/types/sessions" autoload :SessionsImportsCreateParamsImportType, "didit/types/sessions" + autoload :SessionsImportsCreateParamsProvider, "didit/types/sessions" + autoload :SessionsImportsCreateParamsSource, "didit/types/sessions" autoload :SessionsImportsCreateParamsSourceFormat, "didit/types/sessions" + autoload :SessionsImportsCreateParamsStatusMappingValue, "didit/types/sessions" + autoload :SessionsImportsListActiveJobsResponse, "didit/types/sessions" autoload :SessionsImportsListErrorsResponse, "didit/types/sessions" + autoload :SessionsImportsListJobsParamsScope, "didit/types/sessions" + autoload :SessionsImportsListJobsResponse, "didit/types/sessions" + autoload :SessionsImportsListJobsResponseCounts, "didit/types/sessions" + autoload :SessionsImportsListProvidersResponse, "didit/types/sessions" autoload :SessionsImportsRetrieveTemplateParamsImportType, "didit/types/sessions" + autoload :SessionsImportsStartParamsStatusMappingValue, "didit/types/sessions" autoload :SessionsListAmlScreeningHistoryResponse, "didit/types/sessions" autoload :SessionsListEventsResponse, "didit/types/sessions" autoload :SessionsListFeatureOverridesResponse, "didit/types/sessions" diff --git a/lib/didit/types/components.rb b/lib/didit/types/components.rb index 5c8f9e3..df97fd0 100644 --- a/lib/didit/types/components.rb +++ b/lib/didit/types/components.rb @@ -237,6 +237,13 @@ module BankAccountCheckResponseResult VALUES = [MATCH, CLOSE_MATCH, NO_MATCH, CANNOT_VERIFY].freeze end + # Currency of every price in the response. + module BankVerificationPricingCurrency + USD = "USD" + + VALUES = [USD].freeze + end + # Known values of an open enum: the API may send others. module BankVerificationResultAccountHolderType PERSON = "person" @@ -279,6 +286,30 @@ module BankVerificationResultConnectionStatus VALUES = [PENDING, CONNECTED, CANCELLED, TIMEOUT, FAILED, UNSUPPORTED, REVOKED, EXPIRED].freeze end + # Known values of an open enum: the API may send others. + module BankVerificationResultContinuationOffered + STATEMENT = "statement" + MICRODEPOSITS = "microdeposits" + + VALUES = [STATEMENT, MICRODEPOSITS].freeze + end + + # 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. + module BankVerificationResultContinuationReason + NO_ROUTE = "no_route" + INSTITUTION_UNSUPPORTED = "institution_unsupported" + ATTEMPTS_EXHAUSTED = "attempts_exhausted" + PERSON_CHOICE = "person_choice" + + VALUES = [NO_ROUTE, INSTITUTION_UNSUPPORTED, ATTEMPTS_EXHAUSTED, PERSON_CHOICE].freeze + end + # `native`: Didit's own route, billed to your Didit balance. `byok`: a marketplace provider you connected with # your own credentials. module BankVerificationResultCredentialSource @@ -299,15 +330,18 @@ module BankVerificationResultFinancialDataNotCollected # 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`. + # `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`. module BankVerificationResultMethod OPEN_BANKING = "open_banking" ACCOUNT_LOOKUP = "account_lookup" MICRODEPOSITS = "microdeposits" STATEMENT = "statement" + NONE = "none" - VALUES = [OPEN_BANKING, ACCOUNT_LOOKUP, MICRODEPOSITS, STATEMENT].freeze + VALUES = [OPEN_BANKING, ACCOUNT_LOOKUP, MICRODEPOSITS, STATEMENT, NONE].freeze end # Known values of an open enum: the API may send others. @@ -1387,6 +1421,83 @@ module IPRiskResponseStatus VALUES = [APPROVED, IN_REVIEW].freeze end + # Known values of an open enum: the API may send others. + module ImportJobSummaryKind + SESSIONS = "sessions" + BUSINESSES = "businesses" + USERS = "users" + STATUS_RULES = "status_rules" + TRANSACTIONS = "transactions" + + VALUES = [SESSIONS, BUSINESSES, USERS, STATUS_RULES, TRANSACTIONS].freeze + end + + # Known values of an open enum: the API may send others. + module ImportJobSummarySource + FILE = "file" + API = "api" + PROVIDER = "provider" + + VALUES = [FILE, API, PROVIDER].freeze + end + + # The job's state as the console shows it; `errors` is a completed job with rejected rows. + module ImportJobSummaryState + READY = "ready" + QUEUED = "queued" + RUNNING = "running" + PAUSED = "paused" + COMPLETED = "completed" + ERRORS = "errors" + FAILED = "failed" + CANCELLED = "cancelled" + + VALUES = [READY, QUEUED, RUNNING, PAUSED, COMPLETED, ERRORS, FAILED, CANCELLED].freeze + end + + # Known values of an open enum: the API may send others. + module ImportProviderKey + SUMSUB = "sumsub" + JUMIO = "jumio" + VERIFF = "veriff" + ONFIDO = "onfido" + PERSONA = "persona" + METAMAP = "metamap" + SOCURE = "socure" + IDNOW = "idnow" + SHUFTI = "shufti" + IDENFY = "idenfy" + ONDATO = "ondato" + TRULIOO = "trulioo" + AU10TIX = "au10tix" + COMPLYCUBE = "complycube" + OTHER = "other" + + VALUES = [SUMSUB, JUMIO, VERIFF, ONFIDO, PERSONA, METAMAP, SOCURE, IDNOW, SHUFTI, IDENFY, ONDATO, TRULIOO, AU10TIX, COMPLYCUBE, OTHER].freeze + end + + # `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. + module ImportProviderMode + API_LIST = "api_list" + API_IDS = "api_ids" + EXPORT_FILE = "export_file" + + VALUES = [API_LIST, API_IDS, EXPORT_FILE].freeze + end + + # Known values of an open enum: the API may send others. + module ImportProviderStatusMappingValue + APPROVED = "Approved" + DECLINED = "Declined" + IN_REVIEW = "In Review" + EXPIRED = "Expired" + NOT_FINISHED = "Not Finished" + ABANDONED = "Abandoned" + + VALUES = [APPROVED, DECLINED, IN_REVIEW, EXPIRED, NOT_FINISHED, ABANDONED].freeze + end + # Known values of an open enum: the API may send others. module InvestigatorBatchAcceptResponseResultsReason NOT_FOUND = "not_found" @@ -3514,6 +3625,15 @@ module SessionImportJobImportType VALUES = [USER_VERIFICATION, BUSINESS_VERIFICATION, STATUS_RULES, TRANSACTIONS].freeze end + # Known values of an open enum: the API may send others. + module SessionImportJobSource + FILE = "file" + API = "api" + PROVIDER = "provider" + + VALUES = [FILE, API, PROVIDER].freeze + end + # Known values of an open enum: the API may send others. module SessionImportJobSourceFormat CSV = "csv" @@ -3522,6 +3642,20 @@ module SessionImportJobSourceFormat VALUES = [CSV, NDJSON].freeze end + # The job's state as the console shows it; `errors` is a completed job with rejected rows. + module SessionImportJobState + READY = "ready" + QUEUED = "queued" + RUNNING = "running" + PAUSED = "paused" + COMPLETED = "completed" + ERRORS = "errors" + FAILED = "failed" + CANCELLED = "cancelled" + + VALUES = [READY, QUEUED, RUNNING, PAUSED, COMPLETED, ERRORS, FAILED, CANCELLED].freeze + end + # Known values of an open enum: the API may send others. module SessionImportJobStatus PENDING = "PENDING" @@ -3530,8 +3664,9 @@ module SessionImportJobStatus FAILED = "FAILED" PAUSED = "PAUSED" CANCELLED = "CANCELLED" + READY = "READY" - VALUES = [PENDING, PROCESSING, COMPLETED, FAILED, PAUSED, CANCELLED].freeze + VALUES = [PENDING, PROCESSING, COMPLETED, FAILED, PAUSED, CANCELLED, READY].freeze end # `all` places one field per match; the keys after the first get `_2`, `_3` and so on. @@ -6069,6 +6204,12 @@ class ApplicationAnalyticsWorkflowFunnelValueStepsValue < Didit::Model field :reached, "reached", :integer end + # Account check: the person types their account number and Didit checks it with the bank. Priced per country. + class BankAccountCheckPricing < Didit::Model + field :available, "available", :boolean + field :price_usd, "price_usd", :string + end + class BankAccountCheckResponse < Didit::Model field :request_id, "request_id", :string field :result, "result", :string @@ -6078,8 +6219,53 @@ class BankAccountCheckResponse < Didit::Model field :created_at, "created_at", :datetime end + # Bank sign-in: the person signs in to their bank. Priced by market, the same for every bank in it. + class BankSignInPricing < Didit::Model + field :available, "available", :boolean + field :market, "market", :string + field :price_usd, "price_usd", :string + field :add_ons, "add_ons", "BankSignInPricingAddOns" + end + + # 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. + class BankSignInPricingAddOns < Didit::Model + field :balance, "balance", :string + field :transactions, "transactions", :string + end + + # How the bank statement upload is priced. + class BankStatementUploadPricing < Didit::Model + field :price_usd, "price_usd", :string + field :included_after_charged_bank_attempt, "included_after_charged_bank_attempt", :boolean + field :standalone_available, "standalone_available", :boolean + end + + # Public Bank Verification list prices: the statement upload, the own provider key fee and each country's methods. + class BankVerificationPricing < Didit::Model + field :currency, "currency", :string + field :statement_upload, "statement_upload", "BankStatementUploadPricing" + field :own_provider_fee_usd, "own_provider_fee_usd", :string + field :countries, "countries", [:map, "BankVerificationPricingCountry"] + end + + # One country's Bank Verification methods and their list prices. + class BankVerificationPricingCountry < Didit::Model + field :name, "name", :string + field :methods_, "methods", "BankVerificationPricingMethods" + end + + # The two Bank Verification methods in a country. + class BankVerificationPricingMethods < Didit::Model + field :open_banking, "open_banking", "BankSignInPricing" + field :account_lookup, "account_lookup", "BankAccountCheckPricing" + end + # 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). + # 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). class BankVerificationResult < Didit::Model field :schema_version, "schema_version", :integer field :bank_verification_id, "bank_verification_id", :string @@ -6099,6 +6285,8 @@ class BankVerificationResult < Didit::Model field :signals, "signals", :any field :connection_abandoned, "connection_abandoned", :boolean field :not_covered, "not_covered", :boolean + field :continued_without_bank, "continued_without_bank", :boolean + field :continuation, "continuation", "BankVerificationResultContinuation" field :evidence_purged_at, "evidence_purged_at", :datetime field :warnings, "warnings", [:array, :string] field :reason_codes, "reason_codes", [:array, :string] @@ -6142,6 +6330,17 @@ class BankVerificationResultConnection < Didit::Model field :reason_code, "reason_code", :string end + # 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`. + class BankVerificationResultContinuation < Didit::Model + field :reason, "reason", :string + field :country, "country", :string + field :offered, "offered", [:array, :string] + field :institution_id, "institution_id", :string + field :institution_name, "institution_name", :string + field :continued_at, "continued_at", :datetime + end + # The financial data the step read. Only bank sign-in reads it. class BankVerificationResultFinancialData < Didit::Model field :balances, "balances", :any @@ -7298,6 +7497,70 @@ class IPRiskResponseIp < Didit::Model field :threat, "threat", :any end + # One import job of any kind, in the shape the console's Import jobs drawer reads. + class ImportJobSummary < Didit::Model + field :id, "id", :string + field :kind, "kind", :string + field :source, "source", :string + field :provider, "provider", :string + field :provider_name, "provider_name", :string + field :filename, "filename", :string + field :state, "state", :string + field :status, "status", :string + field :is_dry_run, "is_dry_run", :boolean + field :credential_hint, "credential_hint", :string + field :resumes_at, "resumes_at", :datetime + field :last_error, "last_error", :string + field :started_by, "started_by", "ImportJobSummaryStartedBy" + field :progress, "progress", "ImportJobSummaryProgress" + field :face_templates, "face_templates", "ImportJobSummaryFaceTemplates" + field :eta_seconds, "eta_seconds", :integer + field :created_at, "created_at", :datetime + field :started_at, "started_at", :datetime + field :completed_at, "completed_at", :datetime + end + + class ImportJobSummaryFaceTemplates < Didit::Model + field :enabled, "enabled", :boolean + field :built, "built", :integer + field :duplicates, "duplicates", :integer + field :blocklisted, "blocklisted", :integer + end + + class ImportJobSummaryProgress < Didit::Model + field :total, "total", :integer + field :processed, "processed", :integer + field :imported, "imported", :integer + field :updated, "updated", :integer + field :already_in_didit, "already_in_didit", :integer + field :failed, "failed", :integer + field :not_finished, "not_finished", :integer + field :same_person, "same_person", :integer + end + + class ImportJobSummaryStartedBy < Didit::Model + field :name, "name", :string + field :email, "email", :string + end + + class ImportProvider < Didit::Model + field :key, "key", :string + field :name, "name", :string + field :mode, "mode", :string + field :record_noun, "record_noun", :string + field :credential_fields, "credential_fields", [:array, "ImportProviderCredentialFields"] + field :regions, "regions", [:array, :string] + field :required_permissions, "required_permissions", [:array, :string] + field :docs_url, "docs_url", :string + field :status_mapping, "status_mapping", [:map, :string] + end + + class ImportProviderCredentialFields < Didit::Model + field :name, "name", :string + field :label, "label", :string + field :secret, "secret", :boolean + end + class InvestigatorBatchAcceptResponse < Didit::Model field :accepted, "accepted", :integer field :skipped, "skipped", :integer @@ -9941,6 +10204,25 @@ class SessionImportJob < Didit::Model field :updated_at, "updated_at", :datetime field :started_at, "started_at", :datetime field :completed_at, "completed_at", :datetime + field :state, "state", :string + field :source, "source", :string + field :provider, "provider", :string + field :provider_options, "provider_options", :any + field :credential_hint, "credential_hint", :string + field :credentials_expires_at, "credentials_expires_at", :datetime + field :resumes_at, "resumes_at", :datetime + field :status_mapping, "status_mapping", [:map, :string] + field :is_dry_run, "is_dry_run", :boolean + field :dry_run_summary, "dry_run_summary", :any + field :face_templates_enabled, "face_templates_enabled", :boolean + field :lawful_basis_confirmed_at, "lawful_basis_confirmed_at", :datetime + field :not_finished_count, "not_finished_count", :integer + field :same_person_count, "same_person_count", :integer + field :face_templates_count, "face_templates_count", :integer + field :face_duplicates_count, "face_duplicates_count", :integer + field :face_blocklist_hits_count, "face_blocklist_hits_count", :integer + field :created_by_name, "created_by_name", :string + field :created_by_email, "created_by_email", :string end # One webhook delivery attempt recorded for a verification session, with the exact request headers and body Didit @@ -11498,6 +11780,10 @@ class WorkflowDetail < Didit::Model field :kyb_role_settings, "kyb_role_settings", [:array, :any] field :created_at, "created_at", :datetime field :updated_at, "updated_at", :datetime + field :is_bank_verification_enabled, "is_bank_verification_enabled", :boolean + field :bank_verification_config, "bank_verification_config", :any + field :is_geolocation_enabled, "is_geolocation_enabled", :boolean + field :geolocation_config, "geolocation_config", :any end # One workflow version in the list view. diff --git a/lib/didit/types/sessions.rb b/lib/didit/types/sessions.rb index 728c97b..bb59f86 100644 --- a/lib/didit/types/sessions.rb +++ b/lib/didit/types/sessions.rb @@ -253,6 +253,27 @@ module SessionsDeleteResponseFaceRetentionOutcome VALUES = [RETAINED_WITH_USER, DELETED, NONE, INELIGIBLE_NO_VENDOR_USER].freeze end + # Migration source, from `GET /v3/session/imports/providers/`. Required when `source` is `provider`. + module SessionsImportsCheckProviderParamsProvider + SUMSUB = "sumsub" + JUMIO = "jumio" + VERIFF = "veriff" + ONFIDO = "onfido" + PERSONA = "persona" + METAMAP = "metamap" + SOCURE = "socure" + IDNOW = "idnow" + SHUFTI = "shufti" + IDENFY = "idenfy" + ONDATO = "ondato" + TRULIOO = "trulioo" + AU10TIX = "au10tix" + COMPLYCUBE = "complycube" + OTHER = "other" + + VALUES = [SUMSUB, JUMIO, VERIFF, ONFIDO, PERSONA, METAMAP, SOCURE, IDNOW, SHUFTI, IDENFY, ONDATO, TRULIOO, AU10TIX, COMPLYCUBE, OTHER].freeze + end + # What to import: historical User Verification sessions, historical Business Verification sessions, workflow # custom status rules, or historical transaction monitoring records. module SessionsImportsCreateParamsImportType @@ -264,6 +285,35 @@ module SessionsImportsCreateParamsImportType VALUES = [USER_VERIFICATION, BUSINESS_VERIFICATION, STATUS_RULES, TRANSACTIONS].freeze end + # Migration source, from `GET /v3/session/imports/providers/`. Required when `source` is `provider`. + module SessionsImportsCreateParamsProvider + SUMSUB = "sumsub" + JUMIO = "jumio" + VERIFF = "veriff" + ONFIDO = "onfido" + PERSONA = "persona" + METAMAP = "metamap" + SOCURE = "socure" + IDNOW = "idnow" + SHUFTI = "shufti" + IDENFY = "idenfy" + ONDATO = "ondato" + TRULIOO = "trulioo" + AU10TIX = "au10tix" + COMPLYCUBE = "complycube" + OTHER = "other" + + VALUES = [SUMSUB, JUMIO, VERIFF, ONFIDO, PERSONA, METAMAP, SOCURE, IDNOW, SHUFTI, IDENFY, ONDATO, TRULIOO, AU10TIX, COMPLYCUBE, OTHER].freeze + end + + # `provider` makes this a migration from another identity verification provider. Omit for a file import. + module SessionsImportsCreateParamsSource + FILE = "file" + PROVIDER = "provider" + + VALUES = [FILE, PROVIDER].freeze + end + # Optional. Inferred from the URL's file extension when omitted. module SessionsImportsCreateParamsSourceFormat CSV = "csv" @@ -272,6 +322,28 @@ module SessionsImportsCreateParamsSourceFormat VALUES = [CSV, NDJSON].freeze end + # Known values of an open enum: the API may send others. + module SessionsImportsCreateParamsStatusMappingValue + APPROVED = "Approved" + DECLINED = "Declined" + IN_REVIEW = "In Review" + EXPIRED = "Expired" + NOT_FINISHED = "Not Finished" + ABANDONED = "Abandoned" + + VALUES = [APPROVED, DECLINED, IN_REVIEW, EXPIRED, NOT_FINISHED, ABANDONED].freeze + end + + # Known values of an open enum: the API may send others. + module SessionsImportsListJobsParamsScope + ALL = "all" + SESSIONS = "sessions" + USERS = "users" + BUSINESSES = "businesses" + + VALUES = [ALL, SESSIONS, USERS, BUSINESSES].freeze + end + # Known values of an open enum: the API may send others. module SessionsImportsRetrieveTemplateParamsImportType USER_VERIFICATION = "user_verification" @@ -282,6 +354,18 @@ module SessionsImportsRetrieveTemplateParamsImportType VALUES = [USER_VERIFICATION, BUSINESS_VERIFICATION, STATUS_RULES, TRANSACTIONS].freeze end + # Known values of an open enum: the API may send others. + module SessionsImportsStartParamsStatusMappingValue + APPROVED = "Approved" + DECLINED = "Declined" + IN_REVIEW = "In Review" + EXPIRED = "Expired" + NOT_FINISHED = "Not Finished" + ABANDONED = "Abandoned" + + VALUES = [APPROVED, DECLINED, IN_REVIEW, EXPIRED, NOT_FINISHED, ABANDONED].freeze + end + # Known values of an open enum: the API may send others. module SessionsListParamsApiService ID_VERIFICATION = "ID_VERIFICATION" @@ -957,6 +1041,17 @@ class SessionsDeleteResponse < Didit::Model field :deleted_child_verifications, "deleted_child_verifications", :integer end + class SessionsImportsCheckProviderResponse < Didit::Model + field :ok, "ok", :boolean + field :provider, "provider", :string + field :credential_hint, "credential_hint", :string + end + + class SessionsImportsListActiveJobsResponse < Didit::Model + field :results, "results", [:array, "ImportJobSummary"] + field :running, "running", :integer + end + class SessionsImportsListErrorsResponse < Didit::Model field :count, "count", :integer field :next, "next", :string @@ -964,6 +1059,24 @@ class SessionsImportsListErrorsResponse < Didit::Model field :results, "results", [:array, "SessionImportError"] end + class SessionsImportsListJobsResponse < Didit::Model + field :results, "results", [:array, "ImportJobSummary"] + field :counts, "counts", "SessionsImportsListJobsResponseCounts" + end + + class SessionsImportsListJobsResponseCounts < Didit::Model + field :all, "all", :integer + field :running_and_waiting, "running_and_waiting", :integer + field :needs_attention, "needs_attention", :integer + field :done, "done", :integer + end + + class SessionsImportsListProvidersResponse < Didit::Model + field :providers, "providers", [:array, "ImportProvider"] + field :mapping_targets, "mapping_targets", [:array, :string] + field :skipped_statuses, "skipped_statuses", [:array, :string] + end + class SessionsListAmlScreeningHistoryResponse < Didit::Model field :count, "count", :integer field :next, "next", :string diff --git a/openapi/SOURCE.json b/openapi/SOURCE.json index 31a3405..a3693ef 100644 --- a/openapi/SOURCE.json +++ b/openapi/SOURCE.json @@ -1,8 +1,8 @@ { "verification.json": { "url": "https://docs.didit.me/openapi-25.json", - "sha256": "6157d174fff4e0093ca7ac8e0f064ffc777d1cfa4a7eeb2b0e88fbf86f4a060b", - "fetched_at": "2026-10-25T06:57:43Z" + "sha256": "b2658eb22e23f868d2df5fe513c8dcdadce3abf2e35d1bbebce0382c911038db", + "fetched_at": "2026-10-27T07:04:17Z" }, "account.json": { "url": "https://docs.didit.me/openapi-auth.json", 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/sig/didit/resources.rbs b/sig/didit/resources.rbs index d9c8212..75b495b 100644 --- a/sig/didit/resources.rbs +++ b/sig/didit/resources.rbs @@ -32,6 +32,7 @@ module Didit def networks: () -> Didit::Resources::Networks def passive_liveness: () -> Didit::Resources::PassiveLiveness def phone: () -> Didit::Resources::Phone + def pricing: () -> Didit::Resources::Pricing def proof_of_address: () -> Didit::Resources::ProofOfAddress def questionnaires: () -> Didit::Resources::Questionnaires def regulatory_reports: () -> Didit::Resources::RegulatoryReports diff --git a/sig/didit/resources/pricing.rbs b/sig/didit/resources/pricing.rbs new file mode 100644 index 0000000..7aaa3df --- /dev/null +++ b/sig/didit/resources/pricing.rbs @@ -0,0 +1,9 @@ +# Code generated by codegen from openapi/*.json. DO NOT EDIT. + +module Didit + module Resources + class Pricing < Didit::Resource + def bank_verification: (?request_options: Didit::request_options?) -> Didit::Types::BankVerificationPricing + end + end +end diff --git a/sig/didit/resources/sessions.rbs b/sig/didit/resources/sessions.rbs index 85f13f5..19da14a 100644 --- a/sig/didit/resources/sessions.rbs +++ b/sig/didit/resources/sessions.rbs @@ -40,11 +40,20 @@ module Didit def update_poa_data: (String session_id, ?issuing_state: String?, ?document_type: String, ?document_language: String?, ?issuer: String?, ?issue_date: (Date | String)?, ?poa_address: String?, ?name_on_document: String?, ?extra_fields: (Hash[String | Symbol, untyped])?, ?poa_parsed_address: Didit::Types::sessions_update_poa_data_params_poa_parsed_address?, ?node_id: String, ?request_options: Didit::request_options?) -> Didit::Types::SessionsUpdatePoaDataResponse def update_status: (String session_id, new_status: String, ?comment: String, ?nodes_to_resubmit: Array[Didit::Types::sessions_update_status_params_nodes_to_resubmit], ?send_email: bool, ?email_address: String, ?email_language: String, ?email_preview_token: String, ?request_options: Didit::request_options?) -> Didit::Types::SessionsUpdateStatusResponse class Imports < Didit::Resource - def create: (?import_type: String, ?workflow_id: String, ?source_format: String, ?source_file_url: String, ?file: Didit::upload, ?request_options: Didit::request_options?) -> Didit::Types::SessionImportJob + def cancel: (String import_id, ?request_options: Didit::request_options?) -> Didit::Types::SessionImportJob + def check_provider: (provider: String, credentials: Hash[String | Symbol, String], ?options: Didit::Types::sessions_imports_check_provider_params_options, ?record_ids: Array[String], ?request_options: Didit::request_options?) -> Didit::Types::SessionsImportsCheckProviderResponse + def create: (?import_type: String, ?workflow_id: String, ?source_format: String, ?source_file_url: String, ?source: String, ?provider: String, ?credentials: Hash[String | Symbol, String], ?options: Didit::Types::sessions_imports_create_params_options, ?status_mapping: Hash[String | Symbol, String], ?dry_run: bool, ?face_templates: bool, ?lawful_basis_confirmed: bool, ?file: Didit::upload, ?request_options: Didit::request_options?) -> Didit::Types::SessionImportJob + def list_active_jobs: (?request_options: Didit::request_options?) -> Didit::Types::SessionsImportsListActiveJobsResponse def list_errors: (String import_id, ?limit: Integer, ?offset: Integer, ?request_options: Didit::request_options?) -> Didit::Page[Didit::Types::SessionImportError] + def list_jobs: (?scope: String, ?limit: Integer, ?request_options: Didit::request_options?) -> Didit::Types::SessionsImportsListJobsResponse + def list_providers: (?request_options: Didit::request_options?) -> Didit::Types::SessionsImportsListProvidersResponse + def pause: (String import_id, ?request_options: Didit::request_options?) -> Didit::Types::SessionImportJob + def resume: (String import_id, ?request_options: Didit::request_options?) -> Didit::Types::SessionImportJob def retrieve: (String import_id, ?request_options: Didit::request_options?) -> Didit::Types::SessionImportJob def retrieve_template: (?import_type: String, ?request_options: Didit::request_options?) -> String | (?import_type: String, ?request_options: Didit::request_options?) { (String chunk) -> void } -> nil + def `retry`: (String import_id, ?credentials: Hash[String | Symbol, String], ?file: Didit::upload, ?request_options: Didit::request_options?) -> Didit::Types::SessionImportJob + def start: (String import_id, ?status_mapping: Hash[String | Symbol, String], ?face_templates: bool, ?lawful_basis_confirmed: bool, ?request_options: Didit::request_options?) -> Didit::Types::SessionImportJob end class Reviews < Didit::Resource def create: (String session_id, ?new_status: String?, ?comment: String?, ?request_options: Didit::request_options?) -> Didit::Types::SessionsReviewsCreateResponse diff --git a/sig/didit/types/components.rbs b/sig/didit/types/components.rbs index e07c311..ea7a0f0 100644 --- a/sig/didit/types/components.rbs +++ b/sig/didit/types/components.rbs @@ -211,6 +211,12 @@ module Didit VALUES: Array[String] end + module BankVerificationPricingCurrency + USD: String + + VALUES: Array[String] + end + module BankVerificationResultAccountHolderType PERSON: String BUSINESS: String @@ -249,6 +255,22 @@ module Didit VALUES: Array[String] end + module BankVerificationResultContinuationOffered + STATEMENT: String + MICRODEPOSITS: String + + VALUES: Array[String] + end + + module BankVerificationResultContinuationReason + NO_ROUTE: String + INSTITUTION_UNSUPPORTED: String + ATTEMPTS_EXHAUSTED: String + PERSON_CHOICE: String + + VALUES: Array[String] + end + module BankVerificationResultCredentialSource NATIVE: String BYOK: String @@ -269,6 +291,7 @@ module Didit ACCOUNT_LOOKUP: String MICRODEPOSITS: String STATEMENT: String + NONE: String VALUES: Array[String] end @@ -1123,6 +1146,76 @@ module Didit VALUES: Array[String] end + module ImportJobSummaryKind + SESSIONS: String + BUSINESSES: String + USERS: String + STATUS_RULES: String + TRANSACTIONS: String + + VALUES: Array[String] + end + + module ImportJobSummarySource + FILE: String + API: String + PROVIDER: String + + VALUES: Array[String] + end + + module ImportJobSummaryState + READY: String + QUEUED: String + RUNNING: String + PAUSED: String + COMPLETED: String + ERRORS: String + FAILED: String + CANCELLED: String + + VALUES: Array[String] + end + + module ImportProviderKey + SUMSUB: String + JUMIO: String + VERIFF: String + ONFIDO: String + PERSONA: String + METAMAP: String + SOCURE: String + IDNOW: String + SHUFTI: String + IDENFY: String + ONDATO: String + TRULIOO: String + AU10TIX: String + COMPLYCUBE: String + OTHER: String + + VALUES: Array[String] + end + + module ImportProviderMode + API_LIST: String + API_IDS: String + EXPORT_FILE: String + + VALUES: Array[String] + end + + module ImportProviderStatusMappingValue + APPROVED: String + DECLINED: String + IN_REVIEW: String + EXPIRED: String + NOT_FINISHED: String + ABANDONED: String + + VALUES: Array[String] + end + module InvestigatorBatchAcceptResponseResultsReason NOT_FOUND: String FORBIDDEN: String @@ -2922,6 +3015,14 @@ module Didit VALUES: Array[String] end + module SessionImportJobSource + FILE: String + API: String + PROVIDER: String + + VALUES: Array[String] + end + module SessionImportJobSourceFormat CSV: String NDJSON: String @@ -2929,6 +3030,19 @@ module Didit VALUES: Array[String] end + module SessionImportJobState + READY: String + QUEUED: String + RUNNING: String + PAUSED: String + COMPLETED: String + ERRORS: String + FAILED: String + CANCELLED: String + + VALUES: Array[String] + end + module SessionImportJobStatus PENDING: String PROCESSING: String @@ -2936,6 +3050,7 @@ module Didit FAILED: String PAUSED: String CANCELLED: String + READY: String VALUES: Array[String] end @@ -5160,6 +5275,11 @@ module Didit def reached: () -> Integer? end + class BankAccountCheckPricing < Didit::Model + def available: () -> bool + def price_usd: () -> String? + end + class BankAccountCheckResponse < Didit::Model def request_id: () -> String def result: () -> String @@ -5169,6 +5289,41 @@ module Didit def created_at: () -> Time end + class BankSignInPricing < Didit::Model + def available: () -> bool + def market: () -> String? + def price_usd: () -> String? + def add_ons: () -> Didit::Types::BankSignInPricingAddOns + end + + class BankSignInPricingAddOns < Didit::Model + def balance: () -> String? + def transactions: () -> String? + end + + class BankStatementUploadPricing < Didit::Model + def price_usd: () -> String + def included_after_charged_bank_attempt: () -> bool + def standalone_available: () -> bool + end + + class BankVerificationPricing < Didit::Model + def currency: () -> String + def statement_upload: () -> Didit::Types::BankStatementUploadPricing + def own_provider_fee_usd: () -> String + def countries: () -> Hash[String, Didit::Types::BankVerificationPricingCountry] + end + + class BankVerificationPricingCountry < Didit::Model + def name: () -> String + def methods_: () -> Didit::Types::BankVerificationPricingMethods + end + + class BankVerificationPricingMethods < Didit::Model + def open_banking: () -> Didit::Types::BankSignInPricing + def account_lookup: () -> Didit::Types::BankAccountCheckPricing + end + class BankVerificationResult < Didit::Model def schema_version: () -> Integer? def bank_verification_id: () -> String? @@ -5188,6 +5343,8 @@ module Didit def signals: () -> Hash[String, untyped]? def connection_abandoned: () -> bool? def not_covered: () -> bool? + def continued_without_bank: () -> bool? + def continuation: () -> Didit::Types::BankVerificationResultContinuation? def evidence_purged_at: () -> Time? def warnings: () -> Array[String]? def reason_codes: () -> Array[String]? @@ -5229,6 +5386,15 @@ module Didit def reason_code: () -> String? end + class BankVerificationResultContinuation < Didit::Model + def reason: () -> String? + def country: () -> String? + def offered: () -> Array[String]? + def institution_id: () -> String? + def institution_name: () -> String? + def continued_at: () -> Time? + end + class BankVerificationResultFinancialData < Didit::Model def balances: () -> Hash[String, untyped]? def transactions: () -> Hash[String, untyped]? @@ -6343,6 +6509,69 @@ module Didit def threat: () -> Hash[String, untyped] end + class ImportJobSummary < Didit::Model + def id: () -> String? + def kind: () -> String? + def source: () -> String? + def provider: () -> String? + def provider_name: () -> String? + def filename: () -> String? + def state: () -> String? + def status: () -> String? + def is_dry_run: () -> bool? + def credential_hint: () -> String? + def resumes_at: () -> Time? + def last_error: () -> String? + def started_by: () -> Didit::Types::ImportJobSummaryStartedBy? + def progress: () -> Didit::Types::ImportJobSummaryProgress? + def face_templates: () -> Didit::Types::ImportJobSummaryFaceTemplates? + def eta_seconds: () -> Integer? + def created_at: () -> Time? + def started_at: () -> Time? + def completed_at: () -> Time? + end + + class ImportJobSummaryFaceTemplates < Didit::Model + def enabled: () -> bool? + def built: () -> Integer? + def duplicates: () -> Integer? + def blocklisted: () -> Integer? + end + + class ImportJobSummaryProgress < Didit::Model + def total: () -> Integer? + def processed: () -> Integer? + def imported: () -> Integer? + def updated: () -> Integer? + def already_in_didit: () -> Integer? + def failed: () -> Integer? + def not_finished: () -> Integer? + def same_person: () -> Integer? + end + + class ImportJobSummaryStartedBy < Didit::Model + def name: () -> String? + def email: () -> String? + end + + class ImportProvider < Didit::Model + def key: () -> String? + def name: () -> String? + def mode: () -> String? + def record_noun: () -> String? + def credential_fields: () -> Array[Didit::Types::ImportProviderCredentialFields]? + def regions: () -> Array[String]? + def required_permissions: () -> Array[String]? + def docs_url: () -> String? + def status_mapping: () -> Hash[String, String]? + end + + class ImportProviderCredentialFields < Didit::Model + def name: () -> String? + def label: () -> String? + def secret: () -> bool? + end + class InvestigatorBatchAcceptResponse < Didit::Model def accepted: () -> Integer? def skipped: () -> Integer? @@ -8808,6 +9037,25 @@ module Didit def updated_at: () -> Time? def started_at: () -> Time? def completed_at: () -> Time? + def state: () -> String? + def source: () -> String? + def provider: () -> String? + def provider_options: () -> Hash[String, untyped]? + def credential_hint: () -> String? + def credentials_expires_at: () -> Time? + def resumes_at: () -> Time? + def status_mapping: () -> Hash[String, String]? + def is_dry_run: () -> bool? + def dry_run_summary: () -> Hash[String, untyped]? + def face_templates_enabled: () -> bool? + def lawful_basis_confirmed_at: () -> Time? + def not_finished_count: () -> Integer? + def same_person_count: () -> Integer? + def face_templates_count: () -> Integer? + def face_duplicates_count: () -> Integer? + def face_blocklist_hits_count: () -> Integer? + def created_by_name: () -> String? + def created_by_email: () -> String? end class SessionWebhookDelivery < Didit::Model @@ -10209,6 +10457,10 @@ module Didit def kyb_role_settings: () -> Array[Hash[String, untyped]]? def created_at: () -> Time? def updated_at: () -> Time? + def is_bank_verification_enabled: () -> bool? + def bank_verification_config: () -> Hash[String, untyped]? + def is_geolocation_enabled: () -> bool? + def geolocation_config: () -> Hash[String, untyped]? end class WorkflowListItem < Didit::Model diff --git a/sig/didit/types/sessions.rbs b/sig/didit/types/sessions.rbs index 992e8ea..41161b2 100644 --- a/sig/didit/types/sessions.rbs +++ b/sig/didit/types/sessions.rbs @@ -211,6 +211,26 @@ module Didit VALUES: Array[String] end + module SessionsImportsCheckProviderParamsProvider + SUMSUB: String + JUMIO: String + VERIFF: String + ONFIDO: String + PERSONA: String + METAMAP: String + SOCURE: String + IDNOW: String + SHUFTI: String + IDENFY: String + ONDATO: String + TRULIOO: String + AU10TIX: String + COMPLYCUBE: String + OTHER: String + + VALUES: Array[String] + end + module SessionsImportsCreateParamsImportType USER_VERIFICATION: String BUSINESS_VERIFICATION: String @@ -220,6 +240,33 @@ module Didit VALUES: Array[String] end + module SessionsImportsCreateParamsProvider + SUMSUB: String + JUMIO: String + VERIFF: String + ONFIDO: String + PERSONA: String + METAMAP: String + SOCURE: String + IDNOW: String + SHUFTI: String + IDENFY: String + ONDATO: String + TRULIOO: String + AU10TIX: String + COMPLYCUBE: String + OTHER: String + + VALUES: Array[String] + end + + module SessionsImportsCreateParamsSource + FILE: String + PROVIDER: String + + VALUES: Array[String] + end + module SessionsImportsCreateParamsSourceFormat CSV: String NDJSON: String @@ -227,6 +274,26 @@ module Didit VALUES: Array[String] end + module SessionsImportsCreateParamsStatusMappingValue + APPROVED: String + DECLINED: String + IN_REVIEW: String + EXPIRED: String + NOT_FINISHED: String + ABANDONED: String + + VALUES: Array[String] + end + + module SessionsImportsListJobsParamsScope + ALL: String + SESSIONS: String + USERS: String + BUSINESSES: String + + VALUES: Array[String] + end + module SessionsImportsRetrieveTemplateParamsImportType USER_VERIFICATION: String BUSINESS_VERIFICATION: String @@ -236,6 +303,17 @@ module Didit VALUES: Array[String] end + module SessionsImportsStartParamsStatusMappingValue + APPROVED: String + DECLINED: String + IN_REVIEW: String + EXPIRED: String + NOT_FINISHED: String + ABANDONED: String + + VALUES: Array[String] + end + module SessionsListParamsApiService ID_VERIFICATION: String FACE_MATCH: String @@ -822,6 +900,17 @@ module Didit def deleted_child_verifications: () -> Integer? end + class SessionsImportsCheckProviderResponse < Didit::Model + def ok: () -> bool? + def provider: () -> String? + def credential_hint: () -> String? + end + + class SessionsImportsListActiveJobsResponse < Didit::Model + def results: () -> Array[Didit::Types::ImportJobSummary]? + def running: () -> Integer? + end + class SessionsImportsListErrorsResponse < Didit::Model def count: () -> Integer? def `next`: () -> String? @@ -829,6 +918,24 @@ module Didit def results: () -> Array[Didit::Types::SessionImportError]? end + class SessionsImportsListJobsResponse < Didit::Model + def results: () -> Array[Didit::Types::ImportJobSummary]? + def counts: () -> Didit::Types::SessionsImportsListJobsResponseCounts? + end + + class SessionsImportsListJobsResponseCounts < Didit::Model + def all: () -> Integer? + def running_and_waiting: () -> Integer? + def needs_attention: () -> Integer? + def done: () -> Integer? + end + + class SessionsImportsListProvidersResponse < Didit::Model + def providers: () -> Array[Didit::Types::ImportProvider]? + def mapping_targets: () -> Array[String]? + def skipped_statuses: () -> Array[String]? + end + class SessionsListAmlScreeningHistoryResponse < Didit::Model def count: () -> Integer def `next`: () -> String? @@ -1186,7 +1293,17 @@ module Didit type sessions_import_shared_params = { share_token: String, trust_review: bool, workflow_id: String, ?vendor_data: String? } - type sessions_imports_create_params = { ?import_type: String, ?workflow_id: String, ?source_format: String, ?source_file_url: String, ?file: Didit::upload } + type sessions_imports_check_provider_params = { provider: String, credentials: Hash[String | Symbol, String], ?options: Didit::Types::sessions_imports_check_provider_params_options, ?record_ids: Array[String] } + + type sessions_imports_check_provider_params_options = { ?region: String } + + type sessions_imports_create_params = { ?import_type: String, ?workflow_id: String, ?source_format: String, ?source_file_url: String, ?source: String, ?provider: String, ?credentials: Hash[String | Symbol, String], ?options: Didit::Types::sessions_imports_create_params_options, ?status_mapping: Hash[String | Symbol, String], ?dry_run: bool, ?face_templates: bool, ?lawful_basis_confirmed: bool, ?file: Didit::upload } + + type sessions_imports_create_params_options = { ?region: String } + + type sessions_imports_retry_params = { ?credentials: Hash[String | Symbol, String], ?file: Didit::upload } + + type sessions_imports_start_params = { ?status_mapping: Hash[String | Symbol, String], ?face_templates: bool, ?lawful_basis_confirmed: bool } type sessions_preview_decision_email_params = { new_status: String, ?email_language: String } diff --git a/spec/generated/pricing_spec.rb b/spec/generated/pricing_spec.rb new file mode 100644 index 0000000..76a7d2e --- /dev/null +++ b/spec/generated/pricing_spec.rb @@ -0,0 +1,70 @@ +# Code generated by codegen from openapi/*.json. DO NOT EDIT. +# frozen_string_literal: true + +RSpec.describe Didit::Resources::Pricing do + include ApiHelpers + + let(:client) { generated_test_client } + + it "pricing.bank_verification sends GET /v3/organization/bank-verification-pricing/" do + calls = stub_api(status: 200, body: <<~'JSON') + { + "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 + } + } + } + } + } + JSON + result = client.pricing.bank_verification + request = expect_api_request( + calls, + method: :get, + url: "https://verification.didit.me/v3/organization/bank-verification-pricing/", + query: [], + auth: :none, + accept: "application/json" + ) + expect_no_body(request) + expect(result).to be_a(Didit::Types::BankVerificationPricing) + expect(result.to_h).to eq(JSON.parse(calls.body, symbolize_names: true)) + exercise_readers(result) + end +end diff --git a/spec/generated/sessions_spec.rb b/spec/generated/sessions_spec.rb index 009b7e7..1cd37c9 100644 --- a/spec/generated/sessions_spec.rb +++ b/spec/generated/sessions_spec.rb @@ -3465,6 +3465,100 @@ exercise_readers(result) end + it "sessions.imports.cancel sends POST /v3/session/imports/{importId}/cancel/" do + calls = stub_api(status: 200, body: <<~'JSON') + { + "uuid": "3f1c2a9e-5b7d-4e2f-9a1b-6c8d0e4f2a7b", + "status": "PENDING", + "import_type": "user_verification", + "source_format": "csv", + "source_filename": "source_filename-value", + "total_rows": 1, + "processed_rows": 1, + "checkpoint_row": 1, + "created_count": 1, + "updated_count": 1, + "skipped_count": 1, + "failed_count": 1, + "total_media_bytes": 1, + "last_error": "last_error-value", + "created_at": "2026-01-02T03:04:05Z", + "updated_at": "2026-01-02T03:04:05Z", + "started_at": "2026-01-02T03:04:05Z", + "completed_at": "2026-01-02T03:04:05Z", + "state": "ready", + "source": "file", + "provider": "provider-value", + "provider_options": {}, + "credential_hint": "credential_hint-value", + "credentials_expires_at": "2026-01-02T03:04:05Z", + "resumes_at": "2026-01-02T03:04:05Z", + "status_mapping": { + "key": "value" + }, + "is_dry_run": true, + "dry_run_summary": {}, + "face_templates_enabled": true, + "lawful_basis_confirmed_at": "2026-01-02T03:04:05Z", + "not_finished_count": 1, + "same_person_count": 1, + "face_templates_count": 1, + "face_duplicates_count": 1, + "face_blocklist_hits_count": 1, + "created_by_name": "created_by_name-value", + "created_by_email": "created_by_email-value" + } + JSON + result = client.sessions.imports.cancel( + "3f1c2a9e-5b7d-4e2f-9a1b-6c8d0e4f2a7b" + ) + request = expect_api_request( + calls, + method: :post, + url: "https://verification.didit.me/v3/session/imports/3f1c2a9e-5b7d-4e2f-9a1b-6c8d0e4f2a7b/cancel/", + query: [], + auth: :api_key, + accept: "application/json" + ) + expect_no_body(request) + expect(result).to be_a(Didit::Types::SessionImportJob) + expect(result.to_h).to eq(JSON.parse(calls.body, symbolize_names: true)) + exercise_readers(result) + end + + it "sessions.imports.check_provider sends POST /v3/session/imports/providers/check/" do + calls = stub_api(status: 200, body: <<~'JSON') + { + "ok": true, + "provider": "provider-value", + "credential_hint": "credential_hint-value" + } + JSON + result = client.sessions.imports.check_provider( + provider: "sumsub", + credentials: { + key: "value" + } + ) + request = expect_api_request( + calls, + method: :post, + url: "https://verification.didit.me/v3/session/imports/providers/check/", + query: [], + auth: :api_key, + accept: "application/json" + ) + expect_json_body(request, { + "provider" => "sumsub", + "credentials" => { + "key" => "value" + } + }) + expect(result).to be_a(Didit::Types::SessionsImportsCheckProviderResponse) + expect(result.to_h).to eq(JSON.parse(calls.body, symbolize_names: true)) + exercise_readers(result) + end + it "sessions.imports.create sends POST /v3/session/imports/" do calls = stub_api(status: 201, body: <<~'JSON') { @@ -3522,6 +3616,67 @@ exercise_readers(result) end + it "sessions.imports.list_active_jobs sends GET /v3/import-jobs/active/" do + calls = stub_api(status: 200, body: <<~'JSON') + { + "results": [ + { + "id": "3f1c2a9e-5b7d-4e2f-9a1b-6c8d0e4f2a7b", + "kind": "sessions", + "source": "file", + "provider": "provider-value", + "provider_name": "provider_name-value", + "filename": "filename-value", + "state": "ready", + "status": "status-value", + "is_dry_run": true, + "credential_hint": "credential_hint-value", + "resumes_at": "2026-01-02T03:04:05Z", + "last_error": "last_error-value", + "started_by": { + "name": "name-value", + "email": "email-value" + }, + "progress": { + "total": 1, + "processed": 1, + "imported": 1, + "updated": 1, + "already_in_didit": 1, + "failed": 1, + "not_finished": 1, + "same_person": 1 + }, + "face_templates": { + "enabled": true, + "built": 1, + "duplicates": 1, + "blocklisted": 1 + }, + "eta_seconds": 1, + "created_at": "2026-01-02T03:04:05Z", + "started_at": "2026-01-02T03:04:05Z", + "completed_at": "2026-01-02T03:04:05Z" + } + ], + "running": 1 + } + JSON + result = client.sessions.imports.list_active_jobs + request = expect_api_request( + calls, + method: :get, + url: "https://verification.didit.me/v3/import-jobs/active/", + query: [], + auth: :api_key, + accept: "application/json" + ) + expect_no_body(request) + expect(result).to be_a(Didit::Types::SessionsImportsListActiveJobsResponse) + expect(result.to_h).to eq(JSON.parse(calls.body, symbolize_names: true)) + exercise_readers(result) + end + it "sessions.imports.list_errors sends GET /v3/session/imports/{importId}/errors/" do calls = stub_api(status: 200, body: <<~'JSON') { @@ -3562,6 +3717,245 @@ exercise_readers(result.results) end + it "sessions.imports.list_jobs sends GET /v3/import-jobs/" do + calls = stub_api(status: 200, body: <<~'JSON') + { + "results": [ + { + "id": "3f1c2a9e-5b7d-4e2f-9a1b-6c8d0e4f2a7b", + "kind": "sessions", + "source": "file", + "provider": "provider-value", + "provider_name": "provider_name-value", + "filename": "filename-value", + "state": "ready", + "status": "status-value", + "is_dry_run": true, + "credential_hint": "credential_hint-value", + "resumes_at": "2026-01-02T03:04:05Z", + "last_error": "last_error-value", + "started_by": { + "name": "name-value", + "email": "email-value" + }, + "progress": { + "total": 1, + "processed": 1, + "imported": 1, + "updated": 1, + "already_in_didit": 1, + "failed": 1, + "not_finished": 1, + "same_person": 1 + }, + "face_templates": { + "enabled": true, + "built": 1, + "duplicates": 1, + "blocklisted": 1 + }, + "eta_seconds": 1, + "created_at": "2026-01-02T03:04:05Z", + "started_at": "2026-01-02T03:04:05Z", + "completed_at": "2026-01-02T03:04:05Z" + } + ], + "counts": { + "all": 1, + "running_and_waiting": 1, + "needs_attention": 1, + "done": 1 + } + } + JSON + result = client.sessions.imports.list_jobs + request = expect_api_request( + calls, + method: :get, + url: "https://verification.didit.me/v3/import-jobs/", + query: [], + auth: :api_key, + accept: "application/json" + ) + expect_no_body(request) + expect(result).to be_a(Didit::Types::SessionsImportsListJobsResponse) + expect(result.to_h).to eq(JSON.parse(calls.body, symbolize_names: true)) + exercise_readers(result) + end + + it "sessions.imports.list_providers sends GET /v3/session/imports/providers/" do + calls = stub_api(status: 200, body: <<~'JSON') + { + "providers": [ + { + "key": "sumsub", + "name": "name-value", + "mode": "api_list", + "record_noun": "record_noun-value", + "credential_fields": [ + { + "name": "example", + "label": "example", + "secret": "example" + } + ], + "regions": [ + "regions-value" + ], + "required_permissions": [ + "required_permissions-value" + ], + "docs_url": "docs_url-value", + "status_mapping": { + "key": "Approved" + } + } + ], + "mapping_targets": [ + "mapping_targets-value" + ], + "skipped_statuses": [ + "skipped_statuses-value" + ] + } + JSON + result = client.sessions.imports.list_providers + request = expect_api_request( + calls, + method: :get, + url: "https://verification.didit.me/v3/session/imports/providers/", + query: [], + auth: :api_key, + accept: "application/json" + ) + expect_no_body(request) + expect(result).to be_a(Didit::Types::SessionsImportsListProvidersResponse) + expect(result.to_h).to eq(JSON.parse(calls.body, symbolize_names: true)) + exercise_readers(result) + end + + it "sessions.imports.pause sends POST /v3/session/imports/{importId}/pause/" do + calls = stub_api(status: 200, body: <<~'JSON') + { + "uuid": "3f1c2a9e-5b7d-4e2f-9a1b-6c8d0e4f2a7b", + "status": "PENDING", + "import_type": "user_verification", + "source_format": "csv", + "source_filename": "source_filename-value", + "total_rows": 1, + "processed_rows": 1, + "checkpoint_row": 1, + "created_count": 1, + "updated_count": 1, + "skipped_count": 1, + "failed_count": 1, + "total_media_bytes": 1, + "last_error": "last_error-value", + "created_at": "2026-01-02T03:04:05Z", + "updated_at": "2026-01-02T03:04:05Z", + "started_at": "2026-01-02T03:04:05Z", + "completed_at": "2026-01-02T03:04:05Z", + "state": "ready", + "source": "file", + "provider": "provider-value", + "provider_options": {}, + "credential_hint": "credential_hint-value", + "credentials_expires_at": "2026-01-02T03:04:05Z", + "resumes_at": "2026-01-02T03:04:05Z", + "status_mapping": { + "key": "value" + }, + "is_dry_run": true, + "dry_run_summary": {}, + "face_templates_enabled": true, + "lawful_basis_confirmed_at": "2026-01-02T03:04:05Z", + "not_finished_count": 1, + "same_person_count": 1, + "face_templates_count": 1, + "face_duplicates_count": 1, + "face_blocklist_hits_count": 1, + "created_by_name": "created_by_name-value", + "created_by_email": "created_by_email-value" + } + JSON + result = client.sessions.imports.pause( + "3f1c2a9e-5b7d-4e2f-9a1b-6c8d0e4f2a7b" + ) + request = expect_api_request( + calls, + method: :post, + url: "https://verification.didit.me/v3/session/imports/3f1c2a9e-5b7d-4e2f-9a1b-6c8d0e4f2a7b/pause/", + query: [], + auth: :api_key, + accept: "application/json" + ) + expect_no_body(request) + expect(result).to be_a(Didit::Types::SessionImportJob) + expect(result.to_h).to eq(JSON.parse(calls.body, symbolize_names: true)) + exercise_readers(result) + end + + it "sessions.imports.resume sends POST /v3/session/imports/{importId}/resume/" do + calls = stub_api(status: 200, body: <<~'JSON') + { + "uuid": "3f1c2a9e-5b7d-4e2f-9a1b-6c8d0e4f2a7b", + "status": "PENDING", + "import_type": "user_verification", + "source_format": "csv", + "source_filename": "source_filename-value", + "total_rows": 1, + "processed_rows": 1, + "checkpoint_row": 1, + "created_count": 1, + "updated_count": 1, + "skipped_count": 1, + "failed_count": 1, + "total_media_bytes": 1, + "last_error": "last_error-value", + "created_at": "2026-01-02T03:04:05Z", + "updated_at": "2026-01-02T03:04:05Z", + "started_at": "2026-01-02T03:04:05Z", + "completed_at": "2026-01-02T03:04:05Z", + "state": "ready", + "source": "file", + "provider": "provider-value", + "provider_options": {}, + "credential_hint": "credential_hint-value", + "credentials_expires_at": "2026-01-02T03:04:05Z", + "resumes_at": "2026-01-02T03:04:05Z", + "status_mapping": { + "key": "value" + }, + "is_dry_run": true, + "dry_run_summary": {}, + "face_templates_enabled": true, + "lawful_basis_confirmed_at": "2026-01-02T03:04:05Z", + "not_finished_count": 1, + "same_person_count": 1, + "face_templates_count": 1, + "face_duplicates_count": 1, + "face_blocklist_hits_count": 1, + "created_by_name": "created_by_name-value", + "created_by_email": "created_by_email-value" + } + JSON + result = client.sessions.imports.resume( + "3f1c2a9e-5b7d-4e2f-9a1b-6c8d0e4f2a7b" + ) + request = expect_api_request( + calls, + method: :post, + url: "https://verification.didit.me/v3/session/imports/3f1c2a9e-5b7d-4e2f-9a1b-6c8d0e4f2a7b/resume/", + query: [], + auth: :api_key, + accept: "application/json" + ) + expect_no_body(request) + expect(result).to be_a(Didit::Types::SessionImportJob) + expect(result.to_h).to eq(JSON.parse(calls.body, symbolize_names: true)) + exercise_readers(result) + end + it "sessions.imports.retrieve sends GET /v3/session/imports/{importId}/" do calls = stub_api(status: 200, body: <<~'JSON') { @@ -3582,7 +3976,28 @@ "created_at": "2026-01-02T03:04:05Z", "updated_at": "2026-01-02T03:04:05Z", "started_at": "2026-01-02T03:04:05Z", - "completed_at": "2026-01-02T03:04:05Z" + "completed_at": "2026-01-02T03:04:05Z", + "state": "ready", + "source": "file", + "provider": "provider-value", + "provider_options": {}, + "credential_hint": "credential_hint-value", + "credentials_expires_at": "2026-01-02T03:04:05Z", + "resumes_at": "2026-01-02T03:04:05Z", + "status_mapping": { + "key": "value" + }, + "is_dry_run": true, + "dry_run_summary": {}, + "face_templates_enabled": true, + "lawful_basis_confirmed_at": "2026-01-02T03:04:05Z", + "not_finished_count": 1, + "same_person_count": 1, + "face_templates_count": 1, + "face_duplicates_count": 1, + "face_blocklist_hits_count": 1, + "created_by_name": "created_by_name-value", + "created_by_email": "created_by_email-value" } JSON result = client.sessions.imports.retrieve( @@ -3617,6 +4032,139 @@ expect(result).to eq("fake-binary-body") end + it "sessions.imports.retry sends POST /v3/session/imports/{importId}/retry/" do + calls = stub_api(status: 201, body: <<~'JSON') + { + "uuid": "3f1c2a9e-5b7d-4e2f-9a1b-6c8d0e4f2a7b", + "status": "PENDING", + "import_type": "user_verification", + "source_format": "csv", + "source_filename": "source_filename-value", + "total_rows": 1, + "processed_rows": 1, + "checkpoint_row": 1, + "created_count": 1, + "updated_count": 1, + "skipped_count": 1, + "failed_count": 1, + "total_media_bytes": 1, + "last_error": "last_error-value", + "created_at": "2026-01-02T03:04:05Z", + "updated_at": "2026-01-02T03:04:05Z", + "started_at": "2026-01-02T03:04:05Z", + "completed_at": "2026-01-02T03:04:05Z", + "state": "ready", + "source": "file", + "provider": "provider-value", + "provider_options": {}, + "credential_hint": "credential_hint-value", + "credentials_expires_at": "2026-01-02T03:04:05Z", + "resumes_at": "2026-01-02T03:04:05Z", + "status_mapping": { + "key": "value" + }, + "is_dry_run": true, + "dry_run_summary": {}, + "face_templates_enabled": true, + "lawful_basis_confirmed_at": "2026-01-02T03:04:05Z", + "not_finished_count": 1, + "same_person_count": 1, + "face_templates_count": 1, + "face_duplicates_count": 1, + "face_blocklist_hits_count": 1, + "created_by_name": "created_by_name-value", + "created_by_email": "created_by_email-value" + } + JSON + result = client.sessions.imports.retry( + "3f1c2a9e-5b7d-4e2f-9a1b-6c8d0e4f2a7b", + file: Didit::FilePart.new("fake-file-bytes", filename: "file.jpg", content_type: "image/jpeg") + ) + request = expect_api_request( + calls, + method: :post, + url: "https://verification.didit.me/v3/session/imports/3f1c2a9e-5b7d-4e2f-9a1b-6c8d0e4f2a7b/retry/", + query: [], + auth: :api_key, + accept: "application/json" + ) + expect_multipart_body( + request, + fields: {}, + files: { + "file" => [ + "file.jpg", + "image/jpeg", + "fake-file-bytes" + ] + } + ) + expect(result).to be_a(Didit::Types::SessionImportJob) + expect(result.to_h).to eq(JSON.parse(calls.body, symbolize_names: true)) + exercise_readers(result) + end + + it "sessions.imports.start sends POST /v3/session/imports/{importId}/start/" do + calls = stub_api(status: 200, body: <<~'JSON') + { + "uuid": "3f1c2a9e-5b7d-4e2f-9a1b-6c8d0e4f2a7b", + "status": "PENDING", + "import_type": "user_verification", + "source_format": "csv", + "source_filename": "source_filename-value", + "total_rows": 1, + "processed_rows": 1, + "checkpoint_row": 1, + "created_count": 1, + "updated_count": 1, + "skipped_count": 1, + "failed_count": 1, + "total_media_bytes": 1, + "last_error": "last_error-value", + "created_at": "2026-01-02T03:04:05Z", + "updated_at": "2026-01-02T03:04:05Z", + "started_at": "2026-01-02T03:04:05Z", + "completed_at": "2026-01-02T03:04:05Z", + "state": "ready", + "source": "file", + "provider": "provider-value", + "provider_options": {}, + "credential_hint": "credential_hint-value", + "credentials_expires_at": "2026-01-02T03:04:05Z", + "resumes_at": "2026-01-02T03:04:05Z", + "status_mapping": { + "key": "value" + }, + "is_dry_run": true, + "dry_run_summary": {}, + "face_templates_enabled": true, + "lawful_basis_confirmed_at": "2026-01-02T03:04:05Z", + "not_finished_count": 1, + "same_person_count": 1, + "face_templates_count": 1, + "face_duplicates_count": 1, + "face_blocklist_hits_count": 1, + "created_by_name": "created_by_name-value", + "created_by_email": "created_by_email-value" + } + JSON + result = client.sessions.imports.start( + "3f1c2a9e-5b7d-4e2f-9a1b-6c8d0e4f2a7b" + ) + request = expect_api_request( + calls, + method: :post, + url: "https://verification.didit.me/v3/session/imports/3f1c2a9e-5b7d-4e2f-9a1b-6c8d0e4f2a7b/start/", + query: [], + auth: :api_key, + accept: "application/json" + ) + expect_json_body(request, {}) + expect(result).to be_a(Didit::Types::SessionImportJob) + expect(result.to_h).to eq(JSON.parse(calls.body, symbolize_names: true)) + exercise_readers(result) + end + it "sessions.reviews.create sends POST /v3/sessions/{session_id}/reviews/" do calls = stub_api(status: 201, body: <<~'JSON') { diff --git a/spec/generated/workflows_spec.rb b/spec/generated/workflows_spec.rb index 109ee78..6ecf272 100644 --- a/spec/generated/workflows_spec.rb +++ b/spec/generated/workflows_spec.rb @@ -292,7 +292,11 @@ {} ], "created_at": "2026-01-02T03:04:05Z", - "updated_at": "2026-01-02T03:04:05Z" + "updated_at": "2026-01-02T03:04:05Z", + "is_bank_verification_enabled": true, + "bank_verification_config": {}, + "is_geolocation_enabled": true, + "geolocation_config": {} } JSON result = client.workflows.update(