> Toden documentation. For the full index fetch /llms.txt. Every page is available as Markdown by appending .md to its URL. Identity verification uses /api/kyc, Risk Intelligence uses /api/v1; they are separate contracts with different error shapes. Never invent an endpoint, field or enum value: read the API reference page for the operation first.

# Create a verification

POST https://sandbox-api.toden.co/api/kyc/verify
Content-Type: application/json

Submits an identity for verification and returns at once. The checks run asynchronously: receive the outcome by webhook, or poll the status endpoint.

A `202` means a new verification was created. A `200` with the same body shape means `metadata.requestId` matched an earlier submission and that verification is returned instead; nothing new is created or charged.

An accepted submission can still end declined or in error later (an ID not found, a face mismatch, insufficient credit). Those outcomes arrive on the status endpoint and webhooks with a `reason` and `reasonCode`, never as an HTTP error here.

Send the `business` block for a business verification, or `idChecks` for a workflow that verifies several IDs. Both require a published workflow. A hosted verification session token is also accepted in place of an API key.

**Error codes**

| `error` | Status | Meaning |
|---|---|---|
| `Invalid request body` | 400 | The body failed validation. `details` lists each problem. |
| `invalid_sandbox_outcome` | 400 | `metadata.sandboxOutcome` is not a known test outcome. |
| `invalid_media` | 400 | An uploaded file is unknown, expired or already used. `mediaKey` names it when known. |
| `country_mismatch` | 400 | The country is not offered by the business or scoped workflow. |
| `country_not_supported` | 400 | The country is not accepted by the address workflow. |
| `product_unsupported` | 400 | The business product is not offered by the workflow for that country. |
| `Forbidden` | 403 | The `requestId` belongs to another organisation or environment. |
| `mobile_device_required` | 403 | The workflow only runs on a mobile device. |
| `business_verifications_disabled` | 403 | Business verification is switched off for the organisation. |
| `workflow_not_found` | 404 | A business or scoped submission named no published workflow of the right kind. |
| `request_id_conflict` | 409 | The `requestId` was already used for a different verification. |
| `session_cancelled` | 409 | The session named in `sessionId` has been cancelled. |
| `session_unavailable` | 409 | The session has closed and its workflow refuses late submissions. |
| `applicant_session_required` | 409 | An applicant identity submission must resume its business application. |
| `verification_in_progress` | 409 | A resubmission for this verification is still being checked. |
| `resubmission_superseded` | 409 | The verification has already been resubmitted. |
| `resubmission_withdrawn` | 409 | The resubmission link is no longer in use. |
| `handoff_session_used` | 409 | The hosted session has already been submitted. |
| `only_test_ids_allowed` | 422 | A sandbox key was used with a number that is not a published test ID. |
| `workflow_subject_mismatch` | 422 | The submission kind does not match the workflow. |
| `questionnaire_invalid` | 422 | Questionnaire answers failed validation. `issues` lists them. |
| `contact_verification_required` | 422 | A required email or phone proof is missing. `missing` lists which. |
| `missing_supporting_documents` | 422 | A required supporting document is missing. `missing` lists which. |
| `address_collection_required` | 422 | The workflow requires an address pin. |
| `proof_of_address_required` | 422 | The address workflow requires a proof-of-address document. |
| `missing_address_fields` | 422 | Required address fields are missing. `missing` lists which. |
| `invalid_id_checks` | 422 | `idChecks` does not fit the workflow multiple-ID plan. |
| `multi_id_required` | 422 | The workflow verifies several IDs and `idChecks` was not sent. |
| `registration_name_required` | 422 | The business workflow requires the registered name. |
| `missing_documents` | 422 | A required company document is missing. |
| `missing_company_info` | 422 | Required company details are missing. |
| `key_people_required` | 422 | Too few key people were declared. |
| `key_person_email_required` | 422 | A key person who must be invited has no email address. |
| `user_reference_required` | 422 | A biometric submission did not name its subject. |
| `selfie_required` | 422 | A biometric submission carried no selfie. |
| `questionnaire_required` | 422 | A questionnaire submission carried no answers. |
| `not_enrolled` | 422 | The subject has no biometric enrolment to authenticate against. |
| `rate_limited` | 429 | The hourly verification limit for the organisation was reached. |
| `pricing_not_configured` | 500 | No price is configured for this check. Contact support. |
| `Missing or invalid Authorization header` | 401 | No bearer credential was sent. |
| `Invalid API key` | 401 | The key is unknown or revoked. |
| `environment_mismatch` | 403 | The key belongs to an environment this host does not serve. |
| `origin_not_allowed` | 403 | The request origin is not on the publishable key allowlist. |
| `ip_not_allowed` | 403 | The caller address is not on the secret key allowlist. |
| `organization_suspended` | 403 | The organisation is suspended. |
| `business_not_approved` | 403 | A production key was used before the business was approved. |

