> 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.

# Import entities in bulk

POST https://sandbox-api.toden.co/api/identity/entities/import
Content-Type: application/json

Accepts between 1 and 1,000 entities and returns straight away. The whole submission is stored before the response is sent, and each item is then registered in the background, so nothing is lost if processing is interrupted. Poll the job to follow progress.

Each item is the idempotent upsert of a single registration, so sending the same book again updates the same entities. The request itself is not deduplicated: every call creates a new job. The whole array is validated first, and one invalid item rejects the request.

Side effects: `entity.imported` fires for each entity the job creates, and each entity is enrolled in screening as on a single registration. The submission is recorded in your audit log without the individual references.

**Error codes**

| `error` | Status | Meaning |
|---|---|---|
| `invalid_request` | 400 | The body failed validation, or the array is empty or longer than 1,000 items. |
| `secret_key_required` | 403 | A publishable key was used. This API accepts secret keys only. |
| `environment_mismatch` | 403 | The key belongs to an environment this host does not serve. |
| `rate_limited` | 429 | The request rate limit for this key was reached. Retry after a short wait. |
| `rate_limit_store_unavailable` | 503 | Rate limiting is temporarily unavailable. Retry shortly. |

A missing or unknown key returns `401` with a plain sentence in `error` rather than a code.

Requires a secret (`sk_`) key. A publishable key receives `403 secret_key_required`.

Reference: https://docs.toden.co/api-reference/verification/entities/import-entities

## 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 an EntityImportRequest.

- `entities` (list of EntityUpsertRequest, required) — The entities to register. Each item has the same shape and behaviour as a single registration.

## Response

### 202

The import was accepted and is being processed.

- `jobId` (string, required) — The identifier of the import job.
- `status` (enum, required) — Always `PROCESSING` when the job is accepted.
  - Allowed values: `PROCESSING`
- `total` (integer, required) — How many entities the job holds.

## 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.

### 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.

### 503 Service Unavailable Error

The service is temporarily unavailable.

- `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

### EntityUpsertRequest

- `externalUserId` (string, required) — Your own stable reference for the person or business. It is the key of the entity within your organisation and environment.
- `metadata` (map from string to any, optional) — Your own correlation fields for the entity, returned on reads and carried on webhooks about it. Sending it again replaces the stored object. At most 16 KiB of JSON, four levels deep, 100 keys in total, 50 keys per object, 20 items per array, keys up to 64 characters and strings up to 1,000 characters.
- `type` (enum, optional) — Whether the entity is a person or a business. Written on every call, so an omitted value is stored as `INDIVIDUAL`.
  - Allowed values: `INDIVIDUAL`, `BUSINESS`
- `kycProvenance` (enum, optional) — How the entity was verified. `EXTERNAL_VERIFIED` records a verification done outside Toden, which is trusted as declared. Written on every call, so an omitted value is stored as `UNVERIFIED`.
  - Allowed values: `MYAZA_VERIFIED`, `EXTERNAL_VERIFIED`, `UNVERIFIED`
- `kycSource` (string, optional) — A label for where the external verification came from, such as the name of your previous provider. Omitting it clears the stored value.
- `profile` (EntityProfileInput, optional) — Attributes you hold about the entity. Every field is optional, and a field you omit keeps its stored value.

### EntityProfileInput

Attributes you hold about the entity. Every field is optional, and a field you omit keeps its stored value.

- `fullName` (string, optional) — The full name of the person, or the registered name of the business.
- `dateOfBirth` (string, optional) — The date of birth, as a string such as `1990-01-01`.
- `nationality` (string, optional) — The nationality or country, ideally as an ISO 3166-1 alpha-2 code.
- `idType` (string, optional) — The type of identity document the number belongs to, such as `bvn` or `passport`.
- `idNumber` (string, optional) — The identity document number. Together with `idType` it drives identity resolution on a verified entity.
- `address` (map from string to any, optional) — The address you hold, as free-form JSON. It is recorded as declared address evidence for the entity.
- `email` (string, optional) — An email address you hold for the entity. Recorded as declared contact evidence.
- `phone` (string, optional) — A phone number you hold for the entity. Recorded as declared contact evidence.
- `declaredMonthlyVolume` (double, optional) — The monthly transaction volume the customer declared.
- `declaredVolumeCurrency` (string, optional) — The ISO 4217 currency code the declared volume is stated in. Lower case input is upper-cased.
- `declaredTxnTypes` (list of string, optional) — The kinds of transaction the customer declared they expect to make.
- `walletAddresses` (list of EntityProfileInputWalletAddressesItems, optional) — Crypto wallet addresses attached to the entity. Omit the key to leave the stored set unchanged; send an array (including an empty one) to replace it. Wallets are risk attributes for wallet screening, never identity keys.

### EntityProfileInputWalletAddressesItems

- `address` (string, required) — The wallet address.
- `chain` (string, optional) — The network the address belongs to, in your own naming.
- `label` (string, optional) — Your own label for the wallet.

## Examples

**Request**

```json
{
  "entities": [
    {
      "externalUserId": "user_1",
      "type": "INDIVIDUAL",
      "kycProvenance": "EXTERNAL_VERIFIED",
      "kycSource": "previous-provider"
    },
    {
      "externalUserId": "user_2",
      "type": "BUSINESS"
    }
  ]
}
```

**Response**

```json
{
  "jobId": "cm9x2k4m80001",
  "status": "PROCESSING",
  "total": 2
}
```

**SDK Code**

```python
import requests

