/api/v1/contracts/whatsapp-automationReturn the public WhatsApp automation contract version and emitted event types.
One API for structured and unstructured data, mobile-first contacts, communication history, WhatsApp, and Voice.
# CtrlLane beginner examples
#
# Run one section at a time. Commands use curl and jq and call the same v1 API
# used by the CtrlLane console. Sending a message or starting a call is a
# real, billable action. Use your own authorised test number.
## 1. Check access
# Confirm that the key and Business ID work.
# Required permissions: channels:read
# Result: Returns WhatsApp, Voice, and Instagram messaging as live channels. SMS remains reserved until its provider route is enabled.
# Run this in Terminal. Replace the API key and test mobile number.
command -v jq >/dev/null || { echo "Install jq first: https://jqlang.org/download/"; exit 1; }
export CP_BASE_URL="https://app.ctrllane.com"
read -rsp "Paste your CtrlLane API key: " CP_API_KEY; echo
export CP_API_KEY
export CP_BUSINESS_ID="paste_business_id_here"
export CP_TEST_MOBILE="+919999999999"
curl --fail-with-body --silent --show-error \
"$CP_BASE_URL/api/v1/channels?businessId=$CP_BUSINESS_ID" \
-H "Authorization: Bearer $CP_API_KEY" | jq
## 2. Create a contact
# Save a mobile-first customer in the native Contacts data source.
# Required permissions: contacts:write
# Result: Prints the new contact ID. Re-running the same commands is safe.
# Run this in Terminal. Replace the API key and test mobile number.
command -v jq >/dev/null || { echo "Install jq first: https://jqlang.org/download/"; exit 1; }
export CP_BASE_URL="https://app.ctrllane.com"
read -rsp "Paste your CtrlLane API key: " CP_API_KEY; echo
export CP_API_KEY
export CP_BUSINESS_ID="paste_business_id_here"
export CP_TEST_MOBILE="+919999999999"
# Contacts always belong to a category. This creates or reuses "API leads".
CATEGORY_ID=$(curl --fail-with-body --silent --show-error \
"$CP_BASE_URL/api/v1/contacts/categories" -X POST \
-H "Authorization: Bearer $CP_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: beginner-api-leads-category-v1" \
-d "$(jq -n --arg businessId "$CP_BUSINESS_ID" \
'{businessId: $businessId, name: "API leads"}')" | jq -er '.data.category.id')
CONTACT_ID=$(curl --fail-with-body --silent --show-error \
"$CP_BASE_URL/api/v1/contacts" -X POST \
-H "Authorization: Bearer $CP_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: beginner-contact-${CP_TEST_MOBILE//[^0-9]/}-v1" \
-d "$(jq -n \
--arg businessId "$CP_BUSINESS_ID" \
--arg mobile "$CP_TEST_MOBILE" \
--arg categoryId "$CATEGORY_ID" \
'{businessId: $businessId, name: "API test contact", mobile: $mobile, categoryIds: [$categoryId]}')" \
| jq -er '.data.contact.id')
echo "Contact created: $CONTACT_ID"
## 3. Send WhatsApp
# Find the connected number, send one message, and print its ID.
# Required permissions: channels:read, communications:write
# Result: Queues one real WhatsApp message. The same idempotency key never sends it twice.
# Run this in Terminal. Replace the API key and test mobile number.
command -v jq >/dev/null || { echo "Install jq first: https://jqlang.org/download/"; exit 1; }
export CP_BASE_URL="https://app.ctrllane.com"
read -rsp "Paste your CtrlLane API key: " CP_API_KEY; echo
export CP_API_KEY
export CP_BUSINESS_ID="paste_business_id_here"
export CP_TEST_MOBILE="+919999999999"
# CtrlLane discovers the Meta phone-number ID for this business.
PHONE_NUMBER_ID=$(curl --fail-with-body --silent --show-error \
"$CP_BASE_URL/api/v1/channels/assignments?businessId=$CP_BUSINESS_ID&channel=whatsapp" \
-H "Authorization: Bearer $CP_API_KEY" | jq -er '.data.phoneNumberId')
MESSAGE_ID=$(curl --fail-with-body --silent --show-error \
"$CP_BASE_URL/api/v1/messages" -X POST \
-H "Authorization: Bearer $CP_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: beginner-whatsapp-${CP_TEST_MOBILE//[^0-9]/}-v1" \
-d "$(jq -n \
--arg businessId "$CP_BUSINESS_ID" \
--arg phoneNumberId "$PHONE_NUMBER_ID" \
--arg to "$CP_TEST_MOBILE" \
'{businessId: $businessId, phoneNumberId: $phoneNumberId, to: $to, type: "text", text: "Hello from CtrlLane."}')" \
| jq -er '.data.messageId')
echo "Message queued: $MESSAGE_ID"
## 4. Start a voice call
# Find a compatible Voice agent and call the test number.
# Required permissions: agents:read, voice:write
# Result: Starts one real call and prints its call ID. Calling requires an active Voice agent and approved number.
# Run this in Terminal. Replace the API key and test mobile number.
command -v jq >/dev/null || { echo "Install jq first: https://jqlang.org/download/"; exit 1; }
export CP_BASE_URL="https://app.ctrllane.com"
read -rsp "Paste your CtrlLane API key: " CP_API_KEY; echo
export CP_API_KEY
export CP_BUSINESS_ID="paste_business_id_here"
export CP_TEST_MOBILE="+919999999999"
# Choose the newest active Voice agent that does not require contact variables.
AGENT_ID=$(curl --fail-with-body --silent --show-error \
"$CP_BASE_URL/api/v1/agents?businessId=$CP_BUSINESS_ID" \
-H "Authorization: Bearer $CP_API_KEY" \
| jq -er '[.data.agents[] | select(.channel == "voice" and .status == "active" and .contactContextRequired == false)] | first | .id')
CALL_ID=$(curl --fail-with-body --silent --show-error \
"$CP_BASE_URL/api/v1/voice/calls" -X POST \
-H "Authorization: Bearer $CP_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: beginner-call-${CP_TEST_MOBILE//[^0-9]/}-v1" \
-d "$(jq -n \
--arg businessId "$CP_BUSINESS_ID" \
--arg agentId "$AGENT_ID" \
--arg toNumber "$CP_TEST_MOBILE" \
'{businessId: $businessId, agentId: $agentId, toNumber: $toNumber}')" \
| jq -er '.data.callId')
echo "Call started: $CALL_ID"
## 5. Read contact history
# Find a contact and read its WhatsApp and Voice timeline.
# Required permissions: contacts:read, communications:read
# Result: Returns the newest messages, transcripts, and call outcomes stored for that contact.
# Run this in Terminal. Replace the API key and test mobile number.
command -v jq >/dev/null || { echo "Install jq first: https://jqlang.org/download/"; exit 1; }
export CP_BASE_URL="https://app.ctrllane.com"
read -rsp "Paste your CtrlLane API key: " CP_API_KEY; echo
export CP_API_KEY
export CP_BUSINESS_ID="paste_business_id_here"
export CP_TEST_MOBILE="+919999999999"
CONTACT_ID=$(curl --fail-with-body --silent --show-error \
"$CP_BASE_URL/api/v1/contacts?businessId=$CP_BUSINESS_ID&search=${CP_TEST_MOBILE//+/%2B}" \
-H "Authorization: Bearer $CP_API_KEY" \
| jq -er '.data.contacts | first | .id')
curl --fail-with-body --silent --show-error \
"$CP_BASE_URL/api/v1/contacts/$CONTACT_ID/timeline?businessId=$CP_BUSINESS_ID" \
-H "Authorization: Bearer $CP_API_KEY" | jq/api/v1/contracts/whatsapp-automationReturn the public WhatsApp automation contract version and emitted event types.
/api/v1/webhook-subscriptionsList tenant-scoped WhatsApp and Instagram webhook subscriptions without exposing signing secrets.
/api/v1/webhook-subscriptionsSubscribe an external automation backend to signed WhatsApp or Instagram messaging events.
/api/v1/webhook-subscriptions/{subscriptionId}Update callback URL, subscribed events, or active/paused state for a tenant-owned subscription.
/api/v1/webhook-subscriptions/{subscriptionId}Permanently revoke a tenant-owned webhook subscription.
/api/v1/webhook-subscriptions/{subscriptionId}/rotate-secretReplace the signing secret immediately and return the new secret once.
/api/v1/mediaUpload canonical base64 image bytes to Meta WhatsApp Media API and cache the provider media id.
/api/v1/messagesQueue a WhatsApp or Instagram message through CtrlLane.
/api/v1/messages/{messageId}Read authoritative message delivery state and provider timestamps.
/api/v1/channelsList channel keys, labels, live readiness, and assignment mode. WhatsApp and outbound Voice are live.
/api/v1/channels/instagramRead tenant-scoped Instagram professional account connection metadata without exposing its token.
/api/v1/channels/instagramRevoke CtrlLane use of the tenant Instagram connection and clear provider account assets.
/api/v1/agentsList business agents, stable reference names, and channel mapping.
/api/v1/agentsCreate an agent for WhatsApp, SMS, Voice, or Other. Attach Data Sources, contact categories, declared variables, and provider-neutral voice settings. WhatsApp can be assigned during creation.
/api/v1/agentsUpdate a tenant-owned agent using the same channel, prompt, Data Source, and voice-settings contract as creation.
/api/v1/agentsArchive a tenant-owned agent so it can no longer be selected for new conversations.
/api/v1/data-sourcesList the business's structured and unstructured Data Sources, including fields explicitly available for contact variables.
/api/v1/data-sourcesCreate a tenant structured table/JSON source or unstructured text Data Source.
/api/v1/data-sourcesUpdate Data Source metadata, status, or unstructured content.
/api/v1/data-sourcesArchive a tenant Data Source.
/api/v1/data-sources/uploadUpload a CSV, TSV, JSON, XLSX, or XLSM asset for lossless asynchronous ingestion into an immutable version.
/api/v1/data-sources/ingestionsInspect ingestion stages, immutable version status, validation issues, and columns requiring review.
/api/v1/data-sources/ingestionsSubmit reviewed column interpretations and atomically activate the validated version.
/api/v1/contactsList mobile-first tenant contacts with categories and communication rollups.
/api/v1/contactsCreate one mobile-first contact in a tenant-owned category.
/api/v1/contactsDelete selected tenant contacts or every contact in a tenant category.
/api/v1/contacts/importsImport structured CSV contact data into one or more tenant categories.
/api/v1/contacts/categoriesList tenant contact categories with cursor pagination and contact counts.
/api/v1/contacts/categoriesCreate a tenant contact category.
/api/v1/contacts/categoriesDelete a tenant category after explicit name confirmation.
/api/v1/contacts/{contactId}Read one contact with categories and per-channel activity rollups. When campaignId is supplied, include that campaign's shared contact summary.
/api/v1/contacts/{contactId}Update one contact, category membership, and communication-blocked state.
/api/v1/contacts/{contactId}/timelineRead a bounded cross-channel timeline of messages, transcripts, and call outcomes, optionally limited to one campaign. Recording content requires voice:read through the call API.
/api/v1/channel-participants/{participantId}/link-contactResolve a mobile-first contact and link the participant's prior channel history without OTP verification.
/api/v1/channels/assignmentsRead WhatsApp phone-number assignment state and assignable agents.
/api/v1/channels/assignmentsAssign a WhatsApp agent to the connected Meta phone number.
/api/v1/voice/callsCursor-paginated outbound calls with immutable call IDs, status, duration, charge, transcript and recording availability, plus canonical end attribution.
/api/v1/voice/callsStart one outbound call with an active Voice Call agent. Choose exactly one target: a scoped contact or a direct E.164 number.
/api/v1/voice/calls/batchStart calls for 1-20 scoped contacts through the same canonical call service. Each contact resolves its own declared variables and receives an independent billing reservation.
/api/v1/voice/calls/resolveResolve the selected agent's allowlisted contact variables and destination before placement. This endpoint exposes contact data and therefore requires both voice and contact read scopes.
/api/v1/voice/calls/{callId}Return one canonical call report with who ended the call, timestamp-ordered transcript, and a short-lived recording URL when the recording is ready.
/api/v1/voice/calls/{callId}/transcriptDownload the canonical timestamped call transcript as UTF-8 plain text with an attachment filename.
/api/v1/voice/calls/{callId}Durably request cancellation of a queued, ringing, or answered call. Carrier-backed calls remain cancelling until the carrier confirms a terminal result.
/api/v1/campaignsList channel-neutral campaigns and their latest Voice, WhatsApp, or SMS iteration.
/api/v1/campaignsCreate one campaign objective with an initial channel-specific iteration and immutable audience membership.
/api/v1/campaigns/{campaignId}Read one tenant-owned campaign and its current iteration.
/api/v1/campaigns/{campaignId}Start, pause, or cancel the current campaign iteration.
/api/v1/campaigns/{campaignId}/iterationsList ordered channel-specific runs under a stable campaign ID.
/api/v1/campaigns/{campaignId}/iterationsSelect contacts from prior outcomes and create a Voice or WhatsApp iteration without creating another campaign.
/api/v1/campaigns/{campaignId}/membershipsList immutable per-contact iteration membership and outcome history.
/api/v1/campaigns/{campaignId}/activitiesList attributed calls and messages newest first with contact, iteration, status, call duration, and activity time. Filter by contact, iteration, channel, or status.
/api/v1/campaigns/{campaignId}/summary-runsList append-only AI summary runs and their assessment progress for a campaign.
/api/v1/campaigns/{campaignId}/summary-runsCalculate a maximum AI assessment charge or confirm that exact estimate before processing.
/api/v1/campaigns/{campaignId}/exportsStream one campaign conclusion per unique contact with the columns Contact, AI Summary, and Next Action.
Use the generated Markdown brief when an AI coding tool needs the complete API contract and safety rules.
Download