From a6d74ef4d530986d3b823513d884f52cfd670685 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 23 Oct 2026 22:29:34 +0000 Subject: [PATCH 1/2] chore(spec): sync API spec 2026-10-23 --- openapi/SOURCE.json | 4 +- openapi/verification.json | 973 +++++++ .../java/me/didit/resources/BankResource.java | 151 + .../me/didit/resources/DiditResources.java | 11 + .../types/BankAccountCheckBusinessHolder.java | 100 + .../me/didit/types/BankAccountCheckError.java | 216 ++ .../didit/types/BankAccountCheckHolder.java | 90 + .../types/BankAccountCheckPersonHolder.java | 100 + .../didit/types/BankAccountCheckRequest.java | 471 +++ .../didit/types/BankAccountCheckResponse.java | 257 ++ .../didit/types/BankVerificationResult.java | 2591 +++++++++++++++++ .../java/me/didit/types/SessionDecision.java | 22 +- .../me/didit/resources/BankResourceTest.java | 44 + 13 files changed, 5027 insertions(+), 3 deletions(-) create mode 100644 src/main/java/me/didit/resources/BankResource.java create mode 100644 src/main/java/me/didit/types/BankAccountCheckBusinessHolder.java create mode 100644 src/main/java/me/didit/types/BankAccountCheckError.java create mode 100644 src/main/java/me/didit/types/BankAccountCheckHolder.java create mode 100644 src/main/java/me/didit/types/BankAccountCheckPersonHolder.java create mode 100644 src/main/java/me/didit/types/BankAccountCheckRequest.java create mode 100644 src/main/java/me/didit/types/BankAccountCheckResponse.java create mode 100644 src/main/java/me/didit/types/BankVerificationResult.java create mode 100644 src/test/java/me/didit/resources/BankResourceTest.java diff --git a/openapi/SOURCE.json b/openapi/SOURCE.json index 47946a1..689d545 100644 --- a/openapi/SOURCE.json +++ b/openapi/SOURCE.json @@ -1,8 +1,8 @@ { "verification.json": { "url": "https://docs.didit.me/openapi-25.json", - "sha256": "9ada6192b24a5d85e983e57e87fccb6e762d74060b6f0b892928356dd432137c", - "fetched_at": "2026-10-23T06:48:14Z" + "sha256": "da776b2226bd264797268988b179f37b906c0b2e4953a16111c0d4296c89fcd4", + "fetched_at": "2026-10-23T22:27:22Z" }, "account.json": { "url": "https://docs.didit.me/openapi-auth.json", diff --git a/openapi/verification.json b/openapi/verification.json index 73528cc..a3d5eea 100644 --- a/openapi/verification.json +++ b/openapi/verification.json @@ -15542,6 +15542,285 @@ ] } }, + "/v3/bank/account-check/": { + "post": { + "summary": "Check a bank account", + "description": "Check that a bank account belongs to the person or company you name, before you send money to it. No session and no sign-in: send the name and the account, read the result. It is the [account check](/core-technology/bank-verification/account-check) of the Bank Verification step, run from your backend.\n\n**What you send.** The account's `country` (ISO 3166-1 alpha-3), the `account` the way that country writes it, and the `holder` name: `full_name` for a person or `business_name` for a company. A business name checks a business account.\n\n**What you get back.** `result` is `match`, `close_match`, `no_match` or `cannot_verify`. On a `close_match`, `holder_name` is the name the bank holds the account under, when the bank returned it. `account` comes back masked to its last 4 characters.\n\n**Billing.** Each check the bank answers is billed once at the Account check price of the account's country, whatever the result: a `no_match`, an account that does not exist and a `cannot_verify` are billed too. A request answered with an error is never billed.\n\n**Every request is a new check.** There is no idempotency key and no endpoint to read a check back, so a retried request runs, and is billed, again. Store the response.\n\n**Sandbox.** A sandbox key calls no bank and is charged nothing. The last 4 characters of the IBAN, else of the account number, choose the answer: `0001` a `close_match` with a `holder_name`, `0002` a `close_match` without one, `0003` and `0006` a `no_match`, `0004` `cannot_verify`, `0005` a `503` and `0009` a `400`. Any other ending is a `match`.\n\n**API keys.** A scoped API key needs write access to sessions.", + "operationId": "post_v3_bank_account_check", + "tags": [ + "Standalone APIs" + ], + "x-didit-sdk": { + "resource": "bank", + "method": "account_check", + "auth": "api_key", + "server": true + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BearerAuth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BankAccountCheckRequest" + }, + "examples": { + "Person, United Kingdom": { + "summary": "A sort code and account number, checked against a person's name", + "value": { + "country": "GBR", + "account": { + "sort_code": "20-45-67", + "account_number": "31926819" + }, + "holder": { + "full_name": "Maria Oliveira" + }, + "vendor_data": "payout_20481" + } + }, + "Company, IBAN": { + "summary": "An IBAN, checked against a company's name", + "value": { + "country": "DEU", + "account": { + "iban": "DE89 3704 0044 0532 0130 00" + }, + "holder": { + "business_name": "Northwind Trading GmbH" + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "The bank answered. The check is billed, whatever the result.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BankAccountCheckResponse" + }, + "examples": { + "Close match": { + "summary": "The bank holds the account under a close name", + "value": { + "request_id": "c2f4a9e0-7b1d-4c3a-9e55-1d0a6b8f2a47", + "result": "close_match", + "holder_name": "MARIA R OLIVEIRA", + "account": "****6819", + "vendor_data": "payout_20481", + "created_at": "2026-10-21T14:32:08Z" + } + }, + "Match": { + "summary": "The bank holds the account under the name sent", + "value": { + "request_id": "5b0e2d7c-41a8-4f6e-9c3b-8e7d1a2f6c90", + "result": "match", + "holder_name": null, + "account": "****3000", + "vendor_data": null, + "created_at": "2026-10-21T14:35:41Z" + } + } + } + } + } + }, + "400": { + "description": "Refused as sent, and not billed. `field` names the body field to correct and `reason` says why, with the same reasons the hosted account form shows. Only the first refused field is reported.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BankAccountCheckError" + }, + "examples": { + "Missing field": { + "summary": "The country's check needs a sort code", + "value": { + "detail": "The sort code is not valid (required).", + "code": "invalid_account_input", + "field": "account.sort_code", + "reason": "required" + } + }, + "Invalid IBAN": { + "summary": "The IBAN has the wrong length for its country", + "value": { + "detail": "The iban is not valid (length).", + "code": "invalid_account_input", + "field": "account.iban", + "reason": "length" + } + }, + "Refused by the bank": { + "summary": "The bank refused the account as sent", + "value": { + "detail": "The account was refused as typed (rejected).", + "code": "invalid_account_input", + "field": "account.account_number", + "reason": "rejected" + } + }, + "No name": { + "summary": "`holder` has neither `full_name` nor `business_name`", + "value": { + "detail": "Send full_name for a person or business_name for a company.", + "code": "invalid_account_input", + "field": "holder", + "reason": "required" + } + } + } + } + } + }, + "401": { + "description": "The scoped API key has expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BankAccountCheckError" + }, + "examples": { + "Expired key": { + "summary": "The key's expiry date has passed", + "value": { + "detail": "This API key has expired." + } + } + } + } + } + }, + "402": { + "description": "The check cannot be paid for, so it did not run. Top up your balance, then send it again.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BankAccountCheckError" + }, + "examples": { + "Out of credit": { + "summary": "Your balance cannot cover one check", + "value": { + "detail": "You don't have enough credits to perform this request. Please top up at https://business.didit.me", + "code": "insufficient_credits" + } + }, + "Not in your contract": { + "summary": "Your contract has no price for the Account check API", + "value": { + "detail": "Your contract does not price the Account check API. Contact your account manager.", + "code": "contract_rate_missing" + } + } + } + } + } + }, + "403": { + "description": "The `x-api-key` header or the bearer token is missing or invalid, the request came from an address outside the key's IP list, or a scoped key has no write access to sessions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BankAccountCheckError" + }, + "examples": { + "Missing or invalid credentials": { + "summary": "No valid API key or token", + "value": { + "detail": "You do not have permission to perform this action." + } + }, + "No sessions write": { + "summary": "A scoped key without write access to sessions", + "value": { + "detail": "This API key has no write access to sessions." + } + } + } + } + } + }, + "404": { + "description": "No account check serves this account yet, so nothing was checked or billed. `country_not_covered`: none serves its country, or its kind of account (person or business) there. `bank_not_covered`: none serves its bank. `bank_verification_not_available`: Bank Verification is not available yet.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BankAccountCheckError" + }, + "examples": { + "Country not covered": { + "summary": "No account check serves the country", + "value": { + "detail": "No account check serves this country yet.", + "code": "country_not_covered" + } + }, + "Bank not covered": { + "summary": "No account check serves the account's bank", + "value": { + "detail": "No account check serves this account's bank yet.", + "code": "bank_not_covered" + } + } + } + } + } + }, + "429": { + "$ref": "#/components/responses/RateLimitedWrite" + }, + "503": { + "description": "The bank could not answer. Nothing was checked or billed; send the check again later.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BankAccountCheckError" + }, + "examples": { + "Unavailable": { + "summary": "The bank did not answer", + "value": { + "detail": "The account check is temporarily unavailable and this request was not charged. Please try again.", + "code": "account_check_unavailable" + } + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "curl", + "label": "curl", + "source": "curl -X POST https://verification.didit.me/v3/bank/account-check/ \\\n -H 'x-api-key: YOUR_API_KEY' \\\n -H 'Content-Type: application/json' \\\n -d '{\n \"country\": \"GBR\",\n \"account\": {\"sort_code\": \"20-45-67\", \"account_number\": \"31926819\"},\n \"holder\": {\"full_name\": \"Maria Oliveira\"},\n \"vendor_data\": \"payout_20481\"\n }'" + }, + { + "lang": "python", + "label": "Python", + "source": "import os, requests\n\nresp = requests.post(\n \"https://verification.didit.me/v3/bank/account-check/\",\n headers={\"x-api-key\": os.environ[\"DIDIT_API_KEY\"]},\n json={\n \"country\": \"GBR\",\n \"account\": {\"sort_code\": \"20-45-67\", \"account_number\": \"31926819\"},\n \"holder\": {\"full_name\": \"Maria Oliveira\"},\n \"vendor_data\": \"payout_20481\",\n },\n timeout=30,\n)\nresp.raise_for_status()\ncheck = resp.json()\nif check[\"result\"] == \"match\":\n pass # send the payout\nelif check[\"result\"] == \"close_match\":\n print(check[\"holder_name\"]) # the name the bank holds, when it returned one" + }, + { + "lang": "javascript", + "label": "JavaScript", + "source": "const res = await fetch('https://verification.didit.me/v3/bank/account-check/', {\n method: 'POST',\n headers: {\n 'x-api-key': process.env.DIDIT_API_KEY,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n country: 'GBR',\n account: { sort_code: '20-45-67', account_number: '31926819' },\n holder: { full_name: 'Maria Oliveira' },\n vendor_data: 'payout_20481',\n }),\n});\nconst check = await res.json();\n// check.result: match, close_match, no_match or cannot_verify" + } + ] + } + }, "/v3/email/send/": { "post": { "summary": "Send Email Code", @@ -92013,6 +92292,14 @@ } } }, + "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).", + "items": { + "$ref": "#/components/schemas/BankVerificationResult" + } + }, "signatures": { "type": "array", "description": "Electronic Signature results, one item per signer and signature step, for User and Business Verification. Present only when the workflow has an Electronic Signature step; an empty array until a signer reaches it. See the [Electronic Signature report](/core-technology/electronic-signature/report-electronic-signature).", @@ -103652,6 +103939,692 @@ "format": "date-time" } } + }, + "BankAccountCheckHolder": { + "description": "The name the account is checked against. Send exactly one of `full_name` and `business_name`.", + "oneOf": [ + { + "$ref": "#/components/schemas/BankAccountCheckPersonHolder" + }, + { + "$ref": "#/components/schemas/BankAccountCheckBusinessHolder" + } + ] + }, + "BankAccountCheckRequest": { + "type": "object", + "required": [ + "country", + "account", + "holder" + ], + "properties": { + "country": { + "type": "string", + "minLength": 3, + "maxLength": 3, + "description": "The account's country, as an ISO 3166-1 alpha-3 code, for example `GBR`. Lowercase is accepted.", + "example": "GBR" + }, + "account": { + "type": "object", + "description": "The account the way its country writes it: an `iban`, or an `account_number` with the bank or branch code the country needs (`sort_code`, `routing_number`, `transit_institution`, `bsb`, `ifsc`, `bank_code` or `bic`). Mexico takes a `clabe` and Argentina a `cbu_cvu`, which already name the bank. A business account adds a `registration_id` where the country asks for one. Spaces, dashes and dots are ignored. Keys the country's check does not use are ignored; a key it needs and does not get is a `400` that names it.", + "properties": { + "iban": { + "type": "string", + "maxLength": 64, + "description": "The IBAN, in a country that uses IBANs. It must belong to `country`." + }, + "account_number": { + "type": "string", + "maxLength": 64, + "description": "The account number, in a country that writes the account with a separate bank or branch code." + }, + "sort_code": { + "type": "string", + "maxLength": 64, + "description": "United Kingdom: the 6-digit sort code." + }, + "routing_number": { + "type": "string", + "maxLength": 64, + "description": "United States: the 9-digit ABA routing number." + }, + "transit_institution": { + "type": "string", + "maxLength": 64, + "description": "Canada: the 8-digit transit and institution number." + }, + "bsb": { + "type": "string", + "maxLength": 64, + "description": "Australia: the 6-digit BSB." + }, + "ifsc": { + "type": "string", + "maxLength": 64, + "description": "India: the 11-character IFSC." + }, + "bank_code": { + "type": "string", + "maxLength": 64, + "description": "The bank's code, where the country needs one, for example in Nigeria." + }, + "bic": { + "type": "string", + "maxLength": 64, + "description": "The bank's BIC, where the country's check asks for one." + }, + "clabe": { + "type": "string", + "maxLength": 64, + "description": "Mexico: the 18-digit CLABE. It already names the bank." + }, + "cbu_cvu": { + "type": "string", + "maxLength": 64, + "description": "Argentina: the 22-digit CBU or CVU. It already names the bank." + }, + "registration_id": { + "type": "string", + "maxLength": 64, + "description": "A business account's registration number, where the country asks for one." + } + }, + "additionalProperties": { + "type": "string", + "maxLength": 64 + }, + "example": { + "sort_code": "20-45-67", + "account_number": "31926819" + } + }, + "holder": { + "$ref": "#/components/schemas/BankAccountCheckHolder" + }, + "vendor_data": { + "type": "string", + "nullable": true, + "description": "Your own reference for this check, returned unchanged.", + "example": "payout_20481" + } + } + }, + "BankAccountCheckResponse": { + "type": "object", + "required": [ + "request_id", + "result", + "holder_name", + "account", + "vendor_data", + "created_at" + ], + "properties": { + "request_id": { + "type": "string", + "format": "uuid", + "description": "The ID of this check." + }, + "result": { + "type": "string", + "enum": [ + "match", + "close_match", + "no_match", + "cannot_verify" + ], + "description": "`match`: the bank holds the account under the name you sent. `close_match`: under a close name, for example a missing middle name or a typo. `no_match`: under another name, or there is no such account. `cannot_verify`: the bank answered without comparing the name, for example for a blocked or closed account." + }, + "holder_name": { + "type": "string", + "nullable": true, + "description": "Only on a `close_match`, and only when the bank returned it: the name on the account, as the bank holds it. `null` otherwise." + }, + "account": { + "type": "string", + "description": "The account, masked to its last 4 characters." + }, + "vendor_data": { + "type": "string", + "nullable": true, + "description": "Your own reference, as you sent it." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "When the check ran, in UTC." + } + } + }, + "BankAccountCheckError": { + "type": "object", + "required": [ + "detail" + ], + "properties": { + "detail": { + "type": "string", + "description": "What went wrong, in English." + }, + "code": { + "type": "string", + "description": "A stable code to branch on. Absent on `401` and `403`." + }, + "field": { + "type": "string", + "description": "`400` only: the body field to correct, as a dotted path, for example `account.sort_code`." + }, + "reason": { + "type": "string", + "enum": [ + "required", + "length", + "format", + "checksum", + "country_mismatch", + "rejected" + ], + "description": "`400` only: why the field was refused. `required`, `length`, `format`, `checksum` and `country_mismatch` (an IBAN of another country) are Didit's own checks; `rejected` means the bank refused the account as sent." + } + } + }, + "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).", + "properties": { + "schema_version": { + "type": "integer", + "description": "Version of this result shape. `1` today." + }, + "bank_verification_id": { + "type": "string", + "format": "uuid", + "description": "The ID of this result." + }, + "node_id": { + "type": "string", + "description": "The workflow node this result belongs to." + }, + "status": { + "type": "string", + "enum": [ + "Not Finished", + "Approved", + "Declined", + "In Review", + "Expired" + ], + "description": "The step's verdict, after its actions and status rules." + }, + "original_status": { + "type": "string", + "nullable": true, + "description": "The first verdict the step reached, before any later change such as a manual review." + }, + "method": { + "type": "string", + "nullable": true, + "enum": [ + "open_banking", + "account_lookup", + "microdeposits", + "statement" + ], + "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`." + }, + "provider": { + "type": "string", + "nullable": true, + "description": "The key of the route that ran the connection. Read `method`, not this key, to tell how the account was verified." + }, + "credential_source": { + "type": "string", + "nullable": true, + "enum": [ + "native", + "byok" + ], + "description": "`native`: Didit's own route, billed to your Didit balance. `byok`: a marketplace provider you connected with your own credentials." + }, + "route": { + "type": "object", + "nullable": true, + "description": "The route chosen before consent. It never changes afterwards.", + "properties": { + "provider_key": { + "type": "string", + "nullable": true, + "description": "The route's key." + }, + "credential_source": { + "type": "string", + "enum": [ + "native", + "byok" + ] + }, + "is_fallback": { + "type": "boolean", + "description": "Whether Didit's own route stood in for a marketplace provider that could not connect." + }, + "provider_connection_id": { + "type": "string", + "nullable": true, + "description": "The marketplace connection used, for `byok`." + }, + "requested_scopes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The data the connection asked for, for example `ownership` or `balances`." + } + } + }, + "connection": { + "type": "object", + "nullable": true, + "description": "The latest attempt's connection. `null` before the first attempt.", + "properties": { + "status": { + "type": "string", + "enum": [ + "pending", + "connected", + "cancelled", + "timeout", + "failed", + "unsupported", + "revoked", + "expired" + ] + }, + "institution_id": { + "type": "string", + "nullable": true, + "description": "The bank's ID. `null` for an account check, where no bank is picked." + }, + "institution_name": { + "type": "string", + "nullable": true, + "description": "The bank's name. `null` for an account check." + }, + "institution_country": { + "type": "string", + "nullable": true, + "description": "The account's country, ISO 3166-1 alpha-3." + }, + "oauth": { + "type": "boolean", + "nullable": true, + "description": "Whether the bank sign-in ran over OAuth or app-to-app. `null` for an account check." + }, + "connected_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the connection succeeded." + }, + "consent_expires_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the bank consent ends, for bank sign-in." + }, + "last_refreshed_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the financial data was last read again." + }, + "attempts": { + "type": "integer", + "description": "The attempts the person spent on this step, every method together." + }, + "reason_code": { + "type": "string", + "nullable": true, + "description": "Why the connection is not simply `connected`, for example `USER_CANCELLED`, `INSTITUTION_DOWN`, `ACCOUNT_NOT_FOUND`, `REFERENCE_IDENTITY_MISSING` or `VERIFICATION_COMPLETED`." + } + } + }, + "account": { + "type": "object", + "nullable": true, + "description": "The evaluated account. `null` until an account is evaluated.", + "properties": { + "account_id_masked": { + "type": "string", + "nullable": true, + "description": "The account number, masked." + }, + "iban_masked": { + "type": "string", + "nullable": true, + "description": "The IBAN, masked." + }, + "sort_code": { + "type": "string", + "nullable": true, + "description": "The sort code, in the United Kingdom." + }, + "routing_number_masked": { + "type": "string", + "nullable": true, + "description": "The routing number, masked." + }, + "type": { + "type": "string", + "nullable": true, + "enum": [ + "checking", + "current", + "savings", + "business", + "other" + ] + }, + "subtype": { + "type": "string", + "nullable": true, + "description": "The bank's own account subtype." + }, + "currency": { + "type": "string", + "nullable": true, + "description": "ISO 4217 currency of the account." + }, + "holder_type": { + "type": "string", + "nullable": true, + "enum": [ + "person", + "business", + "unknown" + ] + }, + "holders_count": { + "type": "integer", + "nullable": true + }, + "is_joint": { + "type": "boolean", + "nullable": true + }, + "is_business": { + "type": "boolean", + "nullable": true + } + } + }, + "ownership": { + "type": "object", + "nullable": true, + "description": "How the account holder compared with the verified identity. `null` until an account is evaluated.", + "properties": { + "result": { + "type": "string", + "enum": [ + "match", + "partial_match", + "no_match", + "unknown", + "not_verifiable" + ], + "description": "`partial_match` is a close match. `not_verifiable`: the bank answered with no holder to compare. `unknown`: the evidence could not be read, or there was no identity to compare." + }, + "reference_identity_source": { + "type": "string", + "nullable": true, + "description": "The step whose identity the holder was compared against: `kyc`, `database_validation`, `expected_details`, `questionnaire`, `document_ai` or `kyb`." + }, + "name_score": { + "type": "integer", + "minimum": 0, + "maximum": 100, + "nullable": true, + "description": "Didit's holder name score." + }, + "provider_name_score": { + "type": "integer", + "minimum": 0, + "maximum": 100, + "nullable": true, + "description": "The bank's own holder name score, when it returned one." + }, + "address_score": { + "type": "integer", + "minimum": 0, + "maximum": 100, + "nullable": true, + "description": "The holder address score, when address matching ran." + }, + "email_score": { + "type": "integer", + "minimum": 0, + "maximum": 100, + "nullable": true, + "description": "The holder email score, when email matching ran." + }, + "phone_score": { + "type": "integer", + "minimum": 0, + "maximum": 100, + "nullable": true, + "description": "The holder phone score, when phone matching ran." + }, + "dob_score": { + "type": "integer", + "minimum": 0, + "maximum": 100, + "nullable": true, + "description": "The holder date of birth score, when the bank shared one." + }, + "close_match": { + "type": "boolean", + "nullable": true, + "description": "Whether the name landed in the close-match band." + }, + "holder_confirmation": { + "type": "string", + "nullable": true, + "enum": [ + "pending", + "confirmed", + "rejected" + ], + "description": "The person's answer when asked to confirm a close-match name. `null` when never asked." + }, + "method": { + "type": "string", + "nullable": true, + "enum": [ + "exact", + "token_set", + "nickname", + "transliteration", + "fuzzy", + "provider_only", + "microdeposits" + ], + "description": "Which name comparison produced the score. This is not the verification method: read the top-level `method` for that." + }, + "matched_holder_index": { + "type": "integer", + "nullable": true + }, + "holders": { + "type": "array", + "items": { + "type": "object" + }, + "description": "Each holder the bank listed, with its scores." + }, + "owner_identity_available": { + "type": "boolean", + "nullable": true + }, + "evidence_freshness": { + "type": "string", + "nullable": true, + "enum": [ + "live", + "cached", + "refreshed" + ] + }, + "evaluated_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the verdict was computed." + } + } + }, + "financial_data": { + "type": "object", + "description": "The financial data the step read. Only bank sign-in reads it.", + "properties": { + "balances": { + "type": "object", + "nullable": true, + "description": "With the `balances` scope." + }, + "transactions": { + "type": "object", + "nullable": true, + "description": "With the `transactions` scope." + }, + "income": { + "type": "object", + "nullable": true, + "description": "With the `income` scope." + }, + "categorization": { + "type": "object", + "nullable": true, + "description": "Didit's categorization of the transactions read. `null` without them." + }, + "not_collected": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "balances", + "income", + "transactions" + ] + }, + "description": "The data the step asked for that the method which verified the account does not collect. Balances, transactions and income come from bank sign-in only, so an account verified by account check lists them here. Never a failure. Empty otherwise." + } + } + }, + "billing": { + "type": "object", + "nullable": true, + "properties": { + "route": { + "type": "string", + "enum": [ + "native", + "byok" + ] + }, + "billed": { + "type": "boolean" + }, + "marketplace_fee": { + "type": "string", + "nullable": true, + "description": "The marketplace platform fee charged, for `byok`." + }, + "usage_type": { + "type": "string", + "nullable": true, + "description": "The usage line the charge was booked on." + } + } + }, + "reference_identity": { + "type": "object", + "nullable": true, + "description": "The identity the holder was compared against, with its source." + }, + "signals": { + "type": "object", + "nullable": true, + "description": "Account signals read from the transaction history, when the step read one." + }, + "connection_abandoned": { + "type": "boolean", + "nullable": true, + "description": "Whether the step ended without a match after the person left at their bank." + }, + "not_covered": { + "type": "boolean", + "nullable": true, + "description": "Whether the person's bank or country could not be reached on this step." + }, + "evidence_purged_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the bank evidence was deleted under `bank_evidence_retention_days`. `null` otherwise." + }, + "warnings": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Informational codes, for example `holder_declared`. A warning never changes the status on its own." + }, + "reason_codes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Why the verdict came out the way it did, for example `OWNER_NAME_PARTIAL`. Several may apply." + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + } + }, + "BankAccountCheckPersonHolder": { + "type": "object", + "description": "The person who should hold the account.", + "required": [ + "full_name" + ], + "properties": { + "full_name": { + "type": "string", + "maxLength": 255, + "description": "The full name of the person who should hold the account.", + "example": "Maria Oliveira" + } + } + }, + "BankAccountCheckBusinessHolder": { + "type": "object", + "description": "The company that should hold the account. Checks a business account.", + "required": [ + "business_name" + ], + "properties": { + "business_name": { + "type": "string", + "maxLength": 255, + "description": "The name of the company that should hold the account. Checks a business account." + } + } } }, "securitySchemes": { diff --git a/src/main/java/me/didit/resources/BankResource.java b/src/main/java/me/didit/resources/BankResource.java new file mode 100644 index 0000000..bfc66fd --- /dev/null +++ b/src/main/java/me/didit/resources/BankResource.java @@ -0,0 +1,151 @@ +// Code generated by codegen from openapi/*.json. DO NOT EDIT. +package me.didit.resources; + +import java.util.concurrent.CompletableFuture; +import me.didit.core.ApiClient; +import me.didit.core.ApiRequest; +import me.didit.core.Conv; +import me.didit.core.RawResponse; +import me.didit.core.RequestOptions; +import me.didit.core.ResponseHandler; +import me.didit.core.Responses; +import me.didit.types.BankAccountCheckRequest; +import me.didit.types.BankAccountCheckResponse; + +/** The {@code bank} resource: {@code client.bank()}. */ +public final class BankResource { + private final ApiClient client; + private final WithRawResponse withRawResponse; + + BankResource(ApiClient client) { + this.client = client; + this.withRawResponse = new WithRawResponse(client); + } + + /** + * The same operations, returning the HTTP status, headers and request id with the parsed body. + * + * @return the raw response view + */ + public WithRawResponse withRawResponse() { + return withRawResponse; + } + + /** + * Check a bank account + * + *

Check that a bank account belongs to the person or company you name, before you send money to it. No session and no sign-in: send the name and the account, read the result. It is the [account check](/core-technology/bank-verification/account-check) of the Bank Verification step, run from your backend. + * + *

What you send. The account's country (ISO 3166-1 alpha-3), the account the way that country writes it, and the holder name: full_name for a person or business_name for a company. A business name checks a business account. + * + *

What you get back. result is match, close_match, no_match or cannot_verify. On a close_match, holder_name is the name the bank holds the account under, when the bank returned it. account comes back masked to its last 4 characters. + * + *

Billing. Each check the bank answers is billed once at the Account check price of the account's country, whatever the result: a no_match, an account that does not exist and a cannot_verify are billed too. A request answered with an error is never billed. + * + *

Every request is a new check. There is no idempotency key and no endpoint to read a check back, so a retried request runs, and is billed, again. Store the response. + * + *

Sandbox. A sandbox key calls no bank and is charged nothing. The last 4 characters of the IBAN, else of the account number, choose the answer: 0001 a close_match with a holder_name, 0002 a close_match without one, 0003 and 0006 a no_match, 0004 cannot_verify, 0005 a 503 and 0009 a 400. Any other ending is a match. + * + *

API keys. A scoped API key needs write access to sessions. + * + *

{@code POST /v3/bank/account-check/} + * + * @param params the request parameters + * @param options per-request options that override the client options + * @return the response body + */ + public BankAccountCheckResponse accountCheck(BankAccountCheckRequest params, RequestOptions options) { + return client.execute(accountCheckRequest(params), options, ACCOUNT_CHECK_RESPONSE).data(); + } + + /** + * Asynchronous {@link #accountCheck(BankAccountCheckRequest, RequestOptions)}. + * + * @param params the request parameters + * @param options per-request options + * @return a future completed with the result + */ + public CompletableFuture accountCheckAsync(BankAccountCheckRequest params, RequestOptions options) { + return client.executeAsync(accountCheckRequest(params), options, ACCOUNT_CHECK_RESPONSE).thenApply(RawResponse::data); + } + + /** + * Same as {@link #accountCheck(BankAccountCheckRequest, RequestOptions)}, with the client's options. + * + * @param params the request parameters + * @return the result + */ + public BankAccountCheckResponse accountCheck(BankAccountCheckRequest params) { + return client.execute(accountCheckRequest(params), RequestOptions.none(), ACCOUNT_CHECK_RESPONSE).data(); + } + + /** + * Asynchronous {@link #accountCheck(BankAccountCheckRequest, RequestOptions)}, with the client's options. + * + * @param params the request parameters + * @return a future completed with the result + */ + public CompletableFuture accountCheckAsync(BankAccountCheckRequest params) { + return client.executeAsync(accountCheckRequest(params), RequestOptions.none(), ACCOUNT_CHECK_RESPONSE).thenApply(RawResponse::data); + } + + private static final ResponseHandler ACCOUNT_CHECK_RESPONSE = Responses.json(Conv.model(BankAccountCheckResponse::fromJson)); + + private static ApiRequest accountCheckRequest(BankAccountCheckRequest params) { + return ApiRequest.builder("POST", "/v3/bank/account-check/") + .params(params) + .body(ApiRequest.BodyEncoding.JSON) + .build(); + } + + /** The {@code bank} operations returning {@link RawResponse}. */ + public static final class WithRawResponse { + private final ApiClient client; + + WithRawResponse(ApiClient client) { + this.client = client; + } + + /** + * {@link #accountCheck(BankAccountCheckRequest, RequestOptions)} with the raw response. + * + * @param params the request parameters + * @param options per-request options + * @return the result + */ + public RawResponse accountCheck(BankAccountCheckRequest params, RequestOptions options) { + return client.execute(accountCheckRequest(params), options, ACCOUNT_CHECK_RESPONSE); + } + + /** + * Asynchronous {@link #accountCheck(BankAccountCheckRequest, RequestOptions)} with the raw response. + * + * @param params the request parameters + * @param options per-request options + * @return a future completed with the result + */ + public CompletableFuture> accountCheckAsync(BankAccountCheckRequest params, RequestOptions options) { + return client.executeAsync(accountCheckRequest(params), options, ACCOUNT_CHECK_RESPONSE); + } + + /** + * {@link #accountCheck(BankAccountCheckRequest, RequestOptions)} with the raw response, with the client's options. + * + * @param params the request parameters + * @return the result + */ + public RawResponse accountCheck(BankAccountCheckRequest params) { + return client.execute(accountCheckRequest(params), RequestOptions.none(), ACCOUNT_CHECK_RESPONSE); + } + + /** + * Asynchronous {@link #accountCheck(BankAccountCheckRequest, RequestOptions)} with the raw response, with the client's options. + * + * @param params the request parameters + * @return a future completed with the result + */ + public CompletableFuture> accountCheckAsync(BankAccountCheckRequest params) { + return client.executeAsync(accountCheckRequest(params), RequestOptions.none(), ACCOUNT_CHECK_RESPONSE); + } + } +} diff --git a/src/main/java/me/didit/resources/DiditResources.java b/src/main/java/me/didit/resources/DiditResources.java index 55827c8..39e4607 100644 --- a/src/main/java/me/didit/resources/DiditResources.java +++ b/src/main/java/me/didit/resources/DiditResources.java @@ -13,6 +13,7 @@ public abstract class DiditResources { private final AmlResource aml; private final AmlMonitoringResource amlMonitoring; private final AnalyticsResource analytics; + private final BankResource bank; private final BillingResource billing; private final BiometricTemplatesResource biometricTemplates; private final BlocklistResource blocklist; @@ -59,6 +60,7 @@ protected DiditResources(ApiClient client) { this.aml = new AmlResource(client); this.amlMonitoring = new AmlMonitoringResource(client); this.analytics = new AnalyticsResource(client); + this.bank = new BankResource(client); this.billing = new BillingResource(client); this.biometricTemplates = new BiometricTemplatesResource(client); this.blocklist = new BlocklistResource(client); @@ -140,6 +142,15 @@ public final AnalyticsResource analytics() { return analytics; } + /** + * The {@code bank} resource. + * + * @return the resource + */ + public final BankResource bank() { + return bank; + } + /** * The {@code billing} resource. * diff --git a/src/main/java/me/didit/types/BankAccountCheckBusinessHolder.java b/src/main/java/me/didit/types/BankAccountCheckBusinessHolder.java new file mode 100644 index 0000000..371c072 --- /dev/null +++ b/src/main/java/me/didit/types/BankAccountCheckBusinessHolder.java @@ -0,0 +1,100 @@ +// Code generated by codegen from openapi/*.json. DO NOT EDIT. +package me.didit.types; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.util.List; +import java.util.Map; +import java.util.Set; +import me.didit.core.Conv; +import me.didit.core.FileUpload; +import me.didit.core.Json; +import me.didit.core.JsonModel; + +/** The company that should hold the account. Checks a business account. */ +public final class BankAccountCheckBusinessHolder extends JsonModel { + private static final Set KNOWN_FIELDS = Set.of("business_name"); + + private BankAccountCheckBusinessHolder(ObjectNode json, Map> files) { + super(json, files); + } + + /** + * Reads a {@code BankAccountCheckBusinessHolder} from JSON. Unknown fields are kept and readable + * through {@link #_additionalProperties()}. + * + * @param json a JSON object + * @return the parsed value + */ + public static BankAccountCheckBusinessHolder fromJson(JsonNode json) { + return new BankAccountCheckBusinessHolder(Json.copyObject(json), Map.of()); + } + + /** + * Returns an empty builder. + * + * @return a new builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Returns a builder holding a copy of every field of this value. + * + * @return a new builder + */ + public Builder toBuilder() { + return new Builder(this); + } + + /** + * The name of the company that should hold the account. Checks a business account. + * + * @return the value + * @throws me.didit.errors.UnexpectedResponseException when the field is absent or has another type + */ + public String businessName() { + return Json.required(json, "business_name", Conv.STRING); + } + + @Override + protected Set knownFields() { + return KNOWN_FIELDS; + } + + /** Builds a {@link BankAccountCheckBusinessHolder}. */ + public static final class Builder extends JsonModel.BaseBuilder { + private Builder() {} + + private Builder(BankAccountCheckBusinessHolder from) { + super(from); + } + + /** + * The name of the company that should hold the account. Checks a business account. + * + * @param businessName the value + * @return this builder + */ + public Builder businessName(String businessName) { + return set("business_name", Conv.STRING, businessName); + } + + /** + * Builds the value. + * + * @return a new immutable {@code BankAccountCheckBusinessHolder} + * @throws IllegalStateException when a required field is missing + */ + public BankAccountCheckBusinessHolder build() { + require("business_name", false); + return new BankAccountCheckBusinessHolder(buildJson(), buildFiles()); + } + + @Override + protected Builder self() { + return this; + } + } +} diff --git a/src/main/java/me/didit/types/BankAccountCheckError.java b/src/main/java/me/didit/types/BankAccountCheckError.java new file mode 100644 index 0000000..8566adb --- /dev/null +++ b/src/main/java/me/didit/types/BankAccountCheckError.java @@ -0,0 +1,216 @@ +// Code generated by codegen from openapi/*.json. DO NOT EDIT. +package me.didit.types; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import me.didit.core.Conv; +import me.didit.core.FileUpload; +import me.didit.core.Json; +import me.didit.core.JsonModel; +import me.didit.core.StringEnum; + +public final class BankAccountCheckError extends JsonModel { + private static final Set KNOWN_FIELDS = Set.of("detail", "code", "field", "reason"); + + private BankAccountCheckError(ObjectNode json, Map> files) { + super(json, files); + } + + /** + * Reads a {@code BankAccountCheckError} from JSON. Unknown fields are kept and readable + * through {@link #_additionalProperties()}. + * + * @param json a JSON object + * @return the parsed value + */ + public static BankAccountCheckError fromJson(JsonNode json) { + return new BankAccountCheckError(Json.copyObject(json), Map.of()); + } + + /** + * Returns an empty builder. + * + * @return a new builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Returns a builder holding a copy of every field of this value. + * + * @return a new builder + */ + public Builder toBuilder() { + return new Builder(this); + } + + /** + * What went wrong, in English. + * + * @return the value + * @throws me.didit.errors.UnexpectedResponseException when the field is absent or has another type + */ + public String detail() { + return Json.required(json, "detail", Conv.STRING); + } + + /** + * A stable code to branch on. Absent on 401 and 403. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional code() { + return Json.optional(json, "code", Conv.STRING); + } + + /** + * 400 only: the body field to correct, as a dotted path, for example account.sort_code. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional field() { + return Json.optional(json, "field", Conv.STRING); + } + + /** + * 400 only: why the field was refused. required, length, format, checksum and country_mismatch (an IBAN of another country) are Didit's own checks; rejected means the bank refused the account as sent. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional reason() { + return Json.optional(json, "reason", Conv.enumeration(BankAccountCheckError.Reason::of)); + } + + @Override + protected Set knownFields() { + return KNOWN_FIELDS; + } + + /** Builds a {@link BankAccountCheckError}. */ + public static final class Builder extends JsonModel.BaseBuilder { + private Builder() {} + + private Builder(BankAccountCheckError from) { + super(from); + } + + /** + * What went wrong, in English. + * + * @param detail the value + * @return this builder + */ + public Builder detail(String detail) { + return set("detail", Conv.STRING, detail); + } + + /** + * A stable code to branch on. Absent on 401 and 403. + * + * @param code the value + * @return this builder + */ + public Builder code(String code) { + return set("code", Conv.STRING, code); + } + + /** + * 400 only: the body field to correct, as a dotted path, for example account.sort_code. + * + * @param field the value + * @return this builder + */ + public Builder field(String field) { + return set("field", Conv.STRING, field); + } + + /** + * 400 only: why the field was refused. required, length, format, checksum and country_mismatch (an IBAN of another country) are Didit's own checks; rejected means the bank refused the account as sent. + * + * @param reason the value + * @return this builder + */ + public Builder reason(BankAccountCheckError.Reason reason) { + return set("reason", Conv.enumeration(BankAccountCheckError.Reason::of), reason); + } + + /** + * Builds the value. + * + * @return a new immutable {@code BankAccountCheckError} + * @throws IllegalStateException when a required field is missing + */ + public BankAccountCheckError build() { + require("detail", false); + return new BankAccountCheckError(buildJson(), buildFiles()); + } + + @Override + protected Builder self() { + return this; + } + } + + /** + * 400 only: why the field was refused. required, length, format, checksum and country_mismatch (an IBAN of another country) are Didit's own checks; rejected means the bank refused the account as sent. + * + *

An open enum: {@link #of(String)} accepts values this SDK version does not know yet. + */ + public static final class Reason extends StringEnum { + /** The value {@code "required"}. */ + public static final Reason REQUIRED = new Reason("required"); + + /** The value {@code "length"}. */ + public static final Reason LENGTH = new Reason("length"); + + /** The value {@code "format"}. */ + public static final Reason FORMAT = new Reason("format"); + + /** The value {@code "checksum"}. */ + public static final Reason CHECKSUM = new Reason("checksum"); + + /** The value {@code "country_mismatch"}. */ + public static final Reason COUNTRY_MISMATCH = new Reason("country_mismatch"); + + /** The value {@code "rejected"}. */ + public static final Reason REJECTED = new Reason("rejected"); + + private static final List KNOWN_VALUES = List.of(REQUIRED, LENGTH, FORMAT, CHECKSUM, COUNTRY_MISMATCH, REJECTED); + + private Reason(String value) { + super(value); + } + + /** + * Returns the constant for a known value, or a new instance for any other value. + * + * @param value the string value + * @return the enum value + */ + public static Reason of(String value) { + return StringEnum.lookup(KNOWN_VALUES, value, Reason::new); + } + + /** + * Returns the values known to this SDK version. + * + * @return the known values + */ + public static List knownValues() { + return KNOWN_VALUES; + } + + @Override + public boolean isKnown() { + return KNOWN_VALUES.contains(this); + } + } +} diff --git a/src/main/java/me/didit/types/BankAccountCheckHolder.java b/src/main/java/me/didit/types/BankAccountCheckHolder.java new file mode 100644 index 0000000..6443a65 --- /dev/null +++ b/src/main/java/me/didit/types/BankAccountCheckHolder.java @@ -0,0 +1,90 @@ +// Code generated by codegen from openapi/*.json. DO NOT EDIT. +package me.didit.types; + +import com.fasterxml.jackson.databind.JsonNode; +import java.util.Optional; +import me.didit.core.Conv; +import me.didit.core.Json; +import me.didit.core.JsonUnion; + +/** + * The name the account is checked against. Send exactly one of full_name and business_name. + * + *

One of: {@code BankAccountCheckPersonHolder}, {@code BankAccountCheckBusinessHolder}. Check with the {@code is...} + * methods and read with the {@code as...} methods. + */ +public final class BankAccountCheckHolder extends JsonUnion { + private BankAccountCheckHolder(JsonNode json) { + super(json); + } + + /** + * Reads a {@code BankAccountCheckHolder} from JSON. + * + * @param json any JSON value + * @return the union + */ + public static BankAccountCheckHolder fromJson(JsonNode json) { + return new BankAccountCheckHolder(json.deepCopy()); + } + + /** + * Wraps a {@code BankAccountCheckPersonHolder} value. + * + * @param value the value + * @return the union + */ + public static BankAccountCheckHolder ofBankAccountCheckPersonHolder(BankAccountCheckPersonHolder value) { + return new BankAccountCheckHolder(Conv.model(BankAccountCheckPersonHolder::fromJson).write(value)); + } + + /** + * Whether this value is a {@code BankAccountCheckPersonHolder}. + * + * The person who should hold the account. + * + * @return true when it matches + */ + public boolean isBankAccountCheckPersonHolder() { + return Json.hasFields(json, "full_name"); + } + + /** + * Reads this value as a {@code BankAccountCheckPersonHolder}. + * + * @return the value, or empty when {@link #isBankAccountCheckPersonHolder()} is false + */ + public Optional asBankAccountCheckPersonHolder() { + return isBankAccountCheckPersonHolder() ? Optional.of(Conv.model(BankAccountCheckPersonHolder::fromJson).read(json)) : Optional.empty(); + } + + /** + * Wraps a {@code BankAccountCheckBusinessHolder} value. + * + * @param value the value + * @return the union + */ + public static BankAccountCheckHolder ofBankAccountCheckBusinessHolder(BankAccountCheckBusinessHolder value) { + return new BankAccountCheckHolder(Conv.model(BankAccountCheckBusinessHolder::fromJson).write(value)); + } + + /** + * Whether this value is a {@code BankAccountCheckBusinessHolder}. + * + * The company that should hold the account. Checks a business account. + * + * @return true when it matches + */ + public boolean isBankAccountCheckBusinessHolder() { + return Json.hasFields(json, "business_name"); + } + + /** + * Reads this value as a {@code BankAccountCheckBusinessHolder}. + * + * @return the value, or empty when {@link #isBankAccountCheckBusinessHolder()} is false + */ + public Optional asBankAccountCheckBusinessHolder() { + return isBankAccountCheckBusinessHolder() ? Optional.of(Conv.model(BankAccountCheckBusinessHolder::fromJson).read(json)) : Optional.empty(); + } +} diff --git a/src/main/java/me/didit/types/BankAccountCheckPersonHolder.java b/src/main/java/me/didit/types/BankAccountCheckPersonHolder.java new file mode 100644 index 0000000..6120f90 --- /dev/null +++ b/src/main/java/me/didit/types/BankAccountCheckPersonHolder.java @@ -0,0 +1,100 @@ +// Code generated by codegen from openapi/*.json. DO NOT EDIT. +package me.didit.types; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.util.List; +import java.util.Map; +import java.util.Set; +import me.didit.core.Conv; +import me.didit.core.FileUpload; +import me.didit.core.Json; +import me.didit.core.JsonModel; + +/** The person who should hold the account. */ +public final class BankAccountCheckPersonHolder extends JsonModel { + private static final Set KNOWN_FIELDS = Set.of("full_name"); + + private BankAccountCheckPersonHolder(ObjectNode json, Map> files) { + super(json, files); + } + + /** + * Reads a {@code BankAccountCheckPersonHolder} from JSON. Unknown fields are kept and readable + * through {@link #_additionalProperties()}. + * + * @param json a JSON object + * @return the parsed value + */ + public static BankAccountCheckPersonHolder fromJson(JsonNode json) { + return new BankAccountCheckPersonHolder(Json.copyObject(json), Map.of()); + } + + /** + * Returns an empty builder. + * + * @return a new builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Returns a builder holding a copy of every field of this value. + * + * @return a new builder + */ + public Builder toBuilder() { + return new Builder(this); + } + + /** + * The full name of the person who should hold the account. + * + * @return the value + * @throws me.didit.errors.UnexpectedResponseException when the field is absent or has another type + */ + public String fullName() { + return Json.required(json, "full_name", Conv.STRING); + } + + @Override + protected Set knownFields() { + return KNOWN_FIELDS; + } + + /** Builds a {@link BankAccountCheckPersonHolder}. */ + public static final class Builder extends JsonModel.BaseBuilder { + private Builder() {} + + private Builder(BankAccountCheckPersonHolder from) { + super(from); + } + + /** + * The full name of the person who should hold the account. + * + * @param fullName the value + * @return this builder + */ + public Builder fullName(String fullName) { + return set("full_name", Conv.STRING, fullName); + } + + /** + * Builds the value. + * + * @return a new immutable {@code BankAccountCheckPersonHolder} + * @throws IllegalStateException when a required field is missing + */ + public BankAccountCheckPersonHolder build() { + require("full_name", false); + return new BankAccountCheckPersonHolder(buildJson(), buildFiles()); + } + + @Override + protected Builder self() { + return this; + } + } +} diff --git a/src/main/java/me/didit/types/BankAccountCheckRequest.java b/src/main/java/me/didit/types/BankAccountCheckRequest.java new file mode 100644 index 0000000..0535be8 --- /dev/null +++ b/src/main/java/me/didit/types/BankAccountCheckRequest.java @@ -0,0 +1,471 @@ +// Code generated by codegen from openapi/*.json. DO NOT EDIT. +package me.didit.types; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import me.didit.core.Conv; +import me.didit.core.FileUpload; +import me.didit.core.Json; +import me.didit.core.JsonModel; +import org.jspecify.annotations.Nullable; + +public final class BankAccountCheckRequest extends JsonModel { + private static final Set KNOWN_FIELDS = Set.of("country", "account", "holder", "vendor_data"); + + private BankAccountCheckRequest(ObjectNode json, Map> files) { + super(json, files); + } + + /** + * Reads a {@code BankAccountCheckRequest} from JSON. Unknown fields are kept and readable + * through {@link #_additionalProperties()}. + * + * @param json a JSON object + * @return the parsed value + */ + public static BankAccountCheckRequest fromJson(JsonNode json) { + return new BankAccountCheckRequest(Json.copyObject(json), Map.of()); + } + + /** + * Returns an empty builder. + * + * @return a new builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Returns a builder holding a copy of every field of this value. + * + * @return a new builder + */ + public Builder toBuilder() { + return new Builder(this); + } + + /** + * The account's country, as an ISO 3166-1 alpha-3 code, for example GBR. Lowercase is accepted. + * + * @return the value + * @throws me.didit.errors.UnexpectedResponseException when the field is absent or has another type + */ + public String country() { + return Json.required(json, "country", Conv.STRING); + } + + /** + * The account the way its country writes it: an iban, or an account_number with the bank or branch code the country needs (sort_code, routing_number, transit_institution, bsb, ifsc, bank_code or bic). Mexico takes a clabe and Argentina a cbu_cvu, which already name the bank. A business account adds a registration_id where the country asks for one. Spaces, dashes and dots are ignored. Keys the country's check does not use are ignored; a key it needs and does not get is a 400 that names it. + * + * @return the value + * @throws me.didit.errors.UnexpectedResponseException when the field is absent or has another type + */ + public BankAccountCheckRequest.Account account() { + return Json.required(json, "account", Conv.model(BankAccountCheckRequest.Account::fromJson)); + } + + /** + * The name the account is checked against. Send exactly one of full_name and business_name. + * + * @return the value + * @throws me.didit.errors.UnexpectedResponseException when the field is absent or has another type + */ + public BankAccountCheckHolder holder() { + return Json.required(json, "holder", Conv.union(BankAccountCheckHolder::fromJson)); + } + + /** + * Your own reference for this check, returned unchanged. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional vendorData() { + return Json.optional(json, "vendor_data", Conv.STRING); + } + + @Override + protected Set knownFields() { + return KNOWN_FIELDS; + } + + /** Builds a {@link BankAccountCheckRequest}. */ + public static final class Builder extends JsonModel.BaseBuilder { + private Builder() {} + + private Builder(BankAccountCheckRequest from) { + super(from); + } + + /** + * The account's country, as an ISO 3166-1 alpha-3 code, for example GBR. Lowercase is accepted. + * + * @param country the value + * @return this builder + */ + public Builder country(String country) { + return set("country", Conv.STRING, country); + } + + /** + * The account the way its country writes it: an iban, or an account_number with the bank or branch code the country needs (sort_code, routing_number, transit_institution, bsb, ifsc, bank_code or bic). Mexico takes a clabe and Argentina a cbu_cvu, which already name the bank. A business account adds a registration_id where the country asks for one. Spaces, dashes and dots are ignored. Keys the country's check does not use are ignored; a key it needs and does not get is a 400 that names it. + * + * @param account the value + * @return this builder + */ + public Builder account(BankAccountCheckRequest.Account account) { + return set("account", Conv.model(BankAccountCheckRequest.Account::fromJson), account); + } + + /** + * The name the account is checked against. Send exactly one of full_name and business_name. + * + * @param holder the value + * @return this builder + */ + public Builder holder(BankAccountCheckHolder holder) { + return set("holder", Conv.union(BankAccountCheckHolder::fromJson), holder); + } + + /** + * Your own reference for this check, returned unchanged. + * + * @param vendorData the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder vendorData(@Nullable String vendorData) { + return setNullable("vendor_data", Conv.STRING, vendorData); + } + + /** + * Builds the value. + * + * @return a new immutable {@code BankAccountCheckRequest} + * @throws IllegalStateException when a required field is missing + */ + public BankAccountCheckRequest build() { + require("country", false); + require("account", false); + require("holder", false); + return new BankAccountCheckRequest(buildJson(), buildFiles()); + } + + @Override + protected Builder self() { + return this; + } + } + + /** + * The account the way its country writes it: an iban, or an account_number with the bank or branch code the country needs (sort_code, routing_number, transit_institution, bsb, ifsc, bank_code or bic). Mexico takes a clabe and Argentina a cbu_cvu, which already name the bank. A business account adds a registration_id where the country asks for one. Spaces, dashes and dots are ignored. Keys the country's check does not use are ignored; a key it needs and does not get is a 400 that names it. + */ + public static final class Account extends JsonModel { + private static final Set KNOWN_FIELDS = Set.of("iban", "account_number", "sort_code", "routing_number", "transit_institution", "bsb", "ifsc", "bank_code", "bic", "clabe", "cbu_cvu", "registration_id"); + + private Account(ObjectNode json, Map> files) { + super(json, files); + } + + /** + * Reads a {@code Account} from JSON. Unknown fields are kept and readable + * through {@link #_additionalProperties()}. + * + * @param json a JSON object + * @return the parsed value + */ + public static Account fromJson(JsonNode json) { + return new Account(Json.copyObject(json), Map.of()); + } + + /** + * Returns an empty builder. + * + * @return a new builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Returns a builder holding a copy of every field of this value. + * + * @return a new builder + */ + public Builder toBuilder() { + return new Builder(this); + } + + /** + * The IBAN, in a country that uses IBANs. It must belong to country. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional iban() { + return Json.optional(json, "iban", Conv.STRING); + } + + /** + * The account number, in a country that writes the account with a separate bank or branch code. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional accountNumber() { + return Json.optional(json, "account_number", Conv.STRING); + } + + /** + * United Kingdom: the 6-digit sort code. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional sortCode() { + return Json.optional(json, "sort_code", Conv.STRING); + } + + /** + * United States: the 9-digit ABA routing number. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional routingNumber() { + return Json.optional(json, "routing_number", Conv.STRING); + } + + /** + * Canada: the 8-digit transit and institution number. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional transitInstitution() { + return Json.optional(json, "transit_institution", Conv.STRING); + } + + /** + * Australia: the 6-digit BSB. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional bsb() { + return Json.optional(json, "bsb", Conv.STRING); + } + + /** + * India: the 11-character IFSC. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional ifsc() { + return Json.optional(json, "ifsc", Conv.STRING); + } + + /** + * The bank's code, where the country needs one, for example in Nigeria. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional bankCode() { + return Json.optional(json, "bank_code", Conv.STRING); + } + + /** + * The bank's BIC, where the country's check asks for one. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional bic() { + return Json.optional(json, "bic", Conv.STRING); + } + + /** + * Mexico: the 18-digit CLABE. It already names the bank. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional clabe() { + return Json.optional(json, "clabe", Conv.STRING); + } + + /** + * Argentina: the 22-digit CBU or CVU. It already names the bank. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional cbuCvu() { + return Json.optional(json, "cbu_cvu", Conv.STRING); + } + + /** + * A business account's registration number, where the country asks for one. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional registrationId() { + return Json.optional(json, "registration_id", Conv.STRING); + } + + @Override + protected Set knownFields() { + return KNOWN_FIELDS; + } + + /** Builds a {@link Account}. */ + public static final class Builder extends JsonModel.BaseBuilder { + private Builder() {} + + private Builder(Account from) { + super(from); + } + + /** + * The IBAN, in a country that uses IBANs. It must belong to country. + * + * @param iban the value + * @return this builder + */ + public Builder iban(String iban) { + return set("iban", Conv.STRING, iban); + } + + /** + * The account number, in a country that writes the account with a separate bank or branch code. + * + * @param accountNumber the value + * @return this builder + */ + public Builder accountNumber(String accountNumber) { + return set("account_number", Conv.STRING, accountNumber); + } + + /** + * United Kingdom: the 6-digit sort code. + * + * @param sortCode the value + * @return this builder + */ + public Builder sortCode(String sortCode) { + return set("sort_code", Conv.STRING, sortCode); + } + + /** + * United States: the 9-digit ABA routing number. + * + * @param routingNumber the value + * @return this builder + */ + public Builder routingNumber(String routingNumber) { + return set("routing_number", Conv.STRING, routingNumber); + } + + /** + * Canada: the 8-digit transit and institution number. + * + * @param transitInstitution the value + * @return this builder + */ + public Builder transitInstitution(String transitInstitution) { + return set("transit_institution", Conv.STRING, transitInstitution); + } + + /** + * Australia: the 6-digit BSB. + * + * @param bsb the value + * @return this builder + */ + public Builder bsb(String bsb) { + return set("bsb", Conv.STRING, bsb); + } + + /** + * India: the 11-character IFSC. + * + * @param ifsc the value + * @return this builder + */ + public Builder ifsc(String ifsc) { + return set("ifsc", Conv.STRING, ifsc); + } + + /** + * The bank's code, where the country needs one, for example in Nigeria. + * + * @param bankCode the value + * @return this builder + */ + public Builder bankCode(String bankCode) { + return set("bank_code", Conv.STRING, bankCode); + } + + /** + * The bank's BIC, where the country's check asks for one. + * + * @param bic the value + * @return this builder + */ + public Builder bic(String bic) { + return set("bic", Conv.STRING, bic); + } + + /** + * Mexico: the 18-digit CLABE. It already names the bank. + * + * @param clabe the value + * @return this builder + */ + public Builder clabe(String clabe) { + return set("clabe", Conv.STRING, clabe); + } + + /** + * Argentina: the 22-digit CBU or CVU. It already names the bank. + * + * @param cbuCvu the value + * @return this builder + */ + public Builder cbuCvu(String cbuCvu) { + return set("cbu_cvu", Conv.STRING, cbuCvu); + } + + /** + * A business account's registration number, where the country asks for one. + * + * @param registrationId the value + * @return this builder + */ + public Builder registrationId(String registrationId) { + return set("registration_id", Conv.STRING, registrationId); + } + + /** + * Builds the value. + * + * @return a new immutable {@code Account} + */ + public Account build() { + return new Account(buildJson(), buildFiles()); + } + + @Override + protected Builder self() { + return this; + } + } + } +} diff --git a/src/main/java/me/didit/types/BankAccountCheckResponse.java b/src/main/java/me/didit/types/BankAccountCheckResponse.java new file mode 100644 index 0000000..65c5f94 --- /dev/null +++ b/src/main/java/me/didit/types/BankAccountCheckResponse.java @@ -0,0 +1,257 @@ +// Code generated by codegen from openapi/*.json. DO NOT EDIT. +package me.didit.types; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.time.OffsetDateTime; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import me.didit.core.Conv; +import me.didit.core.FileUpload; +import me.didit.core.Json; +import me.didit.core.JsonModel; +import me.didit.core.StringEnum; +import org.jspecify.annotations.Nullable; + +public final class BankAccountCheckResponse extends JsonModel { + private static final Set KNOWN_FIELDS = Set.of("request_id", "result", "holder_name", "account", "vendor_data", "created_at"); + + private BankAccountCheckResponse(ObjectNode json, Map> files) { + super(json, files); + } + + /** + * Reads a {@code BankAccountCheckResponse} from JSON. Unknown fields are kept and readable + * through {@link #_additionalProperties()}. + * + * @param json a JSON object + * @return the parsed value + */ + public static BankAccountCheckResponse fromJson(JsonNode json) { + return new BankAccountCheckResponse(Json.copyObject(json), Map.of()); + } + + /** + * Returns an empty builder. + * + * @return a new builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Returns a builder holding a copy of every field of this value. + * + * @return a new builder + */ + public Builder toBuilder() { + return new Builder(this); + } + + /** + * The ID of this check. + * + * @return the value + * @throws me.didit.errors.UnexpectedResponseException when the field is absent or has another type + */ + public String requestId() { + return Json.required(json, "request_id", Conv.STRING); + } + + /** + * match: the bank holds the account under the name you sent. close_match: under a close name, for example a missing middle name or a typo. no_match: under another name, or there is no such account. cannot_verify: the bank answered without comparing the name, for example for a blocked or closed account. + * + * @return the value + * @throws me.didit.errors.UnexpectedResponseException when the field is absent or has another type + */ + public BankAccountCheckResponse.Result result() { + return Json.required(json, "result", Conv.enumeration(BankAccountCheckResponse.Result::of)); + } + + /** + * Only on a close_match, and only when the bank returned it: the name on the account, as the bank holds it. null otherwise. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional holderName() { + return Json.optional(json, "holder_name", Conv.STRING); + } + + /** + * The account, masked to its last 4 characters. + * + * @return the value + * @throws me.didit.errors.UnexpectedResponseException when the field is absent or has another type + */ + public String account() { + return Json.required(json, "account", Conv.STRING); + } + + /** + * Your own reference, as you sent it. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional vendorData() { + return Json.optional(json, "vendor_data", Conv.STRING); + } + + /** + * When the check ran, in UTC. + * + * @return the value + * @throws me.didit.errors.UnexpectedResponseException when the field is absent or has another type + */ + public OffsetDateTime createdAt() { + return Json.required(json, "created_at", Conv.DATE_TIME); + } + + @Override + protected Set knownFields() { + return KNOWN_FIELDS; + } + + /** Builds a {@link BankAccountCheckResponse}. */ + public static final class Builder extends JsonModel.BaseBuilder { + private Builder() {} + + private Builder(BankAccountCheckResponse from) { + super(from); + } + + /** + * The ID of this check. + * + * @param requestId the value + * @return this builder + */ + public Builder requestId(String requestId) { + return set("request_id", Conv.STRING, requestId); + } + + /** + * match: the bank holds the account under the name you sent. close_match: under a close name, for example a missing middle name or a typo. no_match: under another name, or there is no such account. cannot_verify: the bank answered without comparing the name, for example for a blocked or closed account. + * + * @param result the value + * @return this builder + */ + public Builder result(BankAccountCheckResponse.Result result) { + return set("result", Conv.enumeration(BankAccountCheckResponse.Result::of), result); + } + + /** + * Only on a close_match, and only when the bank returned it: the name on the account, as the bank holds it. null otherwise. + * + * @param holderName the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder holderName(@Nullable String holderName) { + return setNullable("holder_name", Conv.STRING, holderName); + } + + /** + * The account, masked to its last 4 characters. + * + * @param account the value + * @return this builder + */ + public Builder account(String account) { + return set("account", Conv.STRING, account); + } + + /** + * Your own reference, as you sent it. + * + * @param vendorData the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder vendorData(@Nullable String vendorData) { + return setNullable("vendor_data", Conv.STRING, vendorData); + } + + /** + * When the check ran, in UTC. + * + * @param createdAt the value + * @return this builder + */ + public Builder createdAt(OffsetDateTime createdAt) { + return set("created_at", Conv.DATE_TIME, createdAt); + } + + /** + * Builds the value. + * + * @return a new immutable {@code BankAccountCheckResponse} + * @throws IllegalStateException when a required field is missing + */ + public BankAccountCheckResponse build() { + require("request_id", false); + require("result", false); + require("holder_name", true); + require("account", false); + require("vendor_data", true); + require("created_at", false); + return new BankAccountCheckResponse(buildJson(), buildFiles()); + } + + @Override + protected Builder self() { + return this; + } + } + + /** + * match: the bank holds the account under the name you sent. close_match: under a close name, for example a missing middle name or a typo. no_match: under another name, or there is no such account. cannot_verify: the bank answered without comparing the name, for example for a blocked or closed account. + * + *

An open enum: {@link #of(String)} accepts values this SDK version does not know yet. + */ + public static final class Result extends StringEnum { + /** The value {@code "match"}. */ + public static final Result MATCH = new Result("match"); + + /** The value {@code "close_match"}. */ + public static final Result CLOSE_MATCH = new Result("close_match"); + + /** The value {@code "no_match"}. */ + public static final Result NO_MATCH = new Result("no_match"); + + /** The value {@code "cannot_verify"}. */ + public static final Result CANNOT_VERIFY = new Result("cannot_verify"); + + private static final List KNOWN_VALUES = List.of(MATCH, CLOSE_MATCH, NO_MATCH, CANNOT_VERIFY); + + private Result(String value) { + super(value); + } + + /** + * Returns the constant for a known value, or a new instance for any other value. + * + * @param value the string value + * @return the enum value + */ + public static Result of(String value) { + return StringEnum.lookup(KNOWN_VALUES, value, Result::new); + } + + /** + * Returns the values known to this SDK version. + * + * @return the known values + */ + public static List knownValues() { + return KNOWN_VALUES; + } + + @Override + public boolean isKnown() { + return KNOWN_VALUES.contains(this); + } + } +} diff --git a/src/main/java/me/didit/types/BankVerificationResult.java b/src/main/java/me/didit/types/BankVerificationResult.java new file mode 100644 index 0000000..5062932 --- /dev/null +++ b/src/main/java/me/didit/types/BankVerificationResult.java @@ -0,0 +1,2591 @@ +// Code generated by codegen from openapi/*.json. DO NOT EDIT. +package me.didit.types; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.time.OffsetDateTime; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import me.didit.core.Conv; +import me.didit.core.FileUpload; +import me.didit.core.Json; +import me.didit.core.JsonModel; +import me.didit.core.StringEnum; +import org.jspecify.annotations.Nullable; + +/** + * 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). + */ +public final class BankVerificationResult extends JsonModel { + private static final Set KNOWN_FIELDS = Set.of("schema_version", "bank_verification_id", "node_id", "status", "original_status", "method", "provider", "credential_source", "route", "connection", "account", "ownership", "financial_data", "billing", "reference_identity", "signals", "connection_abandoned", "not_covered", "evidence_purged_at", "warnings", "reason_codes", "created_at", "updated_at"); + + private BankVerificationResult(ObjectNode json, Map> files) { + super(json, files); + } + + /** + * Reads a {@code BankVerificationResult} from JSON. Unknown fields are kept and readable + * through {@link #_additionalProperties()}. + * + * @param json a JSON object + * @return the parsed value + */ + public static BankVerificationResult fromJson(JsonNode json) { + return new BankVerificationResult(Json.copyObject(json), Map.of()); + } + + /** + * Returns an empty builder. + * + * @return a new builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Returns a builder holding a copy of every field of this value. + * + * @return a new builder + */ + public Builder toBuilder() { + return new Builder(this); + } + + /** + * Version of this result shape. 1 today. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional schemaVersion() { + return Json.optional(json, "schema_version", Conv.LONG); + } + + /** + * The ID of this result. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional bankVerificationId() { + return Json.optional(json, "bank_verification_id", Conv.STRING); + } + + /** + * The workflow node this result belongs to. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional nodeId() { + return Json.optional(json, "node_id", Conv.STRING); + } + + /** + * The step's verdict, after its actions and status rules. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional status() { + return Json.optional(json, "status", Conv.enumeration(BankVerificationResult.Status::of)); + } + + /** + * The first verdict the step reached, before any later change such as a manual review. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional originalStatus() { + return Json.optional(json, "original_status", Conv.STRING); + } + + /** + * 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. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional method() { + return Json.optional(json, "method", Conv.enumeration(BankVerificationResult.Method::of)); + } + + /** + * The key of the route that ran the connection. Read method, not this key, to tell how the account was verified. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional provider() { + return Json.optional(json, "provider", Conv.STRING); + } + + /** + * native: Didit's own route, billed to your Didit balance. byok: a marketplace provider you connected with your own credentials. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional credentialSource() { + return Json.optional(json, "credential_source", Conv.enumeration(BankVerificationResult.CredentialSource::of)); + } + + /** + * The route chosen before consent. It never changes afterwards. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional route() { + return Json.optional(json, "route", Conv.model(BankVerificationResult.Route::fromJson)); + } + + /** + * The latest attempt's connection. null before the first attempt. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional connection() { + return Json.optional(json, "connection", Conv.model(BankVerificationResult.Connection::fromJson)); + } + + /** + * The evaluated account. null until an account is evaluated. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional account() { + return Json.optional(json, "account", Conv.model(BankVerificationResult.Account::fromJson)); + } + + /** + * How the account holder compared with the verified identity. null until an account is evaluated. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional ownership() { + return Json.optional(json, "ownership", Conv.model(BankVerificationResult.Ownership::fromJson)); + } + + /** + * The financial data the step read. Only bank sign-in reads it. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional financialData() { + return Json.optional(json, "financial_data", Conv.model(BankVerificationResult.FinancialData::fromJson)); + } + + /** + * The billing field. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional billing() { + return Json.optional(json, "billing", Conv.model(BankVerificationResult.Billing::fromJson)); + } + + /** + * The identity the holder was compared against, with its source. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional> referenceIdentity() { + return Json.optional(json, "reference_identity", Conv.OBJECT); + } + + /** + * Account signals read from the transaction history, when the step read one. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional> signals() { + return Json.optional(json, "signals", Conv.OBJECT); + } + + /** + * Whether the step ended without a match after the person left at their bank. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional connectionAbandoned() { + return Json.optional(json, "connection_abandoned", Conv.BOOLEAN); + } + + /** + * Whether the person's bank or country could not be reached on this step. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional notCovered() { + return Json.optional(json, "not_covered", Conv.BOOLEAN); + } + + /** + * When the bank evidence was deleted under bank_evidence_retention_days. null otherwise. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional evidencePurgedAt() { + return Json.optional(json, "evidence_purged_at", Conv.DATE_TIME); + } + + /** + * Informational codes, for example holder_declared. A warning never changes the status on its own. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional> warnings() { + return Json.optional(json, "warnings", Conv.list(Conv.STRING)); + } + + /** + * Why the verdict came out the way it did, for example OWNER_NAME_PARTIAL. Several may apply. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional> reasonCodes() { + return Json.optional(json, "reason_codes", Conv.list(Conv.STRING)); + } + + /** + * The created_at field. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional createdAt() { + return Json.optional(json, "created_at", Conv.DATE_TIME); + } + + /** + * The updated_at field. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional updatedAt() { + return Json.optional(json, "updated_at", Conv.DATE_TIME); + } + + @Override + protected Set knownFields() { + return KNOWN_FIELDS; + } + + /** Builds a {@link BankVerificationResult}. */ + public static final class Builder extends JsonModel.BaseBuilder { + private Builder() {} + + private Builder(BankVerificationResult from) { + super(from); + } + + /** + * Version of this result shape. 1 today. + * + * @param schemaVersion the value + * @return this builder + */ + public Builder schemaVersion(long schemaVersion) { + return set("schema_version", Conv.LONG, schemaVersion); + } + + /** + * The ID of this result. + * + * @param bankVerificationId the value + * @return this builder + */ + public Builder bankVerificationId(String bankVerificationId) { + return set("bank_verification_id", Conv.STRING, bankVerificationId); + } + + /** + * The workflow node this result belongs to. + * + * @param nodeId the value + * @return this builder + */ + public Builder nodeId(String nodeId) { + return set("node_id", Conv.STRING, nodeId); + } + + /** + * The step's verdict, after its actions and status rules. + * + * @param status the value + * @return this builder + */ + public Builder status(BankVerificationResult.Status status) { + return set("status", Conv.enumeration(BankVerificationResult.Status::of), status); + } + + /** + * The first verdict the step reached, before any later change such as a manual review. + * + * @param originalStatus the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder originalStatus(@Nullable String originalStatus) { + return setNullable("original_status", Conv.STRING, originalStatus); + } + + /** + * 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. + * + * @param method the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder method(BankVerificationResult.@Nullable Method method) { + return setNullable("method", Conv.enumeration(BankVerificationResult.Method::of), method); + } + + /** + * The key of the route that ran the connection. Read method, not this key, to tell how the account was verified. + * + * @param provider the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder provider(@Nullable String provider) { + return setNullable("provider", Conv.STRING, provider); + } + + /** + * native: Didit's own route, billed to your Didit balance. byok: a marketplace provider you connected with your own credentials. + * + * @param credentialSource the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder credentialSource(BankVerificationResult.@Nullable CredentialSource credentialSource) { + return setNullable("credential_source", Conv.enumeration(BankVerificationResult.CredentialSource::of), credentialSource); + } + + /** + * The route chosen before consent. It never changes afterwards. + * + * @param route the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder route(BankVerificationResult.@Nullable Route route) { + return setNullable("route", Conv.model(BankVerificationResult.Route::fromJson), route); + } + + /** + * The latest attempt's connection. null before the first attempt. + * + * @param connection the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder connection(BankVerificationResult.@Nullable Connection connection) { + return setNullable("connection", Conv.model(BankVerificationResult.Connection::fromJson), connection); + } + + /** + * The evaluated account. null until an account is evaluated. + * + * @param account the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder account(BankVerificationResult.@Nullable Account account) { + return setNullable("account", Conv.model(BankVerificationResult.Account::fromJson), account); + } + + /** + * How the account holder compared with the verified identity. null until an account is evaluated. + * + * @param ownership the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder ownership(BankVerificationResult.@Nullable Ownership ownership) { + return setNullable("ownership", Conv.model(BankVerificationResult.Ownership::fromJson), ownership); + } + + /** + * The financial data the step read. Only bank sign-in reads it. + * + * @param financialData the value + * @return this builder + */ + public Builder financialData(BankVerificationResult.FinancialData financialData) { + return set("financial_data", Conv.model(BankVerificationResult.FinancialData::fromJson), financialData); + } + + /** + * The billing field. + * + * @param billing the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder billing(BankVerificationResult.@Nullable Billing billing) { + return setNullable("billing", Conv.model(BankVerificationResult.Billing::fromJson), billing); + } + + /** + * The identity the holder was compared against, with its source. + * + * @param referenceIdentity the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder referenceIdentity(@Nullable Map referenceIdentity) { + return setAny("reference_identity", referenceIdentity); + } + + /** + * Account signals read from the transaction history, when the step read one. + * + * @param signals the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder signals(@Nullable Map signals) { + return setAny("signals", signals); + } + + /** + * Whether the step ended without a match after the person left at their bank. + * + * @param connectionAbandoned the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder connectionAbandoned(@Nullable Boolean connectionAbandoned) { + return setNullable("connection_abandoned", Conv.BOOLEAN, connectionAbandoned); + } + + /** + * Whether the person's bank or country could not be reached on this step. + * + * @param notCovered the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder notCovered(@Nullable Boolean notCovered) { + return setNullable("not_covered", Conv.BOOLEAN, notCovered); + } + + /** + * When the bank evidence was deleted under bank_evidence_retention_days. null otherwise. + * + * @param evidencePurgedAt the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder evidencePurgedAt(@Nullable OffsetDateTime evidencePurgedAt) { + return setNullable("evidence_purged_at", Conv.DATE_TIME, evidencePurgedAt); + } + + /** + * Informational codes, for example holder_declared. A warning never changes the status on its own. + * + * @param warnings the value + * @return this builder + */ + public Builder warnings(List warnings) { + return set("warnings", Conv.list(Conv.STRING), warnings); + } + + /** + * Why the verdict came out the way it did, for example OWNER_NAME_PARTIAL. Several may apply. + * + * @param reasonCodes the value + * @return this builder + */ + public Builder reasonCodes(List reasonCodes) { + return set("reason_codes", Conv.list(Conv.STRING), reasonCodes); + } + + /** + * The created_at field. + * + * @param createdAt the value + * @return this builder + */ + public Builder createdAt(OffsetDateTime createdAt) { + return set("created_at", Conv.DATE_TIME, createdAt); + } + + /** + * The updated_at field. + * + * @param updatedAt the value + * @return this builder + */ + public Builder updatedAt(OffsetDateTime updatedAt) { + return set("updated_at", Conv.DATE_TIME, updatedAt); + } + + /** + * Builds the value. + * + * @return a new immutable {@code BankVerificationResult} + */ + public BankVerificationResult build() { + return new BankVerificationResult(buildJson(), buildFiles()); + } + + @Override + protected Builder self() { + return this; + } + } + + /** + * The step's verdict, after its actions and status rules. + * + *

An open enum: {@link #of(String)} accepts values this SDK version does not know yet. + */ + public static final class Status extends StringEnum { + /** The value {@code "Not Finished"}. */ + public static final Status NOT_FINISHED = new Status("Not Finished"); + + /** The value {@code "Approved"}. */ + public static final Status APPROVED = new Status("Approved"); + + /** The value {@code "Declined"}. */ + public static final Status DECLINED = new Status("Declined"); + + /** The value {@code "In Review"}. */ + public static final Status IN_REVIEW = new Status("In Review"); + + /** The value {@code "Expired"}. */ + public static final Status EXPIRED = new Status("Expired"); + + private static final List KNOWN_VALUES = List.of(NOT_FINISHED, APPROVED, DECLINED, IN_REVIEW, EXPIRED); + + private Status(String value) { + super(value); + } + + /** + * Returns the constant for a known value, or a new instance for any other value. + * + * @param value the string value + * @return the enum value + */ + public static Status of(String value) { + return StringEnum.lookup(KNOWN_VALUES, value, Status::new); + } + + /** + * Returns the values known to this SDK version. + * + * @return the known values + */ + public static List knownValues() { + return KNOWN_VALUES; + } + + @Override + public boolean isKnown() { + return KNOWN_VALUES.contains(this); + } + } + + /** + * 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. + * + *

An open enum: {@link #of(String)} accepts values this SDK version does not know yet. + */ + public static final class Method extends StringEnum { + /** The value {@code "open_banking"}. */ + public static final Method OPEN_BANKING = new Method("open_banking"); + + /** The value {@code "account_lookup"}. */ + public static final Method ACCOUNT_LOOKUP = new Method("account_lookup"); + + /** The value {@code "microdeposits"}. */ + public static final Method MICRODEPOSITS = new Method("microdeposits"); + + /** The value {@code "statement"}. */ + public static final Method STATEMENT = new Method("statement"); + + private static final List KNOWN_VALUES = List.of(OPEN_BANKING, ACCOUNT_LOOKUP, MICRODEPOSITS, STATEMENT); + + private Method(String value) { + super(value); + } + + /** + * Returns the constant for a known value, or a new instance for any other value. + * + * @param value the string value + * @return the enum value + */ + public static Method of(String value) { + return StringEnum.lookup(KNOWN_VALUES, value, Method::new); + } + + /** + * Returns the values known to this SDK version. + * + * @return the known values + */ + public static List knownValues() { + return KNOWN_VALUES; + } + + @Override + public boolean isKnown() { + return KNOWN_VALUES.contains(this); + } + } + + /** + * native: Didit's own route, billed to your Didit balance. byok: a marketplace provider you connected with your own credentials. + * + *

An open enum: {@link #of(String)} accepts values this SDK version does not know yet. + */ + public static final class CredentialSource extends StringEnum { + /** The value {@code "native"}. */ + public static final CredentialSource NATIVE = new CredentialSource("native"); + + /** The value {@code "byok"}. */ + public static final CredentialSource BYOK = new CredentialSource("byok"); + + private static final List KNOWN_VALUES = List.of(NATIVE, BYOK); + + private CredentialSource(String value) { + super(value); + } + + /** + * Returns the constant for a known value, or a new instance for any other value. + * + * @param value the string value + * @return the enum value + */ + public static CredentialSource of(String value) { + return StringEnum.lookup(KNOWN_VALUES, value, CredentialSource::new); + } + + /** + * Returns the values known to this SDK version. + * + * @return the known values + */ + public static List knownValues() { + return KNOWN_VALUES; + } + + @Override + public boolean isKnown() { + return KNOWN_VALUES.contains(this); + } + } + + /** The route chosen before consent. It never changes afterwards. */ + public static final class Route extends JsonModel { + private static final Set KNOWN_FIELDS = Set.of("provider_key", "credential_source", "is_fallback", "provider_connection_id", "requested_scopes"); + + private Route(ObjectNode json, Map> files) { + super(json, files); + } + + /** + * Reads a {@code Route} from JSON. Unknown fields are kept and readable + * through {@link #_additionalProperties()}. + * + * @param json a JSON object + * @return the parsed value + */ + public static Route fromJson(JsonNode json) { + return new Route(Json.copyObject(json), Map.of()); + } + + /** + * Returns an empty builder. + * + * @return a new builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Returns a builder holding a copy of every field of this value. + * + * @return a new builder + */ + public Builder toBuilder() { + return new Builder(this); + } + + /** + * The route's key. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional providerKey() { + return Json.optional(json, "provider_key", Conv.STRING); + } + + /** + * The credential_source field. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional credentialSource() { + return Json.optional(json, "credential_source", Conv.enumeration(BankVerificationResult.Route.CredentialSource::of)); + } + + /** + * Whether Didit's own route stood in for a marketplace provider that could not connect. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional isFallback() { + return Json.optional(json, "is_fallback", Conv.BOOLEAN); + } + + /** + * The marketplace connection used, for byok. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional providerConnectionId() { + return Json.optional(json, "provider_connection_id", Conv.STRING); + } + + /** + * The data the connection asked for, for example ownership or balances. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional> requestedScopes() { + return Json.optional(json, "requested_scopes", Conv.list(Conv.STRING)); + } + + @Override + protected Set knownFields() { + return KNOWN_FIELDS; + } + + /** Builds a {@link Route}. */ + public static final class Builder extends JsonModel.BaseBuilder { + private Builder() {} + + private Builder(Route from) { + super(from); + } + + /** + * The route's key. + * + * @param providerKey the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder providerKey(@Nullable String providerKey) { + return setNullable("provider_key", Conv.STRING, providerKey); + } + + /** + * The credential_source field. + * + * @param credentialSource the value + * @return this builder + */ + public Builder credentialSource(BankVerificationResult.Route.CredentialSource credentialSource) { + return set("credential_source", Conv.enumeration(BankVerificationResult.Route.CredentialSource::of), credentialSource); + } + + /** + * Whether Didit's own route stood in for a marketplace provider that could not connect. + * + * @param isFallback the value + * @return this builder + */ + public Builder isFallback(boolean isFallback) { + return set("is_fallback", Conv.BOOLEAN, isFallback); + } + + /** + * The marketplace connection used, for byok. + * + * @param providerConnectionId the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder providerConnectionId(@Nullable String providerConnectionId) { + return setNullable("provider_connection_id", Conv.STRING, providerConnectionId); + } + + /** + * The data the connection asked for, for example ownership or balances. + * + * @param requestedScopes the value + * @return this builder + */ + public Builder requestedScopes(List requestedScopes) { + return set("requested_scopes", Conv.list(Conv.STRING), requestedScopes); + } + + /** + * Builds the value. + * + * @return a new immutable {@code Route} + */ + public Route build() { + return new Route(buildJson(), buildFiles()); + } + + @Override + protected Builder self() { + return this; + } + } + + /** + * + *

An open enum: {@link #of(String)} accepts values this SDK version does not know yet. + */ + public static final class CredentialSource extends StringEnum { + /** The value {@code "native"}. */ + public static final CredentialSource NATIVE = new CredentialSource("native"); + + /** The value {@code "byok"}. */ + public static final CredentialSource BYOK = new CredentialSource("byok"); + + private static final List KNOWN_VALUES = List.of(NATIVE, BYOK); + + private CredentialSource(String value) { + super(value); + } + + /** + * Returns the constant for a known value, or a new instance for any other value. + * + * @param value the string value + * @return the enum value + */ + public static CredentialSource of(String value) { + return StringEnum.lookup(KNOWN_VALUES, value, CredentialSource::new); + } + + /** + * Returns the values known to this SDK version. + * + * @return the known values + */ + public static List knownValues() { + return KNOWN_VALUES; + } + + @Override + public boolean isKnown() { + return KNOWN_VALUES.contains(this); + } + } + } + + /** The latest attempt's connection. null before the first attempt. */ + public static final class Connection extends JsonModel { + private static final Set KNOWN_FIELDS = Set.of("status", "institution_id", "institution_name", "institution_country", "oauth", "connected_at", "consent_expires_at", "last_refreshed_at", "attempts", "reason_code"); + + private Connection(ObjectNode json, Map> files) { + super(json, files); + } + + /** + * Reads a {@code Connection} from JSON. Unknown fields are kept and readable + * through {@link #_additionalProperties()}. + * + * @param json a JSON object + * @return the parsed value + */ + public static Connection fromJson(JsonNode json) { + return new Connection(Json.copyObject(json), Map.of()); + } + + /** + * Returns an empty builder. + * + * @return a new builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Returns a builder holding a copy of every field of this value. + * + * @return a new builder + */ + public Builder toBuilder() { + return new Builder(this); + } + + /** + * The status field. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional status() { + return Json.optional(json, "status", Conv.enumeration(BankVerificationResult.Connection.Status::of)); + } + + /** + * The bank's ID. null for an account check, where no bank is picked. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional institutionId() { + return Json.optional(json, "institution_id", Conv.STRING); + } + + /** + * The bank's name. null for an account check. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional institutionName() { + return Json.optional(json, "institution_name", Conv.STRING); + } + + /** + * The account's country, ISO 3166-1 alpha-3. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional institutionCountry() { + return Json.optional(json, "institution_country", Conv.STRING); + } + + /** + * Whether the bank sign-in ran over OAuth or app-to-app. null for an account check. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional oauth() { + return Json.optional(json, "oauth", Conv.BOOLEAN); + } + + /** + * When the connection succeeded. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional connectedAt() { + return Json.optional(json, "connected_at", Conv.DATE_TIME); + } + + /** + * When the bank consent ends, for bank sign-in. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional consentExpiresAt() { + return Json.optional(json, "consent_expires_at", Conv.DATE_TIME); + } + + /** + * When the financial data was last read again. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional lastRefreshedAt() { + return Json.optional(json, "last_refreshed_at", Conv.DATE_TIME); + } + + /** + * The attempts the person spent on this step, every method together. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional attempts() { + return Json.optional(json, "attempts", Conv.LONG); + } + + /** + * Why the connection is not simply connected, for example USER_CANCELLED, INSTITUTION_DOWN, ACCOUNT_NOT_FOUND, REFERENCE_IDENTITY_MISSING or VERIFICATION_COMPLETED. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional reasonCode() { + return Json.optional(json, "reason_code", Conv.STRING); + } + + @Override + protected Set knownFields() { + return KNOWN_FIELDS; + } + + /** Builds a {@link Connection}. */ + public static final class Builder extends JsonModel.BaseBuilder { + private Builder() {} + + private Builder(Connection from) { + super(from); + } + + /** + * The status field. + * + * @param status the value + * @return this builder + */ + public Builder status(BankVerificationResult.Connection.Status status) { + return set("status", Conv.enumeration(BankVerificationResult.Connection.Status::of), status); + } + + /** + * The bank's ID. null for an account check, where no bank is picked. + * + * @param institutionId the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder institutionId(@Nullable String institutionId) { + return setNullable("institution_id", Conv.STRING, institutionId); + } + + /** + * The bank's name. null for an account check. + * + * @param institutionName the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder institutionName(@Nullable String institutionName) { + return setNullable("institution_name", Conv.STRING, institutionName); + } + + /** + * The account's country, ISO 3166-1 alpha-3. + * + * @param institutionCountry the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder institutionCountry(@Nullable String institutionCountry) { + return setNullable("institution_country", Conv.STRING, institutionCountry); + } + + /** + * Whether the bank sign-in ran over OAuth or app-to-app. null for an account check. + * + * @param oauth the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder oauth(@Nullable Boolean oauth) { + return setNullable("oauth", Conv.BOOLEAN, oauth); + } + + /** + * When the connection succeeded. + * + * @param connectedAt the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder connectedAt(@Nullable OffsetDateTime connectedAt) { + return setNullable("connected_at", Conv.DATE_TIME, connectedAt); + } + + /** + * When the bank consent ends, for bank sign-in. + * + * @param consentExpiresAt the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder consentExpiresAt(@Nullable OffsetDateTime consentExpiresAt) { + return setNullable("consent_expires_at", Conv.DATE_TIME, consentExpiresAt); + } + + /** + * When the financial data was last read again. + * + * @param lastRefreshedAt the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder lastRefreshedAt(@Nullable OffsetDateTime lastRefreshedAt) { + return setNullable("last_refreshed_at", Conv.DATE_TIME, lastRefreshedAt); + } + + /** + * The attempts the person spent on this step, every method together. + * + * @param attempts the value + * @return this builder + */ + public Builder attempts(long attempts) { + return set("attempts", Conv.LONG, attempts); + } + + /** + * Why the connection is not simply connected, for example USER_CANCELLED, INSTITUTION_DOWN, ACCOUNT_NOT_FOUND, REFERENCE_IDENTITY_MISSING or VERIFICATION_COMPLETED. + * + * @param reasonCode the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder reasonCode(@Nullable String reasonCode) { + return setNullable("reason_code", Conv.STRING, reasonCode); + } + + /** + * Builds the value. + * + * @return a new immutable {@code Connection} + */ + public Connection build() { + return new Connection(buildJson(), buildFiles()); + } + + @Override + protected Builder self() { + return this; + } + } + + /** + * + *

An open enum: {@link #of(String)} accepts values this SDK version does not know yet. + */ + public static final class Status extends StringEnum { + /** The value {@code "pending"}. */ + public static final Status PENDING = new Status("pending"); + + /** The value {@code "connected"}. */ + public static final Status CONNECTED = new Status("connected"); + + /** The value {@code "cancelled"}. */ + public static final Status CANCELLED = new Status("cancelled"); + + /** The value {@code "timeout"}. */ + public static final Status TIMEOUT = new Status("timeout"); + + /** The value {@code "failed"}. */ + public static final Status FAILED = new Status("failed"); + + /** The value {@code "unsupported"}. */ + public static final Status UNSUPPORTED = new Status("unsupported"); + + /** The value {@code "revoked"}. */ + public static final Status REVOKED = new Status("revoked"); + + /** The value {@code "expired"}. */ + public static final Status EXPIRED = new Status("expired"); + + private static final List KNOWN_VALUES = List.of(PENDING, CONNECTED, CANCELLED, TIMEOUT, FAILED, UNSUPPORTED, REVOKED, EXPIRED); + + private Status(String value) { + super(value); + } + + /** + * Returns the constant for a known value, or a new instance for any other value. + * + * @param value the string value + * @return the enum value + */ + public static Status of(String value) { + return StringEnum.lookup(KNOWN_VALUES, value, Status::new); + } + + /** + * Returns the values known to this SDK version. + * + * @return the known values + */ + public static List knownValues() { + return KNOWN_VALUES; + } + + @Override + public boolean isKnown() { + return KNOWN_VALUES.contains(this); + } + } + } + + /** The evaluated account. null until an account is evaluated. */ + public static final class Account extends JsonModel { + private static final Set KNOWN_FIELDS = Set.of("account_id_masked", "iban_masked", "sort_code", "routing_number_masked", "type", "subtype", "currency", "holder_type", "holders_count", "is_joint", "is_business"); + + private Account(ObjectNode json, Map> files) { + super(json, files); + } + + /** + * Reads a {@code Account} from JSON. Unknown fields are kept and readable + * through {@link #_additionalProperties()}. + * + * @param json a JSON object + * @return the parsed value + */ + public static Account fromJson(JsonNode json) { + return new Account(Json.copyObject(json), Map.of()); + } + + /** + * Returns an empty builder. + * + * @return a new builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Returns a builder holding a copy of every field of this value. + * + * @return a new builder + */ + public Builder toBuilder() { + return new Builder(this); + } + + /** + * The account number, masked. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional accountIdMasked() { + return Json.optional(json, "account_id_masked", Conv.STRING); + } + + /** + * The IBAN, masked. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional ibanMasked() { + return Json.optional(json, "iban_masked", Conv.STRING); + } + + /** + * The sort code, in the United Kingdom. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional sortCode() { + return Json.optional(json, "sort_code", Conv.STRING); + } + + /** + * The routing number, masked. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional routingNumberMasked() { + return Json.optional(json, "routing_number_masked", Conv.STRING); + } + + /** + * The type field. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional type() { + return Json.optional(json, "type", Conv.enumeration(BankVerificationResult.Account.Type::of)); + } + + /** + * The bank's own account subtype. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional subtype() { + return Json.optional(json, "subtype", Conv.STRING); + } + + /** + * ISO 4217 currency of the account. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional currency() { + return Json.optional(json, "currency", Conv.STRING); + } + + /** + * The holder_type field. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional holderType() { + return Json.optional(json, "holder_type", Conv.enumeration(BankVerificationResult.Account.HolderType::of)); + } + + /** + * The holders_count field. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional holdersCount() { + return Json.optional(json, "holders_count", Conv.LONG); + } + + /** + * The is_joint field. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional isJoint() { + return Json.optional(json, "is_joint", Conv.BOOLEAN); + } + + /** + * The is_business field. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional isBusiness() { + return Json.optional(json, "is_business", Conv.BOOLEAN); + } + + @Override + protected Set knownFields() { + return KNOWN_FIELDS; + } + + /** Builds a {@link Account}. */ + public static final class Builder extends JsonModel.BaseBuilder { + private Builder() {} + + private Builder(Account from) { + super(from); + } + + /** + * The account number, masked. + * + * @param accountIdMasked the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder accountIdMasked(@Nullable String accountIdMasked) { + return setNullable("account_id_masked", Conv.STRING, accountIdMasked); + } + + /** + * The IBAN, masked. + * + * @param ibanMasked the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder ibanMasked(@Nullable String ibanMasked) { + return setNullable("iban_masked", Conv.STRING, ibanMasked); + } + + /** + * The sort code, in the United Kingdom. + * + * @param sortCode the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder sortCode(@Nullable String sortCode) { + return setNullable("sort_code", Conv.STRING, sortCode); + } + + /** + * The routing number, masked. + * + * @param routingNumberMasked the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder routingNumberMasked(@Nullable String routingNumberMasked) { + return setNullable("routing_number_masked", Conv.STRING, routingNumberMasked); + } + + /** + * The type field. + * + * @param type the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder type(BankVerificationResult.Account.@Nullable Type type) { + return setNullable("type", Conv.enumeration(BankVerificationResult.Account.Type::of), type); + } + + /** + * The bank's own account subtype. + * + * @param subtype the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder subtype(@Nullable String subtype) { + return setNullable("subtype", Conv.STRING, subtype); + } + + /** + * ISO 4217 currency of the account. + * + * @param currency the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder currency(@Nullable String currency) { + return setNullable("currency", Conv.STRING, currency); + } + + /** + * The holder_type field. + * + * @param holderType the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder holderType(BankVerificationResult.Account.@Nullable HolderType holderType) { + return setNullable("holder_type", Conv.enumeration(BankVerificationResult.Account.HolderType::of), holderType); + } + + /** + * The holders_count field. + * + * @param holdersCount the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder holdersCount(@Nullable Long holdersCount) { + return setNullable("holders_count", Conv.LONG, holdersCount); + } + + /** + * The is_joint field. + * + * @param isJoint the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder isJoint(@Nullable Boolean isJoint) { + return setNullable("is_joint", Conv.BOOLEAN, isJoint); + } + + /** + * The is_business field. + * + * @param isBusiness the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder isBusiness(@Nullable Boolean isBusiness) { + return setNullable("is_business", Conv.BOOLEAN, isBusiness); + } + + /** + * Builds the value. + * + * @return a new immutable {@code Account} + */ + public Account build() { + return new Account(buildJson(), buildFiles()); + } + + @Override + protected Builder self() { + return this; + } + } + + /** + * + *

An open enum: {@link #of(String)} accepts values this SDK version does not know yet. + */ + public static final class Type extends StringEnum { + /** The value {@code "checking"}. */ + public static final Type CHECKING = new Type("checking"); + + /** The value {@code "current"}. */ + public static final Type CURRENT = new Type("current"); + + /** The value {@code "savings"}. */ + public static final Type SAVINGS = new Type("savings"); + + /** The value {@code "business"}. */ + public static final Type BUSINESS = new Type("business"); + + /** The value {@code "other"}. */ + public static final Type OTHER = new Type("other"); + + private static final List KNOWN_VALUES = List.of(CHECKING, CURRENT, SAVINGS, BUSINESS, OTHER); + + private Type(String value) { + super(value); + } + + /** + * Returns the constant for a known value, or a new instance for any other value. + * + * @param value the string value + * @return the enum value + */ + public static Type of(String value) { + return StringEnum.lookup(KNOWN_VALUES, value, Type::new); + } + + /** + * Returns the values known to this SDK version. + * + * @return the known values + */ + public static List knownValues() { + return KNOWN_VALUES; + } + + @Override + public boolean isKnown() { + return KNOWN_VALUES.contains(this); + } + } + + /** + * + *

An open enum: {@link #of(String)} accepts values this SDK version does not know yet. + */ + public static final class HolderType extends StringEnum { + /** The value {@code "person"}. */ + public static final HolderType PERSON = new HolderType("person"); + + /** The value {@code "business"}. */ + public static final HolderType BUSINESS = new HolderType("business"); + + /** The value {@code "unknown"}. */ + public static final HolderType UNKNOWN = new HolderType("unknown"); + + private static final List KNOWN_VALUES = List.of(PERSON, BUSINESS, UNKNOWN); + + private HolderType(String value) { + super(value); + } + + /** + * Returns the constant for a known value, or a new instance for any other value. + * + * @param value the string value + * @return the enum value + */ + public static HolderType of(String value) { + return StringEnum.lookup(KNOWN_VALUES, value, HolderType::new); + } + + /** + * Returns the values known to this SDK version. + * + * @return the known values + */ + public static List knownValues() { + return KNOWN_VALUES; + } + + @Override + public boolean isKnown() { + return KNOWN_VALUES.contains(this); + } + } + } + + /** + * How the account holder compared with the verified identity. null until an account is evaluated. + */ + public static final class Ownership extends JsonModel { + private static final Set KNOWN_FIELDS = Set.of("result", "reference_identity_source", "name_score", "provider_name_score", "address_score", "email_score", "phone_score", "dob_score", "close_match", "holder_confirmation", "method", "matched_holder_index", "holders", "owner_identity_available", "evidence_freshness", "evaluated_at"); + + private Ownership(ObjectNode json, Map> files) { + super(json, files); + } + + /** + * Reads a {@code Ownership} from JSON. Unknown fields are kept and readable + * through {@link #_additionalProperties()}. + * + * @param json a JSON object + * @return the parsed value + */ + public static Ownership fromJson(JsonNode json) { + return new Ownership(Json.copyObject(json), Map.of()); + } + + /** + * Returns an empty builder. + * + * @return a new builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Returns a builder holding a copy of every field of this value. + * + * @return a new builder + */ + public Builder toBuilder() { + return new Builder(this); + } + + /** + * partial_match is a close match. not_verifiable: the bank answered with no holder to compare. unknown: the evidence could not be read, or there was no identity to compare. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional result() { + return Json.optional(json, "result", Conv.enumeration(BankVerificationResult.Ownership.Result::of)); + } + + /** + * The step whose identity the holder was compared against: kyc, database_validation, expected_details, questionnaire, document_ai or kyb. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional referenceIdentitySource() { + return Json.optional(json, "reference_identity_source", Conv.STRING); + } + + /** + * Didit's holder name score. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional nameScore() { + return Json.optional(json, "name_score", Conv.LONG); + } + + /** + * The bank's own holder name score, when it returned one. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional providerNameScore() { + return Json.optional(json, "provider_name_score", Conv.LONG); + } + + /** + * The holder address score, when address matching ran. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional addressScore() { + return Json.optional(json, "address_score", Conv.LONG); + } + + /** + * The holder email score, when email matching ran. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional emailScore() { + return Json.optional(json, "email_score", Conv.LONG); + } + + /** + * The holder phone score, when phone matching ran. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional phoneScore() { + return Json.optional(json, "phone_score", Conv.LONG); + } + + /** + * The holder date of birth score, when the bank shared one. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional dobScore() { + return Json.optional(json, "dob_score", Conv.LONG); + } + + /** + * Whether the name landed in the close-match band. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional closeMatch() { + return Json.optional(json, "close_match", Conv.BOOLEAN); + } + + /** + * The person's answer when asked to confirm a close-match name. null when never asked. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional holderConfirmation() { + return Json.optional(json, "holder_confirmation", Conv.enumeration(BankVerificationResult.Ownership.HolderConfirmation::of)); + } + + /** + * Which name comparison produced the score. This is not the verification method: read the top-level method for that. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional method() { + return Json.optional(json, "method", Conv.enumeration(BankVerificationResult.Ownership.Method::of)); + } + + /** + * The matched_holder_index field. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional matchedHolderIndex() { + return Json.optional(json, "matched_holder_index", Conv.LONG); + } + + /** + * Each holder the bank listed, with its scores. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional>> holders() { + return Json.optional(json, "holders", Conv.list(Conv.OBJECT)); + } + + /** + * The owner_identity_available field. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional ownerIdentityAvailable() { + return Json.optional(json, "owner_identity_available", Conv.BOOLEAN); + } + + /** + * The evidence_freshness field. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional evidenceFreshness() { + return Json.optional(json, "evidence_freshness", Conv.enumeration(BankVerificationResult.Ownership.EvidenceFreshness::of)); + } + + /** + * When the verdict was computed. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional evaluatedAt() { + return Json.optional(json, "evaluated_at", Conv.DATE_TIME); + } + + @Override + protected Set knownFields() { + return KNOWN_FIELDS; + } + + /** Builds a {@link Ownership}. */ + public static final class Builder extends JsonModel.BaseBuilder { + private Builder() {} + + private Builder(Ownership from) { + super(from); + } + + /** + * partial_match is a close match. not_verifiable: the bank answered with no holder to compare. unknown: the evidence could not be read, or there was no identity to compare. + * + * @param result the value + * @return this builder + */ + public Builder result(BankVerificationResult.Ownership.Result result) { + return set("result", Conv.enumeration(BankVerificationResult.Ownership.Result::of), result); + } + + /** + * The step whose identity the holder was compared against: kyc, database_validation, expected_details, questionnaire, document_ai or kyb. + * + * @param referenceIdentitySource the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder referenceIdentitySource(@Nullable String referenceIdentitySource) { + return setNullable("reference_identity_source", Conv.STRING, referenceIdentitySource); + } + + /** + * Didit's holder name score. + * + * @param nameScore the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder nameScore(@Nullable Long nameScore) { + return setNullable("name_score", Conv.LONG, nameScore); + } + + /** + * The bank's own holder name score, when it returned one. + * + * @param providerNameScore the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder providerNameScore(@Nullable Long providerNameScore) { + return setNullable("provider_name_score", Conv.LONG, providerNameScore); + } + + /** + * The holder address score, when address matching ran. + * + * @param addressScore the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder addressScore(@Nullable Long addressScore) { + return setNullable("address_score", Conv.LONG, addressScore); + } + + /** + * The holder email score, when email matching ran. + * + * @param emailScore the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder emailScore(@Nullable Long emailScore) { + return setNullable("email_score", Conv.LONG, emailScore); + } + + /** + * The holder phone score, when phone matching ran. + * + * @param phoneScore the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder phoneScore(@Nullable Long phoneScore) { + return setNullable("phone_score", Conv.LONG, phoneScore); + } + + /** + * The holder date of birth score, when the bank shared one. + * + * @param dobScore the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder dobScore(@Nullable Long dobScore) { + return setNullable("dob_score", Conv.LONG, dobScore); + } + + /** + * Whether the name landed in the close-match band. + * + * @param closeMatch the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder closeMatch(@Nullable Boolean closeMatch) { + return setNullable("close_match", Conv.BOOLEAN, closeMatch); + } + + /** + * The person's answer when asked to confirm a close-match name. null when never asked. + * + * @param holderConfirmation the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder holderConfirmation(BankVerificationResult.Ownership.@Nullable HolderConfirmation holderConfirmation) { + return setNullable("holder_confirmation", Conv.enumeration(BankVerificationResult.Ownership.HolderConfirmation::of), holderConfirmation); + } + + /** + * Which name comparison produced the score. This is not the verification method: read the top-level method for that. + * + * @param method the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder method(BankVerificationResult.Ownership.@Nullable Method method) { + return setNullable("method", Conv.enumeration(BankVerificationResult.Ownership.Method::of), method); + } + + /** + * The matched_holder_index field. + * + * @param matchedHolderIndex the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder matchedHolderIndex(@Nullable Long matchedHolderIndex) { + return setNullable("matched_holder_index", Conv.LONG, matchedHolderIndex); + } + + /** + * Each holder the bank listed, with its scores. + * + * @param holders the value + * @return this builder + */ + public Builder holders(List> holders) { + return setAny("holders", holders); + } + + /** + * The owner_identity_available field. + * + * @param ownerIdentityAvailable the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder ownerIdentityAvailable(@Nullable Boolean ownerIdentityAvailable) { + return setNullable("owner_identity_available", Conv.BOOLEAN, ownerIdentityAvailable); + } + + /** + * The evidence_freshness field. + * + * @param evidenceFreshness the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder evidenceFreshness(BankVerificationResult.Ownership.@Nullable EvidenceFreshness evidenceFreshness) { + return setNullable("evidence_freshness", Conv.enumeration(BankVerificationResult.Ownership.EvidenceFreshness::of), evidenceFreshness); + } + + /** + * When the verdict was computed. + * + * @param evaluatedAt the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder evaluatedAt(@Nullable OffsetDateTime evaluatedAt) { + return setNullable("evaluated_at", Conv.DATE_TIME, evaluatedAt); + } + + /** + * Builds the value. + * + * @return a new immutable {@code Ownership} + */ + public Ownership build() { + return new Ownership(buildJson(), buildFiles()); + } + + @Override + protected Builder self() { + return this; + } + } + + /** + * partial_match is a close match. not_verifiable: the bank answered with no holder to compare. unknown: the evidence could not be read, or there was no identity to compare. + * + *

An open enum: {@link #of(String)} accepts values this SDK version does not know yet. + */ + public static final class Result extends StringEnum { + /** The value {@code "match"}. */ + public static final Result MATCH = new Result("match"); + + /** The value {@code "partial_match"}. */ + public static final Result PARTIAL_MATCH = new Result("partial_match"); + + /** The value {@code "no_match"}. */ + public static final Result NO_MATCH = new Result("no_match"); + + /** The value {@code "unknown"}. */ + public static final Result UNKNOWN = new Result("unknown"); + + /** The value {@code "not_verifiable"}. */ + public static final Result NOT_VERIFIABLE = new Result("not_verifiable"); + + private static final List KNOWN_VALUES = List.of(MATCH, PARTIAL_MATCH, NO_MATCH, UNKNOWN, NOT_VERIFIABLE); + + private Result(String value) { + super(value); + } + + /** + * Returns the constant for a known value, or a new instance for any other value. + * + * @param value the string value + * @return the enum value + */ + public static Result of(String value) { + return StringEnum.lookup(KNOWN_VALUES, value, Result::new); + } + + /** + * Returns the values known to this SDK version. + * + * @return the known values + */ + public static List knownValues() { + return KNOWN_VALUES; + } + + @Override + public boolean isKnown() { + return KNOWN_VALUES.contains(this); + } + } + + /** + * The person's answer when asked to confirm a close-match name. null when never asked. + * + *

An open enum: {@link #of(String)} accepts values this SDK version does not know yet. + */ + public static final class HolderConfirmation extends StringEnum { + /** The value {@code "pending"}. */ + public static final HolderConfirmation PENDING = new HolderConfirmation("pending"); + + /** The value {@code "confirmed"}. */ + public static final HolderConfirmation CONFIRMED = new HolderConfirmation("confirmed"); + + /** The value {@code "rejected"}. */ + public static final HolderConfirmation REJECTED = new HolderConfirmation("rejected"); + + private static final List KNOWN_VALUES = List.of(PENDING, CONFIRMED, REJECTED); + + private HolderConfirmation(String value) { + super(value); + } + + /** + * Returns the constant for a known value, or a new instance for any other value. + * + * @param value the string value + * @return the enum value + */ + public static HolderConfirmation of(String value) { + return StringEnum.lookup(KNOWN_VALUES, value, HolderConfirmation::new); + } + + /** + * Returns the values known to this SDK version. + * + * @return the known values + */ + public static List knownValues() { + return KNOWN_VALUES; + } + + @Override + public boolean isKnown() { + return KNOWN_VALUES.contains(this); + } + } + + /** + * Which name comparison produced the score. This is not the verification method: read the top-level method for that. + * + *

An open enum: {@link #of(String)} accepts values this SDK version does not know yet. + */ + public static final class Method extends StringEnum { + /** The value {@code "exact"}. */ + public static final Method EXACT = new Method("exact"); + + /** The value {@code "token_set"}. */ + public static final Method TOKEN_SET = new Method("token_set"); + + /** The value {@code "nickname"}. */ + public static final Method NICKNAME = new Method("nickname"); + + /** The value {@code "transliteration"}. */ + public static final Method TRANSLITERATION = new Method("transliteration"); + + /** The value {@code "fuzzy"}. */ + public static final Method FUZZY = new Method("fuzzy"); + + /** The value {@code "provider_only"}. */ + public static final Method PROVIDER_ONLY = new Method("provider_only"); + + /** The value {@code "microdeposits"}. */ + public static final Method MICRODEPOSITS = new Method("microdeposits"); + + private static final List KNOWN_VALUES = List.of(EXACT, TOKEN_SET, NICKNAME, TRANSLITERATION, FUZZY, PROVIDER_ONLY, MICRODEPOSITS); + + private Method(String value) { + super(value); + } + + /** + * Returns the constant for a known value, or a new instance for any other value. + * + * @param value the string value + * @return the enum value + */ + public static Method of(String value) { + return StringEnum.lookup(KNOWN_VALUES, value, Method::new); + } + + /** + * Returns the values known to this SDK version. + * + * @return the known values + */ + public static List knownValues() { + return KNOWN_VALUES; + } + + @Override + public boolean isKnown() { + return KNOWN_VALUES.contains(this); + } + } + + /** + * + *

An open enum: {@link #of(String)} accepts values this SDK version does not know yet. + */ + public static final class EvidenceFreshness extends StringEnum { + /** The value {@code "live"}. */ + public static final EvidenceFreshness LIVE = new EvidenceFreshness("live"); + + /** The value {@code "cached"}. */ + public static final EvidenceFreshness CACHED = new EvidenceFreshness("cached"); + + /** The value {@code "refreshed"}. */ + public static final EvidenceFreshness REFRESHED = new EvidenceFreshness("refreshed"); + + private static final List KNOWN_VALUES = List.of(LIVE, CACHED, REFRESHED); + + private EvidenceFreshness(String value) { + super(value); + } + + /** + * Returns the constant for a known value, or a new instance for any other value. + * + * @param value the string value + * @return the enum value + */ + public static EvidenceFreshness of(String value) { + return StringEnum.lookup(KNOWN_VALUES, value, EvidenceFreshness::new); + } + + /** + * Returns the values known to this SDK version. + * + * @return the known values + */ + public static List knownValues() { + return KNOWN_VALUES; + } + + @Override + public boolean isKnown() { + return KNOWN_VALUES.contains(this); + } + } + } + + /** The financial data the step read. Only bank sign-in reads it. */ + public static final class FinancialData extends JsonModel { + private static final Set KNOWN_FIELDS = Set.of("balances", "transactions", "income", "categorization", "not_collected"); + + private FinancialData(ObjectNode json, Map> files) { + super(json, files); + } + + /** + * Reads a {@code FinancialData} from JSON. Unknown fields are kept and readable + * through {@link #_additionalProperties()}. + * + * @param json a JSON object + * @return the parsed value + */ + public static FinancialData fromJson(JsonNode json) { + return new FinancialData(Json.copyObject(json), Map.of()); + } + + /** + * Returns an empty builder. + * + * @return a new builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Returns a builder holding a copy of every field of this value. + * + * @return a new builder + */ + public Builder toBuilder() { + return new Builder(this); + } + + /** + * With the balances scope. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional> balances() { + return Json.optional(json, "balances", Conv.OBJECT); + } + + /** + * With the transactions scope. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional> transactions() { + return Json.optional(json, "transactions", Conv.OBJECT); + } + + /** + * With the income scope. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional> income() { + return Json.optional(json, "income", Conv.OBJECT); + } + + /** + * Didit's categorization of the transactions read. null without them. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional> categorization() { + return Json.optional(json, "categorization", Conv.OBJECT); + } + + /** + * The data the step asked for that the method which verified the account does not collect. Balances, transactions and income come from bank sign-in only, so an account verified by account check lists them here. Never a failure. Empty otherwise. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional> notCollected() { + return Json.optional(json, "not_collected", Conv.list(Conv.enumeration(BankVerificationResult.FinancialData.NotCollected::of))); + } + + @Override + protected Set knownFields() { + return KNOWN_FIELDS; + } + + /** Builds a {@link FinancialData}. */ + public static final class Builder extends JsonModel.BaseBuilder { + private Builder() {} + + private Builder(FinancialData from) { + super(from); + } + + /** + * With the balances scope. + * + * @param balances the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder balances(@Nullable Map balances) { + return setAny("balances", balances); + } + + /** + * With the transactions scope. + * + * @param transactions the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder transactions(@Nullable Map transactions) { + return setAny("transactions", transactions); + } + + /** + * With the income scope. + * + * @param income the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder income(@Nullable Map income) { + return setAny("income", income); + } + + /** + * Didit's categorization of the transactions read. null without them. + * + * @param categorization the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder categorization(@Nullable Map categorization) { + return setAny("categorization", categorization); + } + + /** + * The data the step asked for that the method which verified the account does not collect. Balances, transactions and income come from bank sign-in only, so an account verified by account check lists them here. Never a failure. Empty otherwise. + * + * @param notCollected the value + * @return this builder + */ + public Builder notCollected(List notCollected) { + return set("not_collected", Conv.list(Conv.enumeration(BankVerificationResult.FinancialData.NotCollected::of)), notCollected); + } + + /** + * Builds the value. + * + * @return a new immutable {@code FinancialData} + */ + public FinancialData build() { + return new FinancialData(buildJson(), buildFiles()); + } + + @Override + protected Builder self() { + return this; + } + } + + /** + * + *

An open enum: {@link #of(String)} accepts values this SDK version does not know yet. + */ + public static final class NotCollected extends StringEnum { + /** The value {@code "balances"}. */ + public static final NotCollected BALANCES = new NotCollected("balances"); + + /** The value {@code "income"}. */ + public static final NotCollected INCOME = new NotCollected("income"); + + /** The value {@code "transactions"}. */ + public static final NotCollected TRANSACTIONS = new NotCollected("transactions"); + + private static final List KNOWN_VALUES = List.of(BALANCES, INCOME, TRANSACTIONS); + + private NotCollected(String value) { + super(value); + } + + /** + * Returns the constant for a known value, or a new instance for any other value. + * + * @param value the string value + * @return the enum value + */ + public static NotCollected of(String value) { + return StringEnum.lookup(KNOWN_VALUES, value, NotCollected::new); + } + + /** + * Returns the values known to this SDK version. + * + * @return the known values + */ + public static List knownValues() { + return KNOWN_VALUES; + } + + @Override + public boolean isKnown() { + return KNOWN_VALUES.contains(this); + } + } + } + + public static final class Billing extends JsonModel { + private static final Set KNOWN_FIELDS = Set.of("route", "billed", "marketplace_fee", "usage_type"); + + private Billing(ObjectNode json, Map> files) { + super(json, files); + } + + /** + * Reads a {@code Billing} from JSON. Unknown fields are kept and readable + * through {@link #_additionalProperties()}. + * + * @param json a JSON object + * @return the parsed value + */ + public static Billing fromJson(JsonNode json) { + return new Billing(Json.copyObject(json), Map.of()); + } + + /** + * Returns an empty builder. + * + * @return a new builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Returns a builder holding a copy of every field of this value. + * + * @return a new builder + */ + public Builder toBuilder() { + return new Builder(this); + } + + /** + * The route field. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional route() { + return Json.optional(json, "route", Conv.enumeration(BankVerificationResult.Billing.Route::of)); + } + + /** + * The billed field. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional billed() { + return Json.optional(json, "billed", Conv.BOOLEAN); + } + + /** + * The marketplace platform fee charged, for byok. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional marketplaceFee() { + return Json.optional(json, "marketplace_fee", Conv.STRING); + } + + /** + * The usage line the charge was booked on. + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional usageType() { + return Json.optional(json, "usage_type", Conv.STRING); + } + + @Override + protected Set knownFields() { + return KNOWN_FIELDS; + } + + /** Builds a {@link Billing}. */ + public static final class Builder extends JsonModel.BaseBuilder { + private Builder() {} + + private Builder(Billing from) { + super(from); + } + + /** + * The route field. + * + * @param route the value + * @return this builder + */ + public Builder route(BankVerificationResult.Billing.Route route) { + return set("route", Conv.enumeration(BankVerificationResult.Billing.Route::of), route); + } + + /** + * The billed field. + * + * @param billed the value + * @return this builder + */ + public Builder billed(boolean billed) { + return set("billed", Conv.BOOLEAN, billed); + } + + /** + * The marketplace platform fee charged, for byok. + * + * @param marketplaceFee the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder marketplaceFee(@Nullable String marketplaceFee) { + return setNullable("marketplace_fee", Conv.STRING, marketplaceFee); + } + + /** + * The usage line the charge was booked on. + * + * @param usageType the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder usageType(@Nullable String usageType) { + return setNullable("usage_type", Conv.STRING, usageType); + } + + /** + * Builds the value. + * + * @return a new immutable {@code Billing} + */ + public Billing build() { + return new Billing(buildJson(), buildFiles()); + } + + @Override + protected Builder self() { + return this; + } + } + + /** + * + *

An open enum: {@link #of(String)} accepts values this SDK version does not know yet. + */ + public static final class Route extends StringEnum { + /** The value {@code "native"}. */ + public static final Route NATIVE = new Route("native"); + + /** The value {@code "byok"}. */ + public static final Route BYOK = new Route("byok"); + + private static final List KNOWN_VALUES = List.of(NATIVE, BYOK); + + private Route(String value) { + super(value); + } + + /** + * Returns the constant for a known value, or a new instance for any other value. + * + * @param value the string value + * @return the enum value + */ + public static Route of(String value) { + return StringEnum.lookup(KNOWN_VALUES, value, Route::new); + } + + /** + * Returns the values known to this SDK version. + * + * @return the known values + */ + public static List knownValues() { + return KNOWN_VALUES; + } + + @Override + public boolean isKnown() { + return KNOWN_VALUES.contains(this); + } + } + } +} diff --git a/src/main/java/me/didit/types/SessionDecision.java b/src/main/java/me/didit/types/SessionDecision.java index d19d2e0..1026d68 100644 --- a/src/main/java/me/didit/types/SessionDecision.java +++ b/src/main/java/me/didit/types/SessionDecision.java @@ -17,7 +17,7 @@ import org.jspecify.annotations.Nullable; public final class SessionDecision extends JsonModel { - private static final Set KNOWN_FIELDS = Set.of("session_id", "session_kind", "shared_from_session", "session_number", "session_url", "status", "workflow_id", "features", "vendor_data", "metadata", "expected_details", "contact_details", "callback", "id_verifications", "nfc_skip_reason", "nfc_verifications", "liveness_checks", "face_matches", "phone_verifications", "email_verifications", "poa_verifications", "document_ai_documents", "questionnaire_responses", "signatures", "aml_screenings", "ip_analyses", "database_validations", "reviews", "created_at", "expires_at", "registry_checks", "key_people_checks", "document_verifications", "environment", "resubmissions", "investigator"); + private static final Set KNOWN_FIELDS = Set.of("session_id", "session_kind", "shared_from_session", "session_number", "session_url", "status", "workflow_id", "features", "vendor_data", "metadata", "expected_details", "contact_details", "callback", "id_verifications", "nfc_skip_reason", "nfc_verifications", "liveness_checks", "face_matches", "phone_verifications", "email_verifications", "poa_verifications", "document_ai_documents", "questionnaire_responses", "bank_verifications", "signatures", "aml_screenings", "ip_analyses", "database_validations", "reviews", "created_at", "expires_at", "registry_checks", "key_people_checks", "document_verifications", "environment", "resubmissions", "investigator"); private SessionDecision(ObjectNode json, Map> files) { super(json, files); @@ -282,6 +282,16 @@ public Optional> questionnaireRespo return Json.optional(json, "questionnaire_responses", Conv.list(Conv.model(SessionDecision.QuestionnaireResponses::fromJson))); } + /** + * 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). + * + * @return the value, or empty when the field is absent or null + * @throws me.didit.errors.UnexpectedResponseException when the field has another type + */ + public Optional> bankVerifications() { + return Json.optional(json, "bank_verifications", Conv.list(Conv.model(BankVerificationResult::fromJson))); + } + /** * Electronic Signature results, one item per signer and signature step, for User and Business Verification. Present only when the workflow has an Electronic Signature step; an empty array until a signer reaches it. See the [Electronic Signature report](/core-technology/electronic-signature/report-electronic-signature). * @@ -691,6 +701,16 @@ public Builder questionnaireResponses(@Nullable Listnull 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). + * + * @param bankVerifications the value, or {@code null} to send JSON null + * @return this builder + */ + public Builder bankVerifications(@Nullable List bankVerifications) { + return setNullable("bank_verifications", Conv.list(Conv.model(BankVerificationResult::fromJson)), bankVerifications); + } + /** * Electronic Signature results, one item per signer and signature step, for User and Business Verification. Present only when the workflow has an Electronic Signature step; an empty array until a signer reaches it. See the [Electronic Signature report](/core-technology/electronic-signature/report-electronic-signature). * diff --git a/src/test/java/me/didit/resources/BankResourceTest.java b/src/test/java/me/didit/resources/BankResourceTest.java new file mode 100644 index 0000000..5bc8bdb --- /dev/null +++ b/src/test/java/me/didit/resources/BankResourceTest.java @@ -0,0 +1,44 @@ +// Code generated by codegen from openapi/*.json. DO NOT EDIT. +package me.didit.resources; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.fasterxml.jackson.databind.JsonNode; +import java.util.List; +import java.util.Map; +import me.didit.Didit; +import me.didit.core.Json; +import me.didit.testing.MockTransport; +import me.didit.testing.RecordedRequest; +import me.didit.testing.SpecExamples; +import me.didit.testing.TestJson; +import me.didit.testing.TestModels; +import me.didit.types.BankAccountCheckHolder; +import me.didit.types.BankAccountCheckPersonHolder; +import me.didit.types.BankAccountCheckRequest; +import org.junit.jupiter.api.Test; + +/** One test per operation of {@code bank}, against a stubbed HTTP layer. */ +@SuppressWarnings({"deprecation", "unused"}) +final class BankResourceTest { + private final MockTransport transport = new MockTransport(); + private final Didit client = transport.client(); + + @Test + void accountCheck() { + BankAccountCheckRequest params = BankAccountCheckRequest.builder().country("value-country").account(BankAccountCheckRequest.Account.builder().iban("value-iban").accountNumber("value-account-number").build()).holder(BankAccountCheckHolder.ofBankAccountCheckPersonHolder(BankAccountCheckPersonHolder.builder().fullName("value-full-name").build())).vendorData("value-vendor-data").build(); + JsonNode example = SpecExamples.response("verification.json", "POST", "/v3/bank/account-check/", "200"); + transport.respondJson(200, example); + var result = client.bank().accountCheck(params); + RecordedRequest request = transport.only(); + assertEquals("POST", request.method()); + assertEquals("/v3/bank/account-check/", request.path()); + assertEquals(Map.of(), request.query()); + assertEquals("test-api-key", request.header("x-api-key")); + assertEquals("https://verification.didit.me", request.origin()); + TestJson.assertJsonEquals("{\"country\":\"value-country\",\"account\":{\"iban\":\"value-iban\",\"account_number\":\"value-account-number\"},\"holder\":{\"full_name\":\"value-full-name\"},\"vendor_data\":\"value-vendor-data\"}", request.body()); + TestJson.assertJsonEquals(example, Json.toNode(result)); + TestModels.readAll(result); + } +} From 0bf57b3e8adaaab6c7fb58b325ca20744a32fb71 Mon Sep 17 00:00:00 2001 From: Alejandro Rosas Date: Sat, 24 Oct 2026 02:38:17 +0400 Subject: [PATCH 2/2] ci: start checks on the spec sync Co-Authored-By: Claude Sonnet 5.5