curl --request POST \
--url https://api.prod.usesimple.ai/api/v1/contacts/upsert \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"source": {
"key": "salesforce",
"name": "Salesforce",
"provider": "salesforce"
},
"fields": {
"name": {
"label": "Name",
"type": "text"
},
"email": {
"label": "Email",
"type": "email"
},
"phone_number": {
"label": "Phone number",
"type": "phone"
},
"lifecycle_stage": {
"label": "Lifecycle stage",
"description": "Current Salesforce lifecycle stage",
"type": "enum",
"enumOptions": [
"lead",
"customer"
]
}
},
"externalId": "lead-42",
"name": "Ada Lovelace",
"email": "ada@example.com",
"phoneNumber": "+14155550100",
"attributes": {
"lifecycle_stage": "lead"
}
}
'import requests
url = "https://api.prod.usesimple.ai/api/v1/contacts/upsert"
payload = {
"source": {
"key": "salesforce",
"name": "Salesforce",
"provider": "salesforce"
},
"fields": {
"name": {
"label": "Name",
"type": "text"
},
"email": {
"label": "Email",
"type": "email"
},
"phone_number": {
"label": "Phone number",
"type": "phone"
},
"lifecycle_stage": {
"label": "Lifecycle stage",
"description": "Current Salesforce lifecycle stage",
"type": "enum",
"enumOptions": ["lead", "customer"]
}
},
"externalId": "lead-42",
"name": "Ada Lovelace",
"email": "ada@example.com",
"phoneNumber": "+14155550100",
"attributes": { "lifecycle_stage": "lead" }
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
source: {key: 'salesforce', name: 'Salesforce', provider: 'salesforce'},
fields: {
name: {label: 'Name', type: 'text'},
email: {label: 'Email', type: 'email'},
phone_number: {label: 'Phone number', type: 'phone'},
lifecycle_stage: {
label: 'Lifecycle stage',
description: 'Current Salesforce lifecycle stage',
type: 'enum',
enumOptions: ['lead', 'customer']
}
},
externalId: 'lead-42',
name: 'Ada Lovelace',
email: 'ada@example.com',
phoneNumber: '+14155550100',
attributes: {lifecycle_stage: 'lead'}
})
};
fetch('https://api.prod.usesimple.ai/api/v1/contacts/upsert', 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.prod.usesimple.ai/api/v1/contacts/upsert",
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([
'source' => [
'key' => 'salesforce',
'name' => 'Salesforce',
'provider' => 'salesforce'
],
'fields' => [
'name' => [
'label' => 'Name',
'type' => 'text'
],
'email' => [
'label' => 'Email',
'type' => 'email'
],
'phone_number' => [
'label' => 'Phone number',
'type' => 'phone'
],
'lifecycle_stage' => [
'label' => 'Lifecycle stage',
'description' => 'Current Salesforce lifecycle stage',
'type' => 'enum',
'enumOptions' => [
'lead',
'customer'
]
]
],
'externalId' => 'lead-42',
'name' => 'Ada Lovelace',
'email' => 'ada@example.com',
'phoneNumber' => '+14155550100',
'attributes' => [
'lifecycle_stage' => 'lead'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"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.prod.usesimple.ai/api/v1/contacts/upsert"
payload := strings.NewReader("{\n \"source\": {\n \"key\": \"salesforce\",\n \"name\": \"Salesforce\",\n \"provider\": \"salesforce\"\n },\n \"fields\": {\n \"name\": {\n \"label\": \"Name\",\n \"type\": \"text\"\n },\n \"email\": {\n \"label\": \"Email\",\n \"type\": \"email\"\n },\n \"phone_number\": {\n \"label\": \"Phone number\",\n \"type\": \"phone\"\n },\n \"lifecycle_stage\": {\n \"label\": \"Lifecycle stage\",\n \"description\": \"Current Salesforce lifecycle stage\",\n \"type\": \"enum\",\n \"enumOptions\": [\n \"lead\",\n \"customer\"\n ]\n }\n },\n \"externalId\": \"lead-42\",\n \"name\": \"Ada Lovelace\",\n \"email\": \"ada@example.com\",\n \"phoneNumber\": \"+14155550100\",\n \"attributes\": {\n \"lifecycle_stage\": \"lead\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
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.prod.usesimple.ai/api/v1/contacts/upsert")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"source\": {\n \"key\": \"salesforce\",\n \"name\": \"Salesforce\",\n \"provider\": \"salesforce\"\n },\n \"fields\": {\n \"name\": {\n \"label\": \"Name\",\n \"type\": \"text\"\n },\n \"email\": {\n \"label\": \"Email\",\n \"type\": \"email\"\n },\n \"phone_number\": {\n \"label\": \"Phone number\",\n \"type\": \"phone\"\n },\n \"lifecycle_stage\": {\n \"label\": \"Lifecycle stage\",\n \"description\": \"Current Salesforce lifecycle stage\",\n \"type\": \"enum\",\n \"enumOptions\": [\n \"lead\",\n \"customer\"\n ]\n }\n },\n \"externalId\": \"lead-42\",\n \"name\": \"Ada Lovelace\",\n \"email\": \"ada@example.com\",\n \"phoneNumber\": \"+14155550100\",\n \"attributes\": {\n \"lifecycle_stage\": \"lead\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.prod.usesimple.ai/api/v1/contacts/upsert")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"source\": {\n \"key\": \"salesforce\",\n \"name\": \"Salesforce\",\n \"provider\": \"salesforce\"\n },\n \"fields\": {\n \"name\": {\n \"label\": \"Name\",\n \"type\": \"text\"\n },\n \"email\": {\n \"label\": \"Email\",\n \"type\": \"email\"\n },\n \"phone_number\": {\n \"label\": \"Phone number\",\n \"type\": \"phone\"\n },\n \"lifecycle_stage\": {\n \"label\": \"Lifecycle stage\",\n \"description\": \"Current Salesforce lifecycle stage\",\n \"type\": \"enum\",\n \"enumOptions\": [\n \"lead\",\n \"customer\"\n ]\n }\n },\n \"externalId\": \"lead-42\",\n \"name\": \"Ada Lovelace\",\n \"email\": \"ada@example.com\",\n \"phoneNumber\": \"+14155550100\",\n \"attributes\": {\n \"lifecycle_stage\": \"lead\"\n }\n}"
response = http.request(request)
puts response.read_body{
"contact": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"email": "jsmith@example.com",
"phoneNumber": "<string>",
"attributes": {},
"derivedAttributes": {},
"externalIdentities": [
{
"sourceKey": "<string>",
"externalId": "<string>"
}
]
},
"created": true,
"linked": true
}{
"contact": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"email": "jsmith@example.com",
"phoneNumber": "<string>",
"attributes": {},
"derivedAttributes": {},
"externalIdentities": [
{
"sourceKey": "<string>",
"externalId": "<string>"
}
]
},
"created": true,
"linked": true
}{
"status": "<string>",
"success": true,
"error": "<string>",
"errors": [
"<string>"
]
}{
"status": "<string>",
"success": true,
"error": "<string>",
"errors": [
"<string>"
]
}{
"status": "<string>",
"success": true,
"error": "<string>",
"errors": [
"<string>"
]
}Upsert Synced Contact
Create or update a contact from a CRM or another external source
curl --request POST \
--url https://api.prod.usesimple.ai/api/v1/contacts/upsert \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"source": {
"key": "salesforce",
"name": "Salesforce",
"provider": "salesforce"
},
"fields": {
"name": {
"label": "Name",
"type": "text"
},
"email": {
"label": "Email",
"type": "email"
},
"phone_number": {
"label": "Phone number",
"type": "phone"
},
"lifecycle_stage": {
"label": "Lifecycle stage",
"description": "Current Salesforce lifecycle stage",
"type": "enum",
"enumOptions": [
"lead",
"customer"
]
}
},
"externalId": "lead-42",
"name": "Ada Lovelace",
"email": "ada@example.com",
"phoneNumber": "+14155550100",
"attributes": {
"lifecycle_stage": "lead"
}
}
'import requests
url = "https://api.prod.usesimple.ai/api/v1/contacts/upsert"
payload = {
"source": {
"key": "salesforce",
"name": "Salesforce",
"provider": "salesforce"
},
"fields": {
"name": {
"label": "Name",
"type": "text"
},
"email": {
"label": "Email",
"type": "email"
},
"phone_number": {
"label": "Phone number",
"type": "phone"
},
"lifecycle_stage": {
"label": "Lifecycle stage",
"description": "Current Salesforce lifecycle stage",
"type": "enum",
"enumOptions": ["lead", "customer"]
}
},
"externalId": "lead-42",
"name": "Ada Lovelace",
"email": "ada@example.com",
"phoneNumber": "+14155550100",
"attributes": { "lifecycle_stage": "lead" }
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
source: {key: 'salesforce', name: 'Salesforce', provider: 'salesforce'},
fields: {
name: {label: 'Name', type: 'text'},
email: {label: 'Email', type: 'email'},
phone_number: {label: 'Phone number', type: 'phone'},
lifecycle_stage: {
label: 'Lifecycle stage',
description: 'Current Salesforce lifecycle stage',
type: 'enum',
enumOptions: ['lead', 'customer']
}
},
externalId: 'lead-42',
name: 'Ada Lovelace',
email: 'ada@example.com',
phoneNumber: '+14155550100',
attributes: {lifecycle_stage: 'lead'}
})
};
fetch('https://api.prod.usesimple.ai/api/v1/contacts/upsert', 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.prod.usesimple.ai/api/v1/contacts/upsert",
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([
'source' => [
'key' => 'salesforce',
'name' => 'Salesforce',
'provider' => 'salesforce'
],
'fields' => [
'name' => [
'label' => 'Name',
'type' => 'text'
],
'email' => [
'label' => 'Email',
'type' => 'email'
],
'phone_number' => [
'label' => 'Phone number',
'type' => 'phone'
],
'lifecycle_stage' => [
'label' => 'Lifecycle stage',
'description' => 'Current Salesforce lifecycle stage',
'type' => 'enum',
'enumOptions' => [
'lead',
'customer'
]
]
],
'externalId' => 'lead-42',
'name' => 'Ada Lovelace',
'email' => 'ada@example.com',
'phoneNumber' => '+14155550100',
'attributes' => [
'lifecycle_stage' => 'lead'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"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.prod.usesimple.ai/api/v1/contacts/upsert"
payload := strings.NewReader("{\n \"source\": {\n \"key\": \"salesforce\",\n \"name\": \"Salesforce\",\n \"provider\": \"salesforce\"\n },\n \"fields\": {\n \"name\": {\n \"label\": \"Name\",\n \"type\": \"text\"\n },\n \"email\": {\n \"label\": \"Email\",\n \"type\": \"email\"\n },\n \"phone_number\": {\n \"label\": \"Phone number\",\n \"type\": \"phone\"\n },\n \"lifecycle_stage\": {\n \"label\": \"Lifecycle stage\",\n \"description\": \"Current Salesforce lifecycle stage\",\n \"type\": \"enum\",\n \"enumOptions\": [\n \"lead\",\n \"customer\"\n ]\n }\n },\n \"externalId\": \"lead-42\",\n \"name\": \"Ada Lovelace\",\n \"email\": \"ada@example.com\",\n \"phoneNumber\": \"+14155550100\",\n \"attributes\": {\n \"lifecycle_stage\": \"lead\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
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.prod.usesimple.ai/api/v1/contacts/upsert")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"source\": {\n \"key\": \"salesforce\",\n \"name\": \"Salesforce\",\n \"provider\": \"salesforce\"\n },\n \"fields\": {\n \"name\": {\n \"label\": \"Name\",\n \"type\": \"text\"\n },\n \"email\": {\n \"label\": \"Email\",\n \"type\": \"email\"\n },\n \"phone_number\": {\n \"label\": \"Phone number\",\n \"type\": \"phone\"\n },\n \"lifecycle_stage\": {\n \"label\": \"Lifecycle stage\",\n \"description\": \"Current Salesforce lifecycle stage\",\n \"type\": \"enum\",\n \"enumOptions\": [\n \"lead\",\n \"customer\"\n ]\n }\n },\n \"externalId\": \"lead-42\",\n \"name\": \"Ada Lovelace\",\n \"email\": \"ada@example.com\",\n \"phoneNumber\": \"+14155550100\",\n \"attributes\": {\n \"lifecycle_stage\": \"lead\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.prod.usesimple.ai/api/v1/contacts/upsert")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"source\": {\n \"key\": \"salesforce\",\n \"name\": \"Salesforce\",\n \"provider\": \"salesforce\"\n },\n \"fields\": {\n \"name\": {\n \"label\": \"Name\",\n \"type\": \"text\"\n },\n \"email\": {\n \"label\": \"Email\",\n \"type\": \"email\"\n },\n \"phone_number\": {\n \"label\": \"Phone number\",\n \"type\": \"phone\"\n },\n \"lifecycle_stage\": {\n \"label\": \"Lifecycle stage\",\n \"description\": \"Current Salesforce lifecycle stage\",\n \"type\": \"enum\",\n \"enumOptions\": [\n \"lead\",\n \"customer\"\n ]\n }\n },\n \"externalId\": \"lead-42\",\n \"name\": \"Ada Lovelace\",\n \"email\": \"ada@example.com\",\n \"phoneNumber\": \"+14155550100\",\n \"attributes\": {\n \"lifecycle_stage\": \"lead\"\n }\n}"
response = http.request(request)
puts response.read_body{
"contact": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"email": "jsmith@example.com",
"phoneNumber": "<string>",
"attributes": {},
"derivedAttributes": {},
"externalIdentities": [
{
"sourceKey": "<string>",
"externalId": "<string>"
}
]
},
"created": true,
"linked": true
}{
"contact": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"email": "jsmith@example.com",
"phoneNumber": "<string>",
"attributes": {},
"derivedAttributes": {},
"externalIdentities": [
{
"sourceKey": "<string>",
"externalId": "<string>"
}
]
},
"created": true,
"linked": true
}{
"status": "<string>",
"success": true,
"error": "<string>",
"errors": [
"<string>"
]
}{
"status": "<string>",
"success": true,
"error": "<string>",
"errors": [
"<string>"
]
}{
"status": "<string>",
"success": true,
"error": "<string>",
"errors": [
"<string>"
]
}source.key and externalId is the durable sync identity. The first request can define the source, its fields, and the contact in one operation. Later requests can omit fields unless the source schema changes.
Define fields
Field keys use lowercase snake case. Supported types aretext, number, boolean, date, enum, url, email, and phone.
Define the system field keys before sending their top-level values:
nameusestextemailusesemailphone_numberusesphone
attributes must have a field definition owned by the same source. Dates use ISO 8601 datetime strings. Enum values must match one of the field’s enumOptions.
Apply sparse updates
Omitted contact properties and attribute keys remain unchanged. Send an explicitnull to clear a top-level value or attribute. The API does not treat missing contacts as deletions.
Link another source
Usematch.email or match.phoneNumber to attach a new external identity to an existing contact. Match values are lookup-only and do not update the contact.
A match succeeds only when the value identifies one contact. Ambiguous matches, or email and phone resolving to different contacts, return 409 Conflict.
Use with Zapier
Create a Webhooks by Zapier action that sends aPOST request to:
https://api.usesimple.ai/api/v1/contacts/upsert
Authorization: Bearer YOUR_API_KEY and Content-Type: application/json headers, then map the CRM fields into the request body shown in the example.Authorizations
Body
Show child attributes
Show child attributes
Stable contact identifier from the external source.
1 - 1000Field definitions owned by this source. Include them when first used or when labels, descriptions, or enum options change. Define name, email, and phone_number before sending their corresponding top-level values.
Show child attributes
Show child attributes
Contact name. Omit to leave unchanged or send null to clear it.
1 - 255Contact email. Omit to leave unchanged or send null to clear it.
Contact phone number. Omit to leave unchanged or send null to clear it.
1 - 255Show child attributes
Show child attributes
Values for non-system fields defined by this source. Values must match their field type. Omit a key to leave it unchanged or send null to clear it.
Response
The existing contact was updated or linked to the supplied external identity.
Was this page helpful?