Add a handle to a contact
Attaches a new channel address to an existing contact and returns the created handle.
Attaches a new channel address to an existing contact and returns the created handle. channel and value are required for every channel except postal, value is capped at 500 characters (an email value must be an email address and is stored trimmed and lowercased), and isPrimary (default false) marks this as the default handle Dairo routes to for that channel. A postal handle instead requires a structured address in metadata (name, street, postalCode, city, and country required; line2 and state optional; country normalized to an ISO-3166 alpha-2 code or a country name), from which the one-line value is derived when omitted — see send a letter. Two conflicts return 409: a handle whose (channel, value) already exists in the project, and a second isPrimary handle for the same channel on this contact. An unknown channel returns 400 and an unknown contact returns 404. Requires the contacts:write scope.
Scope: contacts:write. Send the API key as a bearer token; Scopes lists what each one reaches.
Request
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
contactId | string | yes | The contact's ID. |
Body
Required, application/json: ContactHandleInput.
| Field | Type | Required | Description |
|---|---|---|---|
channel | string | yes | email / a2a / telegram / postal / … |
value | string | yes | The channel address. For a postal handle this is the one-line formatted address (for display); the structured address goes in metadata. (max length 500) |
label | string | no | |
isPrimary | boolean | no | (default false) |
metadata | object | no | Structured extras. REQUIRED for a postal handle: { name, street, line2?, postalCode, city, state?, country } (see PostalAddress). name/street/postalCode/city/country are required; country is an ISO-3166 alpha-2 code or a country name. |
Response
200 Success. Body: application/json, ContactHandleResponse.
| Field | Type | Required | Description |
|---|---|---|---|
contactHandle | ContactHandle | yes |
Errors
Every error has the same body, {"error": {"type", "code", "message", "param"}}; branch on code. Errors lists every code.
| Status | Meaning |
|---|---|
400 | The request is malformed or a value is invalid (invalid_request, invalid_domain, idempotency_key_mismatch). |
401 | The API key is missing or invalid. |
403 | The key lacks the scope this endpoint needs (scope_missing) or may not do this (not_permitted). |
404 | No such resource in this account (resource_not_found). |
422 | The request is well-formed but a field failed validation (validation_failed). |
429 | Rate limit, plan limit, budget or spend cap reached (rate_limited, plan_limit_reached, budget_exceeded, spend_cap_reached). |
500 | An unexpected error; retry with backoff, then contact support (internal_error). |