> **Draft: Addrexy is not live yet.** It will run at https://addrexy.com as a tenant of the white-label developer portal. In version 1 the portal and its documentation are those of the existing white-label tenant at https://intodq2.devapicloud.com; the API and the documentation are the same. **TBD** marks something not yet decided. **Not documented** marks something the white-label documentation does not say.

# Operate: run it

## Errors

Every error from every endpoint has the same envelope. The request id is in the `X-Request-Id` response header, not the body.

```json
{
  "result": {
    "status": "ERROR",
    "message": "query.countryCode is required.",
    "errorCode": "MISSING_REQUIRED_FIELD",
    "docsUrl": "https://addrexy.com/errors/MISSING_REQUIRED_FIELD"
  }
}
```

Branch on `errorCode`. Use `message` for logs, not for end users. `docsUrl` links to documentation; do not depend on it. A `200` response carries `result.status` too (`OK` or `ERROR`): check it, and read `result.message` if it is `ERROR`.

| `errorCode` | HTTP | Do this |
|---|---|---|
| `INVALID_REQUEST` | 400 | The body is malformed or empty. Fix it. Check `Content-Type: application/json`. Do not retry unchanged. |
| `INVALID_COORDINATES` | 400 | Reverse geocode only. Latitude or longitude is not a number or is out of range (latitude -90 to 90, longitude -180 to 180). Fix it. |
| `MISSING_REQUIRED_FIELD` | 400 | A required field is absent or blank. Autocomplete needs `addressInput` and `countryCode`; verify and forward geocode need `address` and `countryCode`; reverse geocode needs `latitude` and `longitude`. |
| `INVALID_PARAMETER` | 400 | A value is the wrong type, format or range, or a dependency is missing (for example `searchRadius` without `originCoordinates`, or a reverse-geocode `searchRadius` missing `value` or `unit`). Fix it. |
| `INVALID_COUNTRY` | 400 | Not three alphabetic characters. Use an ISO 3166-1 alpha-3 code such as `USA`. |
| `UNSUPPORTED_COUNTRY` | 400 | A valid country your subscription does not cover. Skip those addresses, record them, and ask the administrator to add coverage. |
| `MISSING_SESSION_TOKEN` | 400 | `X-Session-Token` is missing or not a UUID v4. Generate one and send it on every call. |
| `MISSING_CREDENTIALS` | 401 | No `Authorization` header. Send `Authorization: Basic base64(key:secret)`. |
| `INVALID_CREDENTIALS` | 401 | The encoding is wrong, or the key and secret are not recognised. Re-encode them. If they are right, they may have been rotated: ask your human for the current pair. Do not retry. |
| `FORBIDDEN` | 403 | The key is valid but lacks the scope for this API. Stop and tell your human. |
| `SUBSCRIPTION_INACTIVE` | 403 | The subscription has expired or been suspended. Stop and tell your human. |
| `UNSUPPORTED_MEDIA_TYPE` | 415 | `Content-Type` is missing or not `application/json`. A charset suffix is fine. |
| `RATE_LIMIT_EXCEEDED` | 429 | Wait the number of seconds in `Retry-After`, then retry once. |
| `INTERNAL_ERROR` | 500 | Retry with backoff. See below. |
| `SERVICE_UNAVAILABLE` | 503 | Wait `Retry-After`, then retry. |

## Retry policy

From the API documentation, with Addrexy guidance marked.

| HTTP status | What to do |
|---|---|
| 429 | Wait `Retry-After` seconds, then retry once. Do not retry immediately. *Addrexy guidance:* if the retry also returns 429, stop and report. If `Retry-After` is missing, back off as for 500. |
| 500 | Exponential backoff: 1 s, 2 s, 4 s. After 3 failed attempts, stop and report. *Addrexy guidance:* make the first call, then up to 3 retries after waits of 1 s, 2 s and 4 s. |
| 503 | Wait `Retry-After`. Then retry. *Addrexy guidance:* no more than 3 attempts. |
| Any other 4xx | Do not retry. A client error will not fix itself. Change the request first. |

Reuse the same `X-Session-Token` when you retry the same operation. Whether a retried call uses credits again is not documented.

## Rate limits

Per API key, per second, and independent for each API:

| API | Limit |
|---|---|
| Autocomplete | 50 requests per second |
| Verify | 200 requests per second |
| Forward geocode | 200 requests per second |
| Reverse geocode | 200 requests per second |

Autocomplete: debounce keystrokes at 200 ms and share one `X-Session-Token` across a whole search session. That collapses many keystrokes into far fewer requests. Do not call autocomplete for fewer than 3 characters.

No rate-limit headers are documented, so throttle yourself. For bulk verification there is no batch endpoint: send individual calls, in parallel if you like, but keep under the limit. Plan the total against your credits first.

## Audit log

Record for every call: the request id, a timestamp, which API, your own `referenceId` if you sent one, the input address, `matchScore` (verify), and what you did next. If someone later asks why you accepted an address, this is your answer. Send your own `X-Request-Id` so your log and ours share a key.

## Credits

Calls draw down credits that the administrator allocated to your department. Cost per call and what happens at zero credits are not documented. Whether a failed or retried call uses credits is not documented either. The administrator has a usage dashboard. If you meet an unexplained `403`, stop; do not loop.

## Support

A support channel is **TBD**: the white-label documentation uses a placeholder for the support address. Until one exists, report problems to your human, quoting the request id.

## Personal data

Addresses can identify a person. Log only what you need. Keep the key and secret out of logs and source control.

## Hand back to a human when

- You get `FORBIDDEN` or `SUBSCRIPTION_INACTIVE`.
- You get `INVALID_CREDENTIALS` and have no newer key.
- You are about to use an address with a `matchScore` of 3 or less for something you cannot undo.
- You need a country that returns `UNSUPPORTED_COUNTRY`.
- You have no credentials and no way to get them.

## When nobody is reachable

- **Low scores.** Follow [/agent/build](https://addrexy.com/agent/build). Queue the record, say why, and carry on with other work. Do not wait.
- **A failure you cannot fix.** Stop. Record the error code and the request id.
- **No credentials.** Stop. Record what you needed and why. Do not look for another way in.