curl --request POST \
--url https://api.cloudtalk.io/v1/contacts \
--header 'Authorization: Basic <encoded-value>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Sam Rivera",
"type": "lead",
"company": "Northwind",
"countryCode": "GB",
"phones": [
"+447700900123"
],
"emails": [
"[email protected]"
],
"tagIds": [
"131"
],
"matchBy": "emailOrPhone"
}
'import requests
url = "https://api.cloudtalk.io/v1/contacts"
payload = {
"name": "Sam Rivera",
"type": "lead",
"company": "Northwind",
"countryCode": "GB",
"phones": ["+447700900123"],
"emails": ["[email protected]"],
"tagIds": ["131"],
"matchBy": "emailOrPhone"
}
headers = {
"Authorization": "Basic <encoded-value>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Basic <encoded-value>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'Sam Rivera',
type: 'lead',
company: 'Northwind',
countryCode: 'GB',
phones: ['+447700900123'],
emails: ['[email protected]'],
tagIds: ['131'],
matchBy: 'emailOrPhone'
})
};
fetch('https://api.cloudtalk.io/v1/contacts', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.cloudtalk.io/v1/contacts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Sam Rivera',
'type' => 'lead',
'company' => 'Northwind',
'countryCode' => 'GB',
'phones' => [
'+447700900123'
],
'emails' => [
'[email protected]'
],
'tagIds' => [
'131'
],
'matchBy' => 'emailOrPhone'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Basic <encoded-value>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.cloudtalk.io/v1/contacts"
payload := strings.NewReader("{\n \"name\": \"Sam Rivera\",\n \"type\": \"lead\",\n \"company\": \"Northwind\",\n \"countryCode\": \"GB\",\n \"phones\": [\n \"+447700900123\"\n ],\n \"emails\": [\n \"[email protected]\"\n ],\n \"tagIds\": [\n \"131\"\n ],\n \"matchBy\": \"emailOrPhone\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Basic <encoded-value>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.cloudtalk.io/v1/contacts")
.header("Authorization", "Basic <encoded-value>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Sam Rivera\",\n \"type\": \"lead\",\n \"company\": \"Northwind\",\n \"countryCode\": \"GB\",\n \"phones\": [\n \"+447700900123\"\n ],\n \"emails\": [\n \"[email protected]\"\n ],\n \"tagIds\": [\n \"131\"\n ],\n \"matchBy\": \"emailOrPhone\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cloudtalk.io/v1/contacts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Basic <encoded-value>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"Sam Rivera\",\n \"type\": \"lead\",\n \"company\": \"Northwind\",\n \"countryCode\": \"GB\",\n \"phones\": [\n \"+447700900123\"\n ],\n \"emails\": [\n \"[email protected]\"\n ],\n \"tagIds\": [\n \"131\"\n ],\n \"matchBy\": \"emailOrPhone\"\n}"
response = http.request(request)
puts response.read_body{
"id": "44190",
"type": "lead",
"name": "Sam Rivera",
"title": "Purchasing Manager",
"company": "Northwind",
"industry": null,
"website": null,
"address": null,
"city": "London",
"state": null,
"zip": null,
"country": {
"code": "GB",
"name": "United Kingdom"
},
"phones": [
"+447700900123"
],
"emails": [
"[email protected]"
],
"tags": [
{
"id": "131",
"name": "webinar",
"readOnly": false
}
],
"customFields": {
"Segment": "smb"
},
"favoriteUserId": null,
"source": "api",
"createdAt": "2026-09-14T08:30:00Z",
"updatedAt": "2026-11-02T10:00:00Z",
"dashboardUrl": "https://dashboard.cloudtalk.io/menu/contacts/details/44190"
}{
"id": "44211",
"type": "lead",
"name": "Sam Rivera",
"title": null,
"company": "Northwind",
"industry": null,
"website": null,
"address": null,
"city": null,
"state": null,
"zip": null,
"country": {
"code": "GB",
"name": "United Kingdom"
},
"phones": [
"+447700900123"
],
"emails": [
"[email protected]"
],
"tags": [
{
"id": "131",
"name": "webinar",
"readOnly": false
}
],
"customFields": {},
"favoriteUserId": null,
"source": "api",
"createdAt": "2026-11-02T10:00:00Z",
"updatedAt": "2026-11-02T10:00:00Z",
"dashboardUrl": "https://dashboard.cloudtalk.io/menu/contacts/details/44211"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}{
"code": "UNAUTHORIZED",
"message": "You are not authorized to access this resource."
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}<string>{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}Create a contact
Creates a contact and returns it with 201. Invalid numbers and emails are rejected, not dropped. Text fields are cleaned up before their length is checked and they are stored, as in the CloudTalk Dashboard and the existing API: emojis and other characters that take 4 bytes in UTF-8, and control characters such as line breaks and tabs, become a space; repeated whitespace becomes one space; and spaces at the start and end are removed. This applies to name, title, company, industry, website, address, city, state, zip and custom field values, not to emails or phone numbers. The contact’s source is api.
Matching. By default no duplicate check runs (matchBy: none). With matchBy set to phone, email or emailOrPhone, a contact that matches is updated instead and the response is 200. Fields you send overwrite the match, custom fields you do not send are kept, and when several contacts match, the most recently created one is updated and the others stay as they are. With emailOrPhone the phone can match one contact and the email another: the most recently created of them gets every value you sent, phones and emails included. The response does not say that more than one contact matched.
Tags. tagIds takes existing contact tag ids only, so a create never makes a tag by accident. To use a new tag, create it first with Create a contact tag. Read-only tags are refused (see List contact tags).
Retries. Send an Idempotency-Key to retry safely. The same key with the same body returns the original status with the contact as it is now. If that contact has been deleted since, the request creates a new one. While the first request with a key is still running, a retry gets 409 IDEMPOTENCY.REQUEST_IN_PROGRESS: retry it shortly. The same key with a different body is rejected with 422 IDEMPOTENCY.KEY_REUSED. Keys are kept for 24 hours. If the key store cannot be reached, a create that carries a key fails with 502 CONTACTS.UPSTREAM_UNAVAILABLE instead of risking a duplicate. A create without a key never touches the key store.
A contact.created webhook is sent, or contact.updated when a match changed. CloudTalk also exports the contact to your active CRM integrations.
curl --request POST \
--url https://api.cloudtalk.io/v1/contacts \
--header 'Authorization: Basic <encoded-value>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Sam Rivera",
"type": "lead",
"company": "Northwind",
"countryCode": "GB",
"phones": [
"+447700900123"
],
"emails": [
"[email protected]"
],
"tagIds": [
"131"
],
"matchBy": "emailOrPhone"
}
'import requests
url = "https://api.cloudtalk.io/v1/contacts"
payload = {
"name": "Sam Rivera",
"type": "lead",
"company": "Northwind",
"countryCode": "GB",
"phones": ["+447700900123"],
"emails": ["[email protected]"],
"tagIds": ["131"],
"matchBy": "emailOrPhone"
}
headers = {
"Authorization": "Basic <encoded-value>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Basic <encoded-value>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'Sam Rivera',
type: 'lead',
company: 'Northwind',
countryCode: 'GB',
phones: ['+447700900123'],
emails: ['[email protected]'],
tagIds: ['131'],
matchBy: 'emailOrPhone'
})
};
fetch('https://api.cloudtalk.io/v1/contacts', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.cloudtalk.io/v1/contacts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Sam Rivera',
'type' => 'lead',
'company' => 'Northwind',
'countryCode' => 'GB',
'phones' => [
'+447700900123'
],
'emails' => [
'[email protected]'
],
'tagIds' => [
'131'
],
'matchBy' => 'emailOrPhone'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Basic <encoded-value>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.cloudtalk.io/v1/contacts"
payload := strings.NewReader("{\n \"name\": \"Sam Rivera\",\n \"type\": \"lead\",\n \"company\": \"Northwind\",\n \"countryCode\": \"GB\",\n \"phones\": [\n \"+447700900123\"\n ],\n \"emails\": [\n \"[email protected]\"\n ],\n \"tagIds\": [\n \"131\"\n ],\n \"matchBy\": \"emailOrPhone\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Basic <encoded-value>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.cloudtalk.io/v1/contacts")
.header("Authorization", "Basic <encoded-value>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Sam Rivera\",\n \"type\": \"lead\",\n \"company\": \"Northwind\",\n \"countryCode\": \"GB\",\n \"phones\": [\n \"+447700900123\"\n ],\n \"emails\": [\n \"[email protected]\"\n ],\n \"tagIds\": [\n \"131\"\n ],\n \"matchBy\": \"emailOrPhone\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cloudtalk.io/v1/contacts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Basic <encoded-value>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"Sam Rivera\",\n \"type\": \"lead\",\n \"company\": \"Northwind\",\n \"countryCode\": \"GB\",\n \"phones\": [\n \"+447700900123\"\n ],\n \"emails\": [\n \"[email protected]\"\n ],\n \"tagIds\": [\n \"131\"\n ],\n \"matchBy\": \"emailOrPhone\"\n}"
response = http.request(request)
puts response.read_body{
"id": "44190",
"type": "lead",
"name": "Sam Rivera",
"title": "Purchasing Manager",
"company": "Northwind",
"industry": null,
"website": null,
"address": null,
"city": "London",
"state": null,
"zip": null,
"country": {
"code": "GB",
"name": "United Kingdom"
},
"phones": [
"+447700900123"
],
"emails": [
"[email protected]"
],
"tags": [
{
"id": "131",
"name": "webinar",
"readOnly": false
}
],
"customFields": {
"Segment": "smb"
},
"favoriteUserId": null,
"source": "api",
"createdAt": "2026-09-14T08:30:00Z",
"updatedAt": "2026-11-02T10:00:00Z",
"dashboardUrl": "https://dashboard.cloudtalk.io/menu/contacts/details/44190"
}{
"id": "44211",
"type": "lead",
"name": "Sam Rivera",
"title": null,
"company": "Northwind",
"industry": null,
"website": null,
"address": null,
"city": null,
"state": null,
"zip": null,
"country": {
"code": "GB",
"name": "United Kingdom"
},
"phones": [
"+447700900123"
],
"emails": [
"[email protected]"
],
"tags": [
{
"id": "131",
"name": "webinar",
"readOnly": false
}
],
"customFields": {},
"favoriteUserId": null,
"source": "api",
"createdAt": "2026-11-02T10:00:00Z",
"updatedAt": "2026-11-02T10:00:00Z",
"dashboardUrl": "https://dashboard.cloudtalk.io/menu/contacts/details/44211"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}{
"code": "UNAUTHORIZED",
"message": "You are not authorized to access this resource."
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}<string>{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}Authorizations
HTTP Basic Authentication. Use your API Access Key ID as the username and your API Access Key Secret as the password. Generate keys in the CloudTalk Dashboard under Account -> Settings -> API Keys (https://dashboard.cloudtalk.io/menu/account/settings/API-keys).
Headers
Up to 255 characters naming this create. See Retries in the operation description.
255Body
1 - 150contact, lead 25510010010025525525515ISO 3166-1 alpha-2.
"GB"
Up to 20 numbers in E.164. An invalid number is rejected, not dropped.
20Up to 20 valid addresses. An invalid address is rejected, not dropped.
20Up to 50 existing contact tag ids from List contact tags. Read-only tags are refused. To use a new tag, create it first with Create a contact tag.
50Keys are field names from List contact fields. Values are strings of up to 255 characters. At most 100 keys.
Show child attributes
Show child attributes
A user in your account who owns the contact.
none creates a new contact without a duplicate check. phone, email or emailOrPhone updates a matching contact instead (see the operation description).
none, phone, email, emailOrPhone Response
matchBy found a contact, and it was updated with the fields you sent. Only when matchBy is not none.
A contact or lead, with every number, email, tag and custom field.
Contact id.
"44210"
contact, lead The contact's name. null only for an older contact saved without one: contacts created through this API always have a name, and an update cannot clear it.
1 - 150"Jane Doe"
25510010010025525525515Show child attributes
Show child attributes
Every number on the contact, in E.164.
["+12025550143"]
The contact's contact tags. Integration tags are not listed.
Show child attributes
Show child attributes
Custom field values as strings, keyed by the field name from List contact fields.
Show child attributes
Show child attributes
{ "Segment": "enterprise" }
The user who owns the contact.
"7"
Where the contact came from. Contacts created through this API have api. Read-only.
"api"
Time of the last change. It moves on changes made through this API, the Dashboard contact form and CSV import. Dashboard bulk edits, CRM list sync, and renaming or deleting a contact tag do not move it.
Link to the contact's page in the CloudTalk Dashboard. It carries no credentials: the person must be signed in to your company's Dashboard, and your company must have Contacts in its menu, otherwise the Dashboard opens their default page. Read-only.
"https://dashboard.cloudtalk.io/menu/contacts/details/44210"