Integrations
Send contacts from your CRM
Instead of uploading a list, let your CRM, website form or automation tool push contacts into a workflow the moment they appear. Each contact you send is queued and called by the workflow's AI employee, inside its calling hours.
How it works
A workflow that starts from an API Trigger step has its own URL. Once you press Start calling on the workflow, it stays open and waits for contacts. Every POST to that URL adds one or more contacts to the queue. The workflow keeps waiting until you stop it.
Set it up
Create an API key
Create a key in the dashboard. See Create an API key. The key must have write access. A read-only key gets
403 This API key is read-only.Start the workflow from an API Trigger
In the workflow builder, pick API Trigger as the contact source. Click the step to see the workflow's trigger URL and a ready-made
curlexample. The workflow ID is the part of the URL between/workflows/and/trigger.Press Start calling
Until the workflow is live, the endpoint answers
409. After you press Start calling, it accepts contacts until you stop the workflow.Send contacts
Call the endpoint from your CRM, backend or automation tool, as in the examples below.
The endpoint
/workflows/{workflow_id}/triggerhttps://calling.ubiqproject.com/api/v1/workflows/{workflow_id}/trigger · Auth: API key
Authenticate with X-API-Key: vk_… or Authorization: Bearer vk_…. Full details are in Authentication and the API reference.
Body (JSON) — send one of these
contactobjectphone (or phone_number).contactsobject[]contact and contacts; they are combined.Contact fields
phonestringrequired+ followed by 8–15 digits, e.g. +919876543210. A leading 00 is turned into +, and spaces and dashes are removed when the number starts with + or 00. Numbers without a country code are rejected. phone_number is accepted as an alternative key.namestringany other keystringloan_id, amount_due, city — is stored with the contact and can be used in the script as a {{placeholder}}, e.g. {{amount_due}}. Values are stored as text. Keys starting with _ are dropped.One contact
curl -X POST "https://calling.ubiqproject.com/api/v1/workflows/WORKFLOW_ID/trigger" \
-H "X-API-Key: vk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"contact": {
"name": "Rahul Sharma",
"phone": "+919876543210",
"loan_id": "LN-20417",
"amount_due": "4,500"
}
}'Several contacts
curl -X POST "https://calling.ubiqproject.com/api/v1/workflows/WORKFLOW_ID/trigger" \
-H "Authorization: Bearer vk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"contacts": [
{ "name": "Rahul Sharma", "phone": "+919876543210", "city": "Pune" },
{ "name": "Priya Nair", "phone": "00919812345678", "city": "Kochi" },
{ "name": "Amit Verma", "phone": "98111 22233", "city": "Delhi" }
]
}'Response
200 OK means the request was accepted. Check the body: some rows may still have been rejected or filtered out. In this example, the third number has no country code.
{
"queued": 2,
"skipped_by_filter": 0,
"invalid": [2],
"detail": "Invalid rows need an international phone number, e.g. +919876543210."
}Response fields
queuedintegerskipped_by_filterintegerinvalidinteger[]contact and contacts, contact is position 0.detailstring | nullnull.Node.js
// Node 18+ — e.g. inside your CRM's "lead created" hook
const res = await fetch(
`https://calling.ubiqproject.com/api/v1/workflows/${process.env.UBIQ_WORKFLOW_ID}/trigger`,
{
method: "POST",
headers: {
"X-API-Key": process.env.UBIQ_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
contact: { name: "Rahul Sharma", phone: "+919876543210", source: "website-form" },
}),
},
);
const out = await res.json();
if (!res.ok) throw new Error(`Daffy Voice ${res.status}: ${out.detail}`);
console.log(`queued ${out.queued}, invalid rows: ${out.invalid.join(", ") || "none"}`);Python
import os
import requests
r = requests.post(
f"https://calling.ubiqproject.com/api/v1/workflows/{os.environ['UBIQ_WORKFLOW_ID']}/trigger",
headers={"X-API-Key": os.environ["UBIQ_API_KEY"]},
json={"contacts": [
{"name": "Rahul Sharma", "phone": "+919876543210", "plan": "Gold"},
{"name": "Priya Nair", "phone": "+919812345678", "plan": "Silver"},
]},
timeout=30,
)
out = r.json()
if not r.ok:
raise RuntimeError(f"Daffy Voice {r.status_code}: {out['detail']}")
print(out["queued"], "queued;", len(out["invalid"]), "invalid")Errors
Errors return JSON with a detail message.
Status codes
401UnauthorizedNot authenticated (no key) or Invalid API key.403ForbiddenThis API key is read-only — use a key with write access.404Not foundWorkflow not found — wrong ID, or the workflow belongs to another workspace.409ConflictThis workflow doesn't start from an API Trigger, or The workflow isn't calling — press Start calling on it first.413Too largeAt most 1000 contacts per request — split the list into batches.422Unprocessablecontact nor contacts, or isn't valid JSON.Duplicates are skipped while waiting
When calls happen