curl -X POST https://api.guayaba.ai/contacts \
-H "Content-Type: application/json" \
-H "X-API-Key: gua_a1b2c3d4_your-api-key-here" \
-d '{
"phoneNumber": "+15551234567",
"name": "Jane Smith",
"splitterId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"customVariables": {
"company": "Acme Corp",
"leadSource": "website",
"loanAmount": "50000"
}
}'
const response = await fetch('https://api.guayaba.ai/contacts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'gua_a1b2c3d4_your-api-key-here'
},
body: JSON.stringify({
phoneNumber: '+15551234567',
name: 'Jane Smith',
splitterId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
customVariables: {
company: 'Acme Corp',
leadSource: 'website',
loanAmount: '50000'
}
})
});
const data = await response.json();
import requests
response = requests.post(
'https://api.guayaba.ai/contacts',
headers={
'Content-Type': 'application/json',
'X-API-Key': 'gua_a1b2c3d4_your-api-key-here'
},
json={
'phoneNumber': '+15551234567',
'name': 'Jane Smith',
'splitterId': 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
'customVariables': {
'company': 'Acme Corp',
'leadSource': 'website',
'loanAmount': '50000'
}
}
)
data = response.json()
{
"success": true,
"data": {
"id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"adminId": "8f14e45f-ceea-467a-9575-d0e9e3c8b8a3",
"campaignId": "550e8400-e29b-41d4-a716-446655440000",
"phoneNumber": "+15551234567",
"name": "Jane Smith",
"timezone": "America/New_York",
"status": "active",
"customVariables": {
"company": "Acme Corp",
"leadSource": "website",
"loanAmount": "50000"
},
"createdAt": "2026-05-13T14:30:00.000Z",
"updatedAt": "2026-05-13T14:30:00.000Z"
}
}
{
"error": "Bad Request",
"message": "Splitter distribution failed: Splitter has no active campaigns"
}
{
"error": "Not found",
"message": "Splitter not found or inactive"
}
Splitters
Send Contact to Splitter
Send a contact into a splitter, which routes them to one of its underlying campaigns.
POST
/
contacts
curl -X POST https://api.guayaba.ai/contacts \
-H "Content-Type: application/json" \
-H "X-API-Key: gua_a1b2c3d4_your-api-key-here" \
-d '{
"phoneNumber": "+15551234567",
"name": "Jane Smith",
"splitterId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"customVariables": {
"company": "Acme Corp",
"leadSource": "website",
"loanAmount": "50000"
}
}'
const response = await fetch('https://api.guayaba.ai/contacts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'gua_a1b2c3d4_your-api-key-here'
},
body: JSON.stringify({
phoneNumber: '+15551234567',
name: 'Jane Smith',
splitterId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
customVariables: {
company: 'Acme Corp',
leadSource: 'website',
loanAmount: '50000'
}
})
});
const data = await response.json();
import requests
response = requests.post(
'https://api.guayaba.ai/contacts',
headers={
'Content-Type': 'application/json',
'X-API-Key': 'gua_a1b2c3d4_your-api-key-here'
},
json={
'phoneNumber': '+15551234567',
'name': 'Jane Smith',
'splitterId': 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
'customVariables': {
'company': 'Acme Corp',
'leadSource': 'website',
'loanAmount': '50000'
}
}
)
data = response.json()
{
"success": true,
"data": {
"id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"adminId": "8f14e45f-ceea-467a-9575-d0e9e3c8b8a3",
"campaignId": "550e8400-e29b-41d4-a716-446655440000",
"phoneNumber": "+15551234567",
"name": "Jane Smith",
"timezone": "America/New_York",
"status": "active",
"customVariables": {
"company": "Acme Corp",
"leadSource": "website",
"loanAmount": "50000"
},
"createdAt": "2026-05-13T14:30:00.000Z",
"updatedAt": "2026-05-13T14:30:00.000Z"
}
}
{
"error": "Bad Request",
"message": "Splitter distribution failed: Splitter has no active campaigns"
}
{
"error": "Not found",
"message": "Splitter not found or inactive"
}
Send a contact to a splitter and let it pick which campaign to enroll them in. This uses the same
Same fields, same behavior. Custom variables can be sent as flat top-level fields — Zapier transform middleware will nest them into
POST /contacts endpoint as Create Contact — the only difference is that you send splitterId instead of campaignId.
All splitter management (create, update, stats, distribution strategies) is handled by admins in the dashboard. This endpoint is the only one integrators need.
Request Body
string
required
Phone number in E.164 format (e.g.,
+15551234567).string (UUID)
required
The ID of the splitter to route this contact through.
Send either
splitterId or campaignId, not both. If both are provided, campaignId takes priority and the splitter is ignored.string
Full name of the contact.
object
Flat key-value pairs of custom data to store on the contact. All values must be strings — send numbers as
"50000", not 50000.These variables are passed to the assigned campaign and available for template substitution in SMS, WhatsApp templates, and voice agent prompts as {{company}}, {{leadSource}}, etc.Authentication
Either method works:- JWT token:
Authorization: Bearer <jwt-token> - API key:
X-API-Key: <api-key>— rate limited to 30 writes per minute.
What happens after the contact is created
- The splitter picks a campaign based on its distribution strategy (percentage, time-weighted, or adaptive).
- The contact is created in the chosen campaign with all provided
customVariables. - The distribution decision is logged (visible in the splitter’s Distribution Logs in the dashboard).
- The campaign’s schedule kicks in — calls, SMS, and WhatsApp are scheduled based on that campaign’s configuration.
customVariablesare available for template substitution in all outbound messages.
Existing contacts
If a contact with the same phone number already exists for this admin:- If active: the contact is updated with the new name and
customVariables, then reassigned to the splitter’s chosen campaign. Existing scheduled calls, SMS, and WhatsApp are cancelled and rescheduled. - If soft-deleted: the contact is reactivated with the new data and assigned to the splitter’s chosen campaign.
campaignId contact creation.
Response
boolean
Always
true on a successful request.object
The created or updated contact object.
Show Contact fields
Show Contact fields
string (UUID)
Unique identifier for the contact.
string (UUID)
The admin (team) the contact belongs to.
string (UUID)
The campaign the splitter assigned this contact to. The contact now lives in this campaign and follows its schedule normally.
string
Phone number in E.164 format.
string
Contact name.
string
IANA timezone string.
string
Contact status. Newly created contacts start as
active.object
Custom key-value data stored on the contact.
string (ISO 8601)
Timestamp of when the contact was created.
string (ISO 8601)
Timestamp of the last update.
Errors
| Status | Error | When |
|---|---|---|
400 | Splitter distribution failed: Splitter has no active campaigns | All campaigns in the splitter are deactivated. |
400 | Splitter distribution failed: No valid campaigns found in splitter | All campaigns in the splitter were deleted. |
400 | Invalid phone number | Phone number format is invalid or not in allowed country codes. |
404 | Splitter not found or inactive | Splitter doesn’t exist, was deleted, or is paused. |
429 | Rate limit exceeded | More than 30 requests/minute with API key auth. |
Zapier
The Zapier endpoint also supports splitters:POST /contacts/zapier
customVariables automatically.
curl -X POST https://api.guayaba.ai/contacts \
-H "Content-Type: application/json" \
-H "X-API-Key: gua_a1b2c3d4_your-api-key-here" \
-d '{
"phoneNumber": "+15551234567",
"name": "Jane Smith",
"splitterId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"customVariables": {
"company": "Acme Corp",
"leadSource": "website",
"loanAmount": "50000"
}
}'
const response = await fetch('https://api.guayaba.ai/contacts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'gua_a1b2c3d4_your-api-key-here'
},
body: JSON.stringify({
phoneNumber: '+15551234567',
name: 'Jane Smith',
splitterId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
customVariables: {
company: 'Acme Corp',
leadSource: 'website',
loanAmount: '50000'
}
})
});
const data = await response.json();
import requests
response = requests.post(
'https://api.guayaba.ai/contacts',
headers={
'Content-Type': 'application/json',
'X-API-Key': 'gua_a1b2c3d4_your-api-key-here'
},
json={
'phoneNumber': '+15551234567',
'name': 'Jane Smith',
'splitterId': 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
'customVariables': {
'company': 'Acme Corp',
'leadSource': 'website',
'loanAmount': '50000'
}
}
)
data = response.json()
{
"success": true,
"data": {
"id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"adminId": "8f14e45f-ceea-467a-9575-d0e9e3c8b8a3",
"campaignId": "550e8400-e29b-41d4-a716-446655440000",
"phoneNumber": "+15551234567",
"name": "Jane Smith",
"timezone": "America/New_York",
"status": "active",
"customVariables": {
"company": "Acme Corp",
"leadSource": "website",
"loanAmount": "50000"
},
"createdAt": "2026-05-13T14:30:00.000Z",
"updatedAt": "2026-05-13T14:30:00.000Z"
}
}
{
"error": "Bad Request",
"message": "Splitter distribution failed: Splitter has no active campaigns"
}
{
"error": "Not found",
"message": "Splitter not found or inactive"
}