Accepts a publishable (`pk_`) or secret (`sk_`) key.

Reference: https://docs.toden.co/api-reference/verification/verifications/create-verification

## Authentication

- `Authorization` header (bearer token, required) — Send the API key as a Bearer token. Each operation states whether a publishable key is enough or a secret key is required.

## Servers

- `https://sandbox-api.toden.co` (Sandbox, default)
- `https://api.toden.co` (Production)

## Request

### Body (application/json)

This endpoint expects a VerifyRequest.

- `country` (string, required) — ISO 3166 alpha-2 country code of the ID.
- `idType` (string, required) — The ID type, for example `bvn` or `passport`. For a business submission, send the lookup product here.
- `metadata` (VerifyMetadata, required) — Request metadata. Any key other than those listed is stored as your own customer metadata and echoed on responses and webhooks.
- `idNumber` (string, optional) — The ID number. Required for number-based ID types and omitted for document-only flows.
- `userData` (VerifyRequestUserData, optional) — Applicant details to compare with the record.
- `mediaIds` (VerifyRequestMediaIds, optional) — References to files uploaded with the upload endpoint.
- `idChecks` (list of VerifyIdCheck, optional) — Two or three ID checks for a workflow that verifies several IDs in one run. The first entry is the primary.
- `business` (VerifyBusiness, optional) — Present for a business verification. Requires a published business workflow.
- `workflowId` (string, optional) — The published workflow that configured this submission. Ignored when unknown, except for business and scoped submissions, which require it.
- `sessionId` (string, optional) — The session this submission belongs to. The verification takes the same identifier.
- `externalUserId` (string, optional) — Your own stable reference for the person or business being verified.
- `livenessMode` (enum, optional) — The liveness method the client ran. A workflow setting takes precedence.
  - Allowed values: `gestures`, `flash`, `both`, `passive`
- `proofOfAddressType` (enum, optional) — What kind of document `mediaIds.proofOfAddress` is.
  - Allowed values: `utility_bill`, `bank_statement`, `tenancy_agreement`, `government_document`, `other`
- `nfc` (VerifyNfcPayload, optional) — Data read from the chip of an electronic passport or identity card. Dropped without error when the document has no verifiable chip or the workflow does not run the chip step.
- `address` (VerifyAddress, optional) — The applicant address pin collected on the address step. Dropped without error when the workflow does not collect an address.
- `supportingDocuments` (list of VerifyRequestSupportingDocumentsItems, optional) — Supporting documents the workflow asks the applicant to provide. Documents the workflow did not ask for are dropped.
- `contact` (VerifyRequestContact, optional) — Proofs that the applicant confirmed their contact details.
- `questionnaire` (map from string to VerifyRequestQuestionnaire, optional) — Answers to the workflow questionnaire, keyed by question key.
- `userId` (string, optional, deprecated) — Legacy alias of `externalUserId`.

## Response

### 200

An earlier submission with the same `requestId` was returned.

- `verificationId` (string, required) — The verification identifier.
- `status` (string, required) — `processing` for a new submission. On a repeated `requestId` this is the existing verification check result: `pending`, `verified`, `failed`, `not_found` or `error`.
- `externalUserId` (string, required, nullable) — Your reference for the subject, as stored.
- `metadata` (map from string to any, required, nullable) — Your customer metadata, as stored. Bounded: at most 16 KiB, four levels deep and 100 keys.
- `applicantKeyPersonId` (string, optional, nullable) — Business submissions only. The reference to send as `userId` on the applicant identity submission that follows, or null when the workflow does not verify the applicant.
- `keyPeopleInvites` (list of VerifyAcceptedKeyPeopleInvitesItems, optional) — Business submissions only. Verification links for the key people the applicant listed.

### 202

The verification was created and queued.

- `verificationId` (string, required) — The verification identifier.
- `status` (string, required) — `processing` for a new submission. On a repeated `requestId` this is the existing verification check result: `pending`, `verified`, `failed`, `not_found` or `error`.
- `externalUserId` (string, required, nullable) — Your reference for the subject, as stored.
- `metadata` (map from string to any, required, nullable) — Your customer metadata, as stored. Bounded: at most 16 KiB, four levels deep and 100 keys.
- `applicantKeyPersonId` (string, optional, nullable) — Business submissions only. The reference to send as `userId` on the applicant identity submission that follows, or null when the workflow does not verify the applicant.
- `keyPeopleInvites` (list of VerifyAcceptedKeyPeopleInvitesItems, optional) — Business submissions only. Verification links for the key people the applicant listed.

## Errors

### 400 Bad Request Error

The request body, query or path was invalid.

- `error` (string, required) — A stable machine-readable code such as `invalid_input`. Authentication failures (401) carry a short sentence here instead of a code.
- `message` (string, optional) — A human-readable explanation, safe to log. The wording may change.

### 401 Unauthorized Error

The Authorization header is missing, or the API key is unknown or revoked.

- `error` (string, required) — A stable machine-readable code such as `invalid_input`. Authentication failures (401) carry a short sentence here instead of a code.
- `message` (string, optional) — A human-readable explanation, safe to log. The wording may change.

### 403 Forbidden Error

The key may not call this endpoint, or the organisation may not use this feature.

- `error` (string, required) — A stable machine-readable code such as `invalid_input`. Authentication failures (401) carry a short sentence here instead of a code.
- `message` (string, optional) — A human-readable explanation, safe to log. The wording may change.

### 404 Not Found Error

The resource does not exist for this organisation and environment.

- `error` (string, required) — A stable machine-readable code such as `invalid_input`. Authentication failures (401) carry a short sentence here instead of a code.
- `message` (string, optional) — A human-readable explanation, safe to log. The wording may change.

### 409 Conflict Error

The request conflicts with the current state of the resource.

- `error` (string, required) — A stable machine-readable code such as `invalid_input`. Authentication failures (401) carry a short sentence here instead of a code.
- `message` (string, optional) — A human-readable explanation, safe to log. The wording may change.

### 422 Unprocessable Entity Error

The request was understood but cannot be processed as sent.

- `error` (string, required) — A stable machine-readable code such as `invalid_input`. Authentication failures (401) carry a short sentence here instead of a code.
- `message` (string, optional) — A human-readable explanation, safe to log. The wording may change.

### 429 Too Many Requests Error

A rate limit was reached. Retry after a short wait.

- `error` (string, required) — A stable machine-readable code such as `invalid_input`. Authentication failures (401) carry a short sentence here instead of a code.
- `message` (string, optional) — A human-readable explanation, safe to log. The wording may change.

### 500 Internal Server Error

An unexpected error occurred.

- `error` (string, required) — A stable machine-readable code such as `invalid_input`. Authentication failures (401) carry a short sentence here instead of a code.
- `message` (string, optional) — A human-readable explanation, safe to log. The wording may change.

## Types

### VerifyMetadata

Request metadata. Any key other than those listed is stored as your own customer metadata and echoed on responses and webhooks.

- `requestId` (string, required) — Your unique idempotency key for this submission. Repeating it returns the existing verification.
- `device` (map from string to any, optional) — Free-form device details supplied by the SDK.
- `endUser` (map from string to any, optional) — Your end user connection details (`ipAddress`, `userAgent`, `acceptLanguage`) when you submit from your own server. Honoured for secret keys only.
- `sandboxOutcome` (string, optional) — Forces a named test outcome. Ignored in production. An unknown value is refused with `invalid_sandbox_outcome`.
- `sandboxDelayMs` (integer, optional) — How long the test verification takes to complete, in milliseconds. Ignored in production.
- `userId` (string, optional, deprecated) — Legacy location for your user reference. Prefer the top-level `externalUserId`.

