Prerequisites
- A telli account with API access
- An API key from your telli dashboard (Settings > API & Webhooks)
What’s changed
The V2 API introduces several improvements over V1:- Typed contact properties — Structured, validated properties replace untyped dynamic variables (see Contact Properties for background)
- Cursor-based pagination — Efficient pagination for listing contacts
- Structured errors — Consistent error responses with HTTP status codes and error codes
Authentication
Authentication is unchanged. Use the same API key with the sameAuthorization header:
/v2/ prefix.
Endpoint mapping
| V1 Endpoint | V2 Endpoint | Notes |
|---|---|---|
POST /v1/add-contact | POST /v2/contacts | Returns 201 with full contact object |
GET /v1/get-contact/:contactId | GET /v2/contacts/{id} | Returns typed response with properties |
GET /v1/get-contact-by-external-id/:externalId | GET /v2/external/contacts/{externalId} | Same behavior, new path |
PATCH /v1/update-contact | PATCH /v2/contacts/{id} | Contact ID moves from body to URL path |
DELETE /v1/delete-contact/:contact_id | DELETE /v2/contacts/{id} | Returns 204 (no body) |
| — | GET /v2/contacts | New. Cursor-paginated contact list |
POST /v1/add-contacts-batch | — | Not yet available in V2 |
PATCH /v1/update-contacts-batch | — | Not yet available in V2 |
POST /v1/get-contacts-batch | — | Not yet available in V2 |
Field mapping
Request and response fields have moved from snake_case to camelCase:| V1 Field | V2 Field | Notes |
|---|---|---|
external_contact_id | externalId | |
external_url | externalUrl | |
first_name | firstName | |
last_name | lastName | |
phone_number | phoneNumber | |
email | email | Unchanged |
salutation | salutation | Unchanged |
timezone | timezoneIana | Renamed for clarity |
dynamic_variables | properties | See Migrating dynamic variables |
contact_details | properties | See Migrating dynamic variables |
contact_id (response) | id (response) | |
created_at (response) | createdAt (response) | ISO 8601 datetime string |
Response format
V2 responses include atype field and return enriched contact property data.
contact_idis nowidcontact_details(flat key-value object) is nowproperties(array of typed, enriched objects)- Each property in the response includes its
dataType,label, andoptions(for select types) - The
typefield identifies the resource type ("Contact") - Call-related fields (
status,call_attempts,next_call_at,in_call_since,reached_at) are not part of the V2 contacts response
Migrating dynamic variables to contact properties
This is the most significant change between V1 and V2. In V1, you could attach arbitrary key-value data to contacts viadynamic_variables or contact_details without any prior setup. In V2, you first define a property schema with a human-readable key and then use that key when setting values.
For a full overview of what contact properties are and how to manage them in the telli UI, see Contact Properties.
How it works
- Define a property — Create a property definition with a key, data type, label, and optional constraints via the API (or through the telli UI)
- Choose a property key — You define a human-readable, URL-safe key (e.g.,
appointment_date) when creating the property - Use the key on contacts — When creating or updating contacts, pass properties as
[{key, value}]pairs using your chosen keys
Example: before and after
Suppose you were storing these dynamic variables on contacts in V1:Available property types
| API Data Type | Description | Example Value |
|---|---|---|
string | Free-text string | "Enterprise" |
number | Numeric value | 42 |
boolean | True or false | true |
date | Calendar date (YYYY-MM-DD) | "2026-03-15" |
datetime | Date with time (ISO 8601) | "2026-03-15T14:30:00Z" |
select | Single choice from predefined options | "gold" |
multi_select | Multiple choices from predefined options | ["german", "english"] |
phone_number | Phone number in E.164 format | "+4915112345678" |
email | Email address | "[email protected]" |
System properties
Some contact fields are represented as system properties in V2. These are always present and cannot be modified or deleted through the properties API:| Key | Data Type | Label |
|---|---|---|
externalId | string | External ID |
firstName | string | First Name |
lastName | string | Last Name |
phoneNumber | phone_number | Phone Number |
email | ||
timezoneIana | string | Timezone |
externalUrl | string | External URL |
firstName, email), not through the properties array.
Operation-by-operation migration
Create a contact
{ "contact_id": "..." }. V2 returns 201 with the full contact object including enriched properties.
Get a contact by ID
Get a contact by external ID
List contacts
This endpoint is new in V2 — there is no V1 equivalent. It returns a paginated list of contacts using cursor-based pagination.endCursor value as the cursor query parameter:
Update a contact
In V1, you pass thecontact_id in the request body. In V2, the contact ID is part of the URL path.
- V1 replaces the entire
dynamic_variablesobject. If you only send{"interest_level": "medium"}, all other dynamic variables are lost. - V2 merges properties. Only the keys you include are updated — all other existing properties are preserved. To clear a property, set its value to
null.
Delete a contact
{ "message": "Contact deleted successfully", "contact_id": "..." }. V2 returns 204 No Content with an empty response body.
Contact Properties API
V2 introduces a dedicated API for managing property definitions. You only need to create property definitions once per account — they then apply to all contacts. For managing properties through the telli UI instead, see Contact Properties.List all property definitions
Get a single property definition
Create a property definition
Update a property definition
You can update the label, description, and add new options (for select types). You cannot change the data type or remove existing options.Key differences to be aware of
-
Properties require prior definition — You must create a property definition before you can use it on contacts. Unknown property keys are rejected with a
422validation error. -
Property keys are user-defined — You choose a human-readable, URL-safe key (e.g.,
appointment_date) when creating a property. Keys must be unique within your account. -
Update merges properties — In V2, updating a contact’s properties only affects the keys you include. Existing properties are preserved. Set a value to
nullto clear a specific property. In V1, sendingdynamic_variablesreplaced the entire object. -
Values are validated — V2 validates property values against their data type and constraints (e.g., a
dateproperty rejects"not-a-date", aselectproperty rejects values not in the options list). V1 accepted any value. -
Batch endpoints are not yet available in V2 — If you rely on batch operations (
add-contacts-batch,update-contacts-batch,get-contacts-batch), continue using the V1 endpoints for now. -
V2 returns enriched properties — GET responses include the
dataType,label, andoptionsfor each property value, so you don’t need a separate lookup to interpret property data.