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

# Grade a book of addresses

POST https://sandbox-api.toden.co/api/identity/address-triage
Content-Type: application/json

Submits up to 25,000 customer addresses for grading and returns straight away; the rows are graded in the background. Each row is graded `corroborated`, `confirmable_in_app`, `needs_presence` or `unresolvable` against the evidence already held for the customer. Poll the job to read the result.

The call is not idempotent: every request creates a new job, and in production a new charge.

**Billing.** In production the whole book is charged per row when the job is accepted, and the request is refused up front if the balance cannot cover it. Sandbox jobs are free. With `preview: true` only the first 250 rows are graded, nothing is charged in any environment, and `quote` states what the rest would cost.

**Error codes**

| `error` | Status | Meaning |
|---|---|---|
| `invalid_request` | 400 | The body failed validation. `details` carries the field-level breakdown. |
| `empty_book` | 400 | The book has no usable rows. |
| `insufficient_credits` | 402 | The balance cannot cover the run. `required`, `balance` and `currency` are returned, and nothing was charged. |
| `pricing_not_configured` | 500 | No price is configured for address triage. Nothing was charged. |
| `geocoder_unavailable` | 503 | Address triage is temporarily unavailable. Nothing was charged. |
| `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/address-triage/create-address-triage

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

- `rows` (list of AddressTriageRow, required) — The rows of the book to grade.
- `country` (string, optional) — The default country for rows that carry none. When omitted, the country of your organisation is used, as an ISO 3166-1 alpha-2 code.
- `preview` (boolean, optional) — Set to true to grade only the first 250 rows free of charge and receive a quote for the rest.

## Response

### 202

The job was accepted and is being graded.

- `jobId` (string, required) — The identifier of the triage job.
- `status` (enum, required) — Always `PROCESSING` when the job is accepted.
  - Allowed values: `PROCESSING`
- `total` (integer, required) — How many rows will be graded.
- `preview` (boolean, required) — True when only a free sample is being graded.
- `quote` (AddressTriageAcceptedQuote, required, nullable) — For a sample, what grading the remaining rows would cost; otherwise `null`.

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

### 402 Payment Required Error

The organisation does not have enough credit for this request.

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

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

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

### AddressTriageRow

- `address` (string, required) — The address you hold, as free text.
- `externalUserId` (string, optional) — Your own reference for the customer. It is how a row is matched to an entity, and a row without one cannot be sent a link.
- `name` (string, optional) — The name of the customer, used to greet them in a remediation link.
- `country` (string, optional) — The country of this row, as an ISO 3166-1 alpha-2 code.

### AddressTriageAcceptedQuote

For a sample, what grading the remaining rows would cost; otherwise `null`.

- `rows` (integer, required) — How many rows the sample left ungraded.
- `amount` (string, required) — What grading those rows would cost, as a decimal string.
- `currency` (enum, required) — Always `USD`.
  - Allowed values: `USD`

## Examples

**Request**

```json
{
  "rows": [
    {
      "address": "1 Example Street, Ikeja, Lagos",
      "externalUserId": "user_42",
      "name": "Ada Example"
    },
    {
      "address": "22 Sample Close, Calabar",
      "externalUserId": "user_43"
    }
  ],
  "country": "NG"
}
```

**Response**

```json
{
  "jobId": "cm9x2k4m80006",
  "status": "PROCESSING",
  "total": 2,
  "preview": false,
  "quote": null
}
```

**SDK Code**

```python
import requests

url = "https://sandbox-api.toden.co/api/identity/address-triage"

payload = {
    "rows": [
        {
            "address": "1 Example Street, Ikeja, Lagos",
            "externalUserId": "user_42",
            "name": "Ada Example"
        },
        {
            "address": "22 Sample Close, Calabar",
            "externalUserId": "user_43"
        }
    ],
    "country": "NG"
}
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/address-triage';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <apiKey>', 'Content-Type': 'application/json'},
  body: '{"rows":[{"address":"1 Example Street, Ikeja, Lagos","externalUserId":"user_42","name":"Ada Example"},{"address":"22 Sample Close, Calabar","externalUserId":"user_43"}],"country":"NG"}'
};

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/address-triage"

	payload := strings.NewReader("{\n  \"rows\": [\n    {\n      \"address\": \"1 Example Street, Ikeja, Lagos\",\n      \"externalUserId\": \"user_42\",\n      \"name\": \"Ada Example\"\n    },\n    {\n      \"address\": \"22 Sample Close, Calabar\",\n      \"externalUserId\": \"user_43\"\n    }\n  ],\n  \"country\": \"NG\"\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/address-triage")

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  \"rows\": [\n    {\n      \"address\": \"1 Example Street, Ikeja, Lagos\",\n      \"externalUserId\": \"user_42\",\n      \"name\": \"Ada Example\"\n    },\n    {\n      \"address\": \"22 Sample Close, Calabar\",\n      \"externalUserId\": \"user_43\"\n    }\n  ],\n  \"country\": \"NG\"\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/address-triage")
  .header("Authorization", "Bearer <apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"rows\": [\n    {\n      \"address\": \"1 Example Street, Ikeja, Lagos\",\n      \"externalUserId\": \"user_42\",\n      \"name\": \"Ada Example\"\n    },\n    {\n      \"address\": \"22 Sample Close, Calabar\",\n      \"externalUserId\": \"user_43\"\n    }\n  ],\n  \"country\": \"NG\"\n}")
  .asString();
```

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

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://sandbox-api.toden.co/api/identity/address-triage', [
  'body' => '{
  "rows": [
    {
      "address": "1 Example Street, Ikeja, Lagos",
      "externalUserId": "user_42",
      "name": "Ada Example"
    },
    {
      "address": "22 Sample Close, Calabar",
      "externalUserId": "user_43"
    }
  ],
  "country": "NG"
}',
  '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/address-triage");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"rows\": [\n    {\n      \"address\": \"1 Example Street, Ikeja, Lagos\",\n      \"externalUserId\": \"user_42\",\n      \"name\": \"Ada Example\"\n    },\n    {\n      \"address\": \"22 Sample Close, Calabar\",\n      \"externalUserId\": \"user_43\"\n    }\n  ],\n  \"country\": \"NG\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "rows": [
    [
      "address": "1 Example Street, Ikeja, Lagos",
      "externalUserId": "user_42",
      "name": "Ada Example"
    ],
    [
      "address": "22 Sample Close, Calabar",
      "externalUserId": "user_43"
    ]
  ],
  "country": "NG"
] as [String : Any]

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

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