### VerifyRequestUserData

Applicant details to compare with the record.

- `firstName` (string, optional) — Given name.
- `lastName` (string, optional) — Family name.
- `dateOfBirth` (string, optional) — Date of birth.
- `email` (string, optional) — The applicant email address, used only if you ask for the applicant to be emailed about a decision.

### VerifyRequestMediaIds

References to files uploaded with the upload endpoint.

- `documentFront` (string, optional) — The `mediaId` of the uploaded document front image.
- `documentBack` (string, optional) — The `mediaId` of the uploaded document back image.
- `selfie` (string, optional) — The `mediaId` of the uploaded selfie.
- `documentFrontVideo` (string, optional) — The `mediaId` of the uploaded document front capture video.
- `documentBackVideo` (string, optional) — The `mediaId` of the uploaded document back capture video.
- `livenessVideo` (string, optional) — The `mediaId` of the uploaded liveness video.
- `proofOfAddress` (string, optional) — The `mediaId` of the uploaded proof-of-address document.
- `addressPhoto` (string, optional) — The `mediaId` of the uploaded address entrance photo.
- `silentCapture1` (string, optional) — The `mediaId` of the uploaded first unposed applicant photo.
- `silentCapture2` (string, optional) — The `mediaId` of the uploaded second unposed applicant photo.
- `silentCapture3` (string, optional) — The `mediaId` of the uploaded third unposed applicant photo.

### VerifyIdCheck

One identity document in a multiple-ID submission.

- `idType` (string, required) — The ID type for this check.
- `idNumber` (string, optional) — The ID number, for number-based ID types.
- `documentFront` (string, optional) — The `mediaId` of the document front image.
- `documentBack` (string, optional) — The `mediaId` of the document back image.
- `documentFrontVideo` (string, optional) — The `mediaId` of the document front capture video.
- `documentBackVideo` (string, optional) — The `mediaId` of the document back capture video.
- `nfc` (VerifyNfcPayload, optional) — Data read from the chip of an electronic passport or identity card. Dropped without error when the document has no verifiable chip or the workflow does not run the chip step.

### VerifyBusiness

Present for a business verification. Requires a published business workflow.

- `registrationNumber` (string, required) — The business registration number.
- `registrationName` (string, optional) — The registered business name.
- `product` (string, optional) — The lookup product to run. Defaults to the standard business lookup.
- `contactEmail` (string, optional) — A contact address for the business, used to send the key people verification links.
- `address` (string, optional) — The business address as stated by the applicant.
- `email` (string, optional) — The business email address.
- `phone` (string, optional) — The business phone number.
- `website` (string, optional) — The business website.
- `dateOfIncorporation` (string, optional) — The date of incorporation as stated by the applicant.
- `taxId` (string, optional) — The tax identifier as stated by the applicant.
- `vatNumber` (string, optional) — The VAT number as stated by the applicant.
- `companyType` (string, optional) — The company type as stated by the applicant.
- `natureOfBusiness` (string, optional) — What the business does, as stated by the applicant.
- `keyPeople` (list of VerifyBusinessKeyPerson, optional) — The key people the applicant declares.
- `uboUnidentifiable` (boolean, optional) — The applicant attests that no natural person qualifies as a beneficial owner.
- `documents` (list of VerifyBusinessDocumentsItems, optional) — Company documents uploaded during the flow.
- `applicant` (VerifyBusinessApplicant, optional) — The role of the person submitting the application.

### VerifyNfcPayload

Data read from the chip of an electronic passport or identity card. Dropped without error when the document has no verifiable chip or the workflow does not run the chip step.

- `dg1` (string, required) — The DG1 data group, base64 encoded, or the bare machine-readable zone text.
- `sod` (string, optional) — The document security object, base64 encoded, used to authenticate the chip data.
- `dg2` (string, optional) — The DG2 data group (the chip portrait), base64 encoded.
- `dg7` (string, optional) — The DG7 data group (the displayed signature), base64 encoded.
- `dg11` (string, optional) — The DG11 data group (additional personal details), base64 encoded.
- `dg12` (string, optional) — The DG12 data group (additional document details), base64 encoded.
- `dg15` (string, optional) — The DG15 data group (the chip public key), base64 encoded.
- `aaChallengeId` (string, optional) — The identifier of the challenge issued for the chip to sign.
- `aaSignature` (string, optional) — The chip signature over that challenge.
- `chipAuth` (enum, optional) — The access protocol the reader used. Informational only.
  - Allowed values: `bac`, `pace`, `none`
- `paceOutcome` (string, optional) — A short diagnostic of the PACE attempt.
- `paceDetail` (string, optional) — Further diagnostic detail of the PACE attempt.

### VerifyAddress

The applicant address pin collected on the address step. Dropped without error when the workflow does not collect an address.

- `lat` (double, required) — Latitude of the pin.
- `lng` (double, required) — Longitude of the pin.
- `label` (string, optional) — A display line for the address.
- `accuracy` (double, optional) — Reported accuracy of the pin, in metres.
- `directions` (string, optional) — Free-text directions to the address.
- `propertyName` (string, optional) — The building or compound name, as typed by the applicant.
- `propertyNumber` (string, optional) — The house or flat number, as typed by the applicant.
- `street` (string, optional) — The street name, as typed by the applicant.
- `unit` (string, optional) — The unit or apartment, as typed by the applicant.
- `neighbourhood` (string, optional) — The neighbourhood, as typed by the applicant.
- `city` (string, optional) — The city, as typed by the applicant.
- `state` (string, optional) — The state or region, as typed by the applicant.
- `postcode` (string, optional) — The postcode, as typed by the applicant.
- `streetView` (VerifyAddressStreetView, optional) — A street-level view of the entrance, given as view angles. The image itself is fetched by the server.
- `deviceLat` (double, optional) — Latitude of the device when the pin was confirmed.
- `deviceLng` (double, optional) — Longitude of the device when the pin was confirmed.
- `deviceAccuracy` (double, optional) — Reported accuracy of the device fix, in metres.
- `capturedAt` (string, optional) — When the device fix was taken.

### VerifyRequestSupportingDocumentsItems

One supporting document.

- `type` (string, required) — The document key defined on the workflow.
- `mediaId` (string, required) — The `mediaId` of the uploaded document.
- `method` (enum, optional) — How the document was provided, where the workflow lets the applicant draw it: `drawn` for a signature drawn on screen, `uploaded` for a file. Ignored for a document the workflow only accepts as an upload.
  - Allowed values: `drawn`, `uploaded`

### VerifyRequestContact

Proofs that the applicant confirmed their contact details.

- `emailToken` (string, optional) — The single-use proof returned when the email code was checked.
- `phoneToken` (string, optional) — The single-use proof returned when the phone code was checked.

### VerifyRequestQuestionnaire

### VerifyAcceptedKeyPeopleInvitesItems

One verification link.

- `keyPersonId` (string, required) — The key person identifier.
- `name` (string, required) — The person name as entered.
- `inviteUrl` (string, required) — The verification link to send to that person.

### VerifyBusinessKeyPerson

A director, owner, signatory or shareholder the applicant declares. Either `role` or `roles` is required.

- `name` (string, required) — The person or company name.
- `role` (enum, optional) — The single role this party holds.
  - Allowed values: `director`, `beneficial_owner`, `signatory`, `shareholder`
- `roles` (list of enum, optional) — Every role this party holds.
  - Allowed values: `director`, `beneficial_owner`, `signatory`, `shareholder`
- `title` (string, optional) — The party title in the applicant own words, for display only.
- `email` (string, optional) — Where to send this person their verification link.
- `country` (string, optional) — The party country, as an ISO 3166 alpha-2 code.
- `ownershipPct` (double, optional) — Percentage of the business this party owns.
- `votingPct` (double, optional) — Percentage of the voting rights this party holds.
- `isCorporate` (boolean, optional) — True when this party is a company rather than a person.
- `registrationNumber` (string, optional) — The registration number of a corporate party.
- `owners` (list of VerifyBusinessKeyPersonOwnersItems, optional) — The people who own a corporate party, as the applicant knows them. Ignored for a party that is not a company.
- `isApplicant` (boolean, optional) — True when this entry is the person submitting the application.

