curl --request PATCH \
--url https://api.cloudtalk.io/v1/contacts/{contactId} \
--header 'Authorization: Basic <encoded-value>' \
--header 'Content-Type: application/json' \
--data '
{
"title": "VP Procurement",
"website": null,
"customFields": {
"Segment": "mid-market",
"Legacy ID": null
}
}
'import requests
url = "https://api.cloudtalk.io/v1/contacts/{contactId}"
payload = {
"title": "VP Procurement",
"website": None,
"customFields": {
"Segment": "mid-market",
"Legacy ID": None
}
}
headers = {
"Authorization": "Basic <encoded-value>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Basic <encoded-value>', 'Content-Type': 'application/json'},
body: JSON.stringify({
title: 'VP Procurement',
website: null,
customFields: {Segment: 'mid-market', 'Legacy ID': null}
})
};
fetch('https://api.cloudtalk.io/v1/contacts/{contactId}', 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/{contactId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'title' => 'VP Procurement',
'website' => null,
'customFields' => [
'Segment' => 'mid-market',
'Legacy ID' => null
]
]),
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/{contactId}"
payload := strings.NewReader("{\n \"title\": \"VP Procurement\",\n \"website\": null,\n \"customFields\": {\n \"Segment\": \"mid-market\",\n \"Legacy ID\": null\n }\n}")
req, _ := http.NewRequest("PATCH", 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.patch("https://api.cloudtalk.io/v1/contacts/{contactId}")
.header("Authorization", "Basic <encoded-value>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"VP Procurement\",\n \"website\": null,\n \"customFields\": {\n \"Segment\": \"mid-market\",\n \"Legacy ID\": null\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cloudtalk.io/v1/contacts/{contactId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Basic <encoded-value>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"title\": \"VP Procurement\",\n \"website\": null,\n \"customFields\": {\n \"Segment\": \"mid-market\",\n \"Legacy ID\": null\n }\n}"
response = http.request(request)
puts response.read_body{
"id": "44210",
"type": "contact",
"name": "Jane Doe",
"title": "VP Procurement",
"company": "Acme Inc.",
"industry": "Manufacturing",
"website": null,
"address": "1 Market Street",
"city": "San Francisco",
"state": "CA",
"zip": "94105",
"country": {
"code": "US",
"name": "United States"
},
"phones": [
"+12025550143",
"+13105550166"
],
"emails": [
"[email protected]"
],
"tags": [
{
"id": "123",
"name": "vip",
"readOnly": false
}
],
"customFields": {
"Segment": "mid-market"
},
"favoriteUserId": "7",
"source": "api",
"createdAt": "2026-08-17T09:34:21Z",
"updatedAt": "2026-11-02T10:20:00Z",
"dashboardUrl": "https://dashboard.cloudtalk.io/menu/contacts/details/44210"
}{
"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>"
}{
"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>"
}Update a contact
Updates only the fields you send. Fields you leave out stay unchanged, and null clears a field that can be null.
phonesandemailsreplace the whole list when sent.customFieldsmerges by key: keys you send are set, a key sent asnullis removed, and other keys stay. Two requests that change different keys at the same time both apply.- Tags change only through Add tags to a contact and Remove tags from a contact. A
tagsfield is rejected as an unknown field. - A lead can become a contact. A contact cannot become a lead.
- When two requests change the same contact at the same time, the last write wins.
- Text fields are cleaned up before their length is checked and they are stored, as on Create a contact: 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,zipand custom field values, not to emails or phone numbers.
A request that changes nothing returns 200 with the contact and sends no webhook. Otherwise contact.updated is sent, and CloudTalk exports the change to your active CRM integrations.
curl --request PATCH \
--url https://api.cloudtalk.io/v1/contacts/{contactId} \
--header 'Authorization: Basic <encoded-value>' \
--header 'Content-Type: application/json' \
--data '
{
"title": "VP Procurement",
"website": null,
"customFields": {
"Segment": "mid-market",
"Legacy ID": null
}
}
'import requests
url = "https://api.cloudtalk.io/v1/contacts/{contactId}"
payload = {
"title": "VP Procurement",
"website": None,
"customFields": {
"Segment": "mid-market",
"Legacy ID": None
}
}
headers = {
"Authorization": "Basic <encoded-value>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Basic <encoded-value>', 'Content-Type': 'application/json'},
body: JSON.stringify({
title: 'VP Procurement',
website: null,
customFields: {Segment: 'mid-market', 'Legacy ID': null}
})
};
fetch('https://api.cloudtalk.io/v1/contacts/{contactId}', 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/{contactId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'title' => 'VP Procurement',
'website' => null,
'customFields' => [
'Segment' => 'mid-market',
'Legacy ID' => null
]
]),
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/{contactId}"
payload := strings.NewReader("{\n \"title\": \"VP Procurement\",\n \"website\": null,\n \"customFields\": {\n \"Segment\": \"mid-market\",\n \"Legacy ID\": null\n }\n}")
req, _ := http.NewRequest("PATCH", 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.patch("https://api.cloudtalk.io/v1/contacts/{contactId}")
.header("Authorization", "Basic <encoded-value>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"VP Procurement\",\n \"website\": null,\n \"customFields\": {\n \"Segment\": \"mid-market\",\n \"Legacy ID\": null\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cloudtalk.io/v1/contacts/{contactId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Basic <encoded-value>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"title\": \"VP Procurement\",\n \"website\": null,\n \"customFields\": {\n \"Segment\": \"mid-market\",\n \"Legacy ID\": null\n }\n}"
response = http.request(request)
puts response.read_body{
"id": "44210",
"type": "contact",
"name": "Jane Doe",
"title": "VP Procurement",
"company": "Acme Inc.",
"industry": "Manufacturing",
"website": null,
"address": "1 Market Street",
"city": "San Francisco",
"state": "CA",
"zip": "94105",
"country": {
"code": "US",
"name": "United States"
},
"phones": [
"+12025550143",
"+13105550166"
],
"emails": [
"[email protected]"
],
"tags": [
{
"id": "123",
"name": "vip",
"readOnly": false
}
],
"customFields": {
"Segment": "mid-market"
},
"favoriteUserId": "7",
"source": "api",
"createdAt": "2026-08-17T09:34:21Z",
"updatedAt": "2026-11-02T10:20:00Z",
"dashboardUrl": "https://dashboard.cloudtalk.io/menu/contacts/details/44210"
}{
"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>"
}{
"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).
Path Parameters
The contact id.
"44210"
Body
At least one field. Leave a field out to keep it; send null to clear a field that can be null.
Cannot be null.
1 - 150Only contact, which turns a lead into a contact. A contact cannot become a lead. Cannot be null.
contact null clears the field.
255null clears the field.
100null clears the field.
100null clears the field.
100null clears the field.
255null clears the field.
255null clears the field.
255null clears the field.
15ISO 3166-1 alpha-2. Cannot be null.
Replaces the whole list. Up to 20, in E.164.
20Replaces the whole list. Up to 20.
20Merged by key: keys you send are set, a key sent as null is removed, and other keys stay. At most 100 keys, removals included.
Show child attributes
Show child attributes
null clears the owner.
Response
The updated contact.
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"