url = "https://sandbox-api.toden.co/api/identity/entities/import"

payload = { "entities": [
        {
            "externalUserId": "user_1",
            "type": "INDIVIDUAL",
            "kycProvenance": "EXTERNAL_VERIFIED",
            "kycSource": "previous-provider"
        },
        {
            "externalUserId": "user_2",
            "type": "BUSINESS"
        }
    ] }
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/identity/entities/import';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <apiKey>', 'Content-Type': 'application/json'},
  body: '{"entities":[{"externalUserId":"user_1","type":"INDIVIDUAL","kycProvenance":"EXTERNAL_VERIFIED","kycSource":"previous-provider"},{"externalUserId":"user_2","type":"BUSINESS"}]}'
};

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/identity/entities/import"

	payload := strings.NewReader("{\n  \"entities\": [\n    {\n      \"externalUserId\": \"user_1\",\n      \"type\": \"INDIVIDUAL\",\n      \"kycProvenance\": \"EXTERNAL_VERIFIED\",\n      \"kycSource\": \"previous-provider\"\n    },\n    {\n      \"externalUserId\": \"user_2\",\n      \"type\": \"BUSINESS\"\n    }\n  ]\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/identity/entities/import")

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  \"entities\": [\n    {\n      \"externalUserId\": \"user_1\",\n      \"type\": \"INDIVIDUAL\",\n      \"kycProvenance\": \"EXTERNAL_VERIFIED\",\n      \"kycSource\": \"previous-provider\"\n    },\n    {\n      \"externalUserId\": \"user_2\",\n      \"type\": \"BUSINESS\"\n    }\n  ]\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/identity/entities/import")
  .header("Authorization", "Bearer <apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"entities\": [\n    {\n      \"externalUserId\": \"user_1\",\n      \"type\": \"INDIVIDUAL\",\n      \"kycProvenance\": \"EXTERNAL_VERIFIED\",\n      \"kycSource\": \"previous-provider\"\n    },\n    {\n      \"externalUserId\": \"user_2\",\n      \"type\": \"BUSINESS\"\n    }\n  ]\n}")
  .asString();
```

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

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://sandbox-api.toden.co/api/identity/entities/import', [
  'body' => '{
  "entities": [
    {
      "externalUserId": "user_1",
      "type": "INDIVIDUAL",
      "kycProvenance": "EXTERNAL_VERIFIED",
      "kycSource": "previous-provider"
    },
    {
      "externalUserId": "user_2",
      "type": "BUSINESS"
    }
  ]
}',
  'headers' => [
    'Authorization' => 'Bearer <apiKey>',
    'Content-Type' => 'application/json',
  ],
]);

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

```csharp
using RestSharp;

var client = new RestClient("https://sandbox-api.toden.co/api/identity/entities/import");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"entities\": [\n    {\n      \"externalUserId\": \"user_1\",\n      \"type\": \"INDIVIDUAL\",\n      \"kycProvenance\": \"EXTERNAL_VERIFIED\",\n      \"kycSource\": \"previous-provider\"\n    },\n    {\n      \"externalUserId\": \"user_2\",\n      \"type\": \"BUSINESS\"\n    }\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <apiKey>",
  "Content-Type": "application/json"
]
let parameters = ["entities": [
    [
      "externalUserId": "user_1",
      "type": "INDIVIDUAL",
      "kycProvenance": "EXTERNAL_VERIFIED",
      "kycSource": "previous-provider"
    ],
    [
      "externalUserId": "user_2",
      "type": "BUSINESS"
    ]
  ]] as [String : Any]

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

let request = NSMutableURLRequest(url: NSURL(string: "https://sandbox-api.toden.co/api/identity/entities/import")! 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()
```