### VerifyBusinessDocumentsItems

One company document.

- `type` (enum, required) — What the document is.
  - Allowed values: `incorporation_certificate`, `memart`, `proof_of_address`, `tax_document`, `regulatory_license`, `board_resolution`, `other`
- `mediaId` (string, required) — The `mediaId` of the uploaded document.

### VerifyBusinessApplicant

The role of the person submitting the application.

- `role` (enum, required) — The role the applicant holds in the business.
  - Allowed values: `director`, `beneficial_owner`, `signatory`, `shareholder`, `authorized_representative`
- `name` (string, optional) — The applicant name.

### VerifyAddressStreetView

A street-level view of the entrance, given as view angles. The image itself is fetched by the server.

- `panoId` (string, required) — The panorama identifier.
- `heading` (double, required) — Compass heading of the view, in degrees.
- `pitch` (double, required) — Vertical angle of the view, in degrees.
- `fov` (double, required) — Field of view, in degrees.

### VerifyBusinessKeyPersonOwnersItems

One declared owner of a corporate party.

- `name` (string, required) — The owner name.
- `ownershipPct` (double, optional) — Percentage of the corporate party this owner holds.
- `email` (string, optional) — The owner email address.
- `country` (string, optional) — The owner country, as an ISO 3166 alpha-2 code.

## Examples

### Example 1

**Request**

```json
{
  "country": "NG",
  "idType": "bvn",
  "metadata": {
    "requestId": "req_7f3a2c",
    "loanId": "loan_20191"
  },
  "idNumber": "00000000001",
  "userData": {
    "firstName": "Ada",
    "lastName": "Example",
    "dateOfBirth": "1990-01-01"
  },
  "mediaIds": {
    "selfie": "med_01j9x2k4m8"
  },
  "externalUserId": "user_42"
}
```

**Response**

```json
{
  "verificationId": "ver_01j9x2k4m8",
  "status": "processing",
  "externalUserId": "user_42",
  "metadata": {
    "loanId": "loan_20191"
  }
}
```

**SDK Code**

```python
import requests

url = "https://sandbox-api.toden.co/api/kyc/verify"

payload = {
    "country": "NG",
    "idType": "bvn",
    "metadata": {
        "requestId": "req_7f3a2c",
        "loanId": "loan_20191"
    },
    "idNumber": "00000000001",
    "userData": {
        "firstName": "Ada",
        "lastName": "Example",
        "dateOfBirth": "1990-01-01"
    },
    "mediaIds": { "selfie": "med_01j9x2k4m8" },
    "externalUserId": "user_42"
}
headers = {
    "Authorization": "Bearer <apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://sandbox-api.toden.co/api/kyc/verify';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <apiKey>', 'Content-Type': 'application/json'},
  body: '{"country":"NG","idType":"bvn","metadata":{"requestId":"req_7f3a2c","loanId":"loan_20191"},"idNumber":"00000000001","userData":{"firstName":"Ada","lastName":"Example","dateOfBirth":"1990-01-01"},"mediaIds":{"selfie":"med_01j9x2k4m8"},"externalUserId":"user_42"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://sandbox-api.toden.co/api/kyc/verify"

	payload := strings.NewReader("{\n  \"country\": \"NG\",\n  \"idType\": \"bvn\",\n  \"metadata\": {\n    \"requestId\": \"req_7f3a2c\",\n    \"loanId\": \"loan_20191\"\n  },\n  \"idNumber\": \"00000000001\",\n  \"userData\": {\n    \"firstName\": \"Ada\",\n    \"lastName\": \"Example\",\n    \"dateOfBirth\": \"1990-01-01\"\n  },\n  \"mediaIds\": {\n    \"selfie\": \"med_01j9x2k4m8\"\n  },\n  \"externalUserId\": \"user_42\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://sandbox-api.toden.co/api/kyc/verify")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"country\": \"NG\",\n  \"idType\": \"bvn\",\n  \"metadata\": {\n    \"requestId\": \"req_7f3a2c\",\n    \"loanId\": \"loan_20191\"\n  },\n  \"idNumber\": \"00000000001\",\n  \"userData\": {\n    \"firstName\": \"Ada\",\n    \"lastName\": \"Example\",\n    \"dateOfBirth\": \"1990-01-01\"\n  },\n  \"mediaIds\": {\n    \"selfie\": \"med_01j9x2k4m8\"\n  },\n  \"externalUserId\": \"user_42\"\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://sandbox-api.toden.co/api/kyc/verify")
  .header("Authorization", "Bearer <apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"country\": \"NG\",\n  \"idType\": \"bvn\",\n  \"metadata\": {\n    \"requestId\": \"req_7f3a2c\",\n    \"loanId\": \"loan_20191\"\n  },\n  \"idNumber\": \"00000000001\",\n  \"userData\": {\n    \"firstName\": \"Ada\",\n    \"lastName\": \"Example\",\n    \"dateOfBirth\": \"1990-01-01\"\n  },\n  \"mediaIds\": {\n    \"selfie\": \"med_01j9x2k4m8\"\n  },\n  \"externalUserId\": \"user_42\"\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://sandbox-api.toden.co/api/kyc/verify', [
  'body' => '{
  "country": "NG",
  "idType": "bvn",
  "metadata": {
    "requestId": "req_7f3a2c",
    "loanId": "loan_20191"
  },
  "idNumber": "00000000001",
  "userData": {
    "firstName": "Ada",
    "lastName": "Example",
    "dateOfBirth": "1990-01-01"
  },
  "mediaIds": {
    "selfie": "med_01j9x2k4m8"
  },
  "externalUserId": "user_42"
}',
  'headers' => [
    'Authorization' => 'Bearer <apiKey>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://sandbox-api.toden.co/api/kyc/verify");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"country\": \"NG\",\n  \"idType\": \"bvn\",\n  \"metadata\": {\n    \"requestId\": \"req_7f3a2c\",\n    \"loanId\": \"loan_20191\"\n  },\n  \"idNumber\": \"00000000001\",\n  \"userData\": {\n    \"firstName\": \"Ada\",\n    \"lastName\": \"Example\",\n    \"dateOfBirth\": \"1990-01-01\"\n  },\n  \"mediaIds\": {\n    \"selfie\": \"med_01j9x2k4m8\"\n  },\n  \"externalUserId\": \"user_42\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "country": "NG",
  "idType": "bvn",
  "metadata": [
    "requestId": "req_7f3a2c",
    "loanId": "loan_20191"
  ],
  "idNumber": "00000000001",
  "userData": [
    "firstName": "Ada",
    "lastName": "Example",
    "dateOfBirth": "1990-01-01"
  ],
  "mediaIds": ["selfie": "med_01j9x2k4m8"],
  "externalUserId": "user_42"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://sandbox-api.toden.co/api/kyc/verify")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Example 2

**Request**

```json
{
  "country": "NG",
  "idType": "bvn",
  "metadata": {
    "requestId": "req_7f3a2c",
    "loanId": "loan_20191"
  },
  "idNumber": "00000000001",
  "userData": {
    "firstName": "Ada",
    "lastName": "Example",
    "dateOfBirth": "1990-01-01"
  },
  "mediaIds": {
    "selfie": "med_01j9x2k4m8"
  },
  "externalUserId": "user_42"
}
```

**Response**

```json
{
  "verificationId": "ver_01j9x2k4m8",
  "status": "processing",
  "externalUserId": "user_42",
  "metadata": {
    "loanId": "loan_20191"
  }
}
```

**SDK Code**

```python
import requests

url = "https://sandbox-api.toden.co/api/kyc/verify"

payload = {
    "country": "NG",
    "idType": "bvn",
    "metadata": {
        "requestId": "req_7f3a2c",
        "loanId": "loan_20191"
    },
    "idNumber": "00000000001",
    "userData": {
        "firstName": "Ada",
        "lastName": "Example",
        "dateOfBirth": "1990-01-01"
    },
    "mediaIds": { "selfie": "med_01j9x2k4m8" },
    "externalUserId": "user_42"
}
headers = {
    "Authorization": "Bearer <apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://sandbox-api.toden.co/api/kyc/verify';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <apiKey>', 'Content-Type': 'application/json'},
  body: '{"country":"NG","idType":"bvn","metadata":{"requestId":"req_7f3a2c","loanId":"loan_20191"},"idNumber":"00000000001","userData":{"firstName":"Ada","lastName":"Example","dateOfBirth":"1990-01-01"},"mediaIds":{"selfie":"med_01j9x2k4m8"},"externalUserId":"user_42"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://sandbox-api.toden.co/api/kyc/verify"

	payload := strings.NewReader("{\n  \"country\": \"NG\",\n  \"idType\": \"bvn\",\n  \"metadata\": {\n    \"requestId\": \"req_7f3a2c\",\n    \"loanId\": \"loan_20191\"\n  },\n  \"idNumber\": \"00000000001\",\n  \"userData\": {\n    \"firstName\": \"Ada\",\n    \"lastName\": \"Example\",\n    \"dateOfBirth\": \"1990-01-01\"\n  },\n  \"mediaIds\": {\n    \"selfie\": \"med_01j9x2k4m8\"\n  },\n  \"externalUserId\": \"user_42\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://sandbox-api.toden.co/api/kyc/verify")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"country\": \"NG\",\n  \"idType\": \"bvn\",\n  \"metadata\": {\n    \"requestId\": \"req_7f3a2c\",\n    \"loanId\": \"loan_20191\"\n  },\n  \"idNumber\": \"00000000001\",\n  \"userData\": {\n    \"firstName\": \"Ada\",\n    \"lastName\": \"Example\",\n    \"dateOfBirth\": \"1990-01-01\"\n  },\n  \"mediaIds\": {\n    \"selfie\": \"med_01j9x2k4m8\"\n  },\n  \"externalUserId\": \"user_42\"\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://sandbox-api.toden.co/api/kyc/verify")
  .header("Authorization", "Bearer <apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"country\": \"NG\",\n  \"idType\": \"bvn\",\n  \"metadata\": {\n    \"requestId\": \"req_7f3a2c\",\n    \"loanId\": \"loan_20191\"\n  },\n  \"idNumber\": \"00000000001\",\n  \"userData\": {\n    \"firstName\": \"Ada\",\n    \"lastName\": \"Example\",\n    \"dateOfBirth\": \"1990-01-01\"\n  },\n  \"mediaIds\": {\n    \"selfie\": \"med_01j9x2k4m8\"\n  },\n  \"externalUserId\": \"user_42\"\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://sandbox-api.toden.co/api/kyc/verify', [
  'body' => '{
  "country": "NG",
  "idType": "bvn",
  "metadata": {
    "requestId": "req_7f3a2c",
    "loanId": "loan_20191"
  },
  "idNumber": "00000000001",
  "userData": {
    "firstName": "Ada",
    "lastName": "Example",
    "dateOfBirth": "1990-01-01"
  },
  "mediaIds": {
    "selfie": "med_01j9x2k4m8"
  },
  "externalUserId": "user_42"
}',
  'headers' => [
    'Authorization' => 'Bearer <apiKey>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://sandbox-api.toden.co/api/kyc/verify");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"country\": \"NG\",\n  \"idType\": \"bvn\",\n  \"metadata\": {\n    \"requestId\": \"req_7f3a2c\",\n    \"loanId\": \"loan_20191\"\n  },\n  \"idNumber\": \"00000000001\",\n  \"userData\": {\n    \"firstName\": \"Ada\",\n    \"lastName\": \"Example\",\n    \"dateOfBirth\": \"1990-01-01\"\n  },\n  \"mediaIds\": {\n    \"selfie\": \"med_01j9x2k4m8\"\n  },\n  \"externalUserId\": \"user_42\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "country": "NG",
  "idType": "bvn",
  "metadata": [
    "requestId": "req_7f3a2c",
    "loanId": "loan_20191"
  ],
  "idNumber": "00000000001",
  "userData": [
    "firstName": "Ada",
    "lastName": "Example",
    "dateOfBirth": "1990-01-01"
  ],
  "mediaIds": ["selfie": "med_01j9x2k4m8"],
  "externalUserId": "user_42"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://sandbox-api.toden.co/api/kyc/verify")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```