Server integration
Connect your app.
Keep each client in its workspace.
Verify access, save the matching workspace and agent IDs, then connect the features your customer approved. These examples use Bash and curl with your key loaded privately on your server.
Need your referral link or agency account first? Follow the easy partner and agency onboarding guide.
1. Choose the right key
An API key authorizes requests within its granted scopes and accessible workspaces. A referral code only attributes signups; it does not authorize API requests.
| Your setup | Where to get access | What to verify |
|---|---|---|
| One customer business | Owner or admin creates a business-scoped key in Developer Platform. | Selected business and reviewed permissions. The Partner integration preset covers setup and reads. |
| Agency operations | An authorized agency member uses the agency portal’s scoped key controls. | Agency role, client membership and assignment, key reach, and operation scope. |
| Partner-managed workspaces | Use a separately issued partner-scoped key after the managed arrangement is enabled. | Server-derived partner identity, accessible workspaces, and billing eligibility. |
Store the full key in your server secret manager as KAICALLS_API_KEY. Send Authorization: Bearer on authenticated requests. The server derives partner identity from a partner key; do not add an X-Partner-ID header. A bearer token cannot mint another key or upgrade its own permissions.
2. Read your workspaces and agents
Your first requests establish which businesses and permissions the runtime key can access. Read capabilities, then list workspaces before choosing an ID.
export KAICALLS_BASE_URL='https://www.kaicalls.com/api/v1'
curl --fail-with-body "$KAICALLS_BASE_URL/capabilities" \
-H "Authorization: Bearer $KAICALLS_API_KEY"
curl --fail-with-body "$KAICALLS_BASE_URL/workspaces" \
-H "Authorization: Bearer $KAICALLS_API_KEY"Set the business ID returned for the intended customer. List agents and save an agent whose returned business_id matches that workspace. Keep this pair with the customer record in your application.
export KAICALLS_BUSINESS_ID='YOUR_BUSINESS_ID'
curl --fail-with-body "$KAICALLS_BASE_URL/agents?business_id=$KAICALLS_BUSINESS_ID" \
-H "Authorization: Bearer $KAICALLS_API_KEY"
export KAICALLS_AGENT_ID='AGENT_ID_FOR_THIS_BUSINESS'
curl --fail-with-body "$KAICALLS_BASE_URL/agents?id=$KAICALLS_AGENT_ID&business_id=$KAICALLS_BUSINESS_ID" \
-H "Authorization: Bearer $KAICALLS_API_KEY"
curl --fail-with-body "$KAICALLS_BASE_URL/numbers?business_id=$KAICALLS_BUSINESS_ID" \
-H "Authorization: Bearer $KAICALLS_API_KEY"Read the authenticated live contract at GET /openapi.json and individual request schemas at GET /schemas?name=agentUpdate. The public OpenAPI YAML is available before you have a key. Live capabilities and schemas describe the current supported surface.
3. Configure the existing agent
Agent configuration updates use PATCH /agents with the existing agent’s id. Confirm the intended agent first, fetch agentUpdate for supported fields, and send only the changes you intend.
curl --fail-with-body -X PATCH "$KAICALLS_BASE_URL/agents" \
-H "Authorization: Bearer $KAICALLS_API_KEY" \
-H 'Content-Type: application/json' \
-d "{\"id\":\"$KAICALLS_AGENT_ID\",\"first_message\":\"Hello, thanks for calling. How can I help?\"}"Read the agent again after updating it. The update requires agents:write and access to that agent’s workspace. Use the returned signup agent instead of creating a duplicate.
Add business facts and services
Business facts use POST /knowledge; services use POST /products. Include business_id and fetch knowledgeUpsert or productUpsert for the current fields.
{
"business_id": "YOUR_BUSINESS_ID",
"title": "Service area",
"content": "We serve Hoboken, New Jersey.",
"content_type": "text"
}{
"business_id": "YOUR_BUSINESS_ID",
"name": "Consultation",
"description": "A 30-minute introductory consultation",
"price": 50,
"attributes": {
"duration_minutes": 30
}
}Replace the examples with the customer’s approved facts. Save each returned record ID and include id on later updates. Reusing a name or title without its ID creates another record.
Agent email, continuity, and native-policy settings use a separate PATCH from voice or greeting changes. Follow agentUpdate and read GET /agents?id=AGENT_ID&configuration=continuity for those settings.
4. Receive signed events
Webhooks deliver supported events to your public HTTPS receiver. Register a receiver for each workspace with POST /webhooks, the bearer header, and JSON content type.
{
"business_id": "YOUR_BUSINESS_ID",
"webhook_url": "https://your-app.example/api/kaicalls/webhook",
"events": [
"workspace.ready",
"phone_number.assigned",
"call.completed"
],
"is_active": true
}Use your real receiver URL and check events against capabilities or webhookUpsert. Save the returned webhook_secret privately when the webhook is created; the secret is disclosed once.
- Read
X-KaiCalls-Signature, formatted ast=TIMESTAMP,v1=HEX_SIGNATURE, and preserve the raw request body. - Calculate HMAC-SHA256 with the signing secret over
timestamp + "." + rawBody. Compare signatures in constant time before trusting the payload. - Reject stale timestamps under your receiver’s freshness policy and deduplicate event IDs before processing.
- Acknowledge accepted deliveries promptly. Read
X-KaiCalls-Eventfor the event type.
Registering a webhook does not emit a new event for an already assigned number. Verify a new delivery with an agreed test action. The webhook reference describes delivery details.
5. Test a call and read the result
A call test places a real phone call. Run a test only after confirming calls:write, an eligible active workspace, a ready outbound line, and a consenting test recipient. The standard Partner integration preset does not grant call placement.
Replace the recipient below with your own agreed E.164 number. Generate a unique idempotency key for each intended call; reuse the same key only when retrying the exact same request.
export KAICALLS_TEST_NUMBER='YOUR_CONSENTING_E164_NUMBER'
export KAICALLS_CALL_IDEMPOTENCY_KEY='YOUR_UNIQUE_LOGICAL_CALL_ID'
curl --fail-with-body -X POST "$KAICALLS_BASE_URL/calls" \
-H "Authorization: Bearer $KAICALLS_API_KEY" \
-H 'Content-Type: application/json' \
-H "Idempotency-Key: $KAICALLS_CALL_IDEMPOTENCY_KEY" \
-d "{\"agent_id\":\"$KAICALLS_AGENT_ID\",\"to\":\"$KAICALLS_TEST_NUMBER\",\"context\":\"This is an agreed integration test.\",\"max_duration\":60}"POST /calls selects the workspace from agent_id, not a body business_id. The idempotency header takes precedence over body idempotency_key. Save the returned call ID.
export KAICALLS_CALL_ID='RETURNED_CALL_ID'
curl --fail-with-body "$KAICALLS_BASE_URL/calls?id=$KAICALLS_CALL_ID&business_id=$KAICALLS_BUSINESS_ID" \
-H "Authorization: Bearer $KAICALLS_API_KEY"
curl --fail-with-body "$KAICALLS_BASE_URL/calls?business_id=$KAICALLS_BUSINESS_ID&agent_id=$KAICALLS_AGENT_ID&limit=5" \
-H "Authorization: Bearer $KAICALLS_API_KEY"Read completed transcripts through /transcripts using its current OpenAPI parameters. A successful API read does not establish SMS registration, a usable email inbox, or phone readiness. Verify each channel separately.
KaiCalls currently issues live keys and uses live phone infrastructure. There is no separate kc_test_ sandbox. Use mocked responses for automated tests and agreed test numbers for live calls.
Agency teams and client access
Agency teams can begin in the agency portal after creating an account through the agency landing page. The launch journey covers agency identity, choosing a service, confirming who pays, previewing and publishing, adding clients, and verifying services.
Use “Create scoped operations API key” for the permissions available to your role. The current operations key covers workspace reads and, for authorized roles, workspace and agent writes. A reader receives read access only. The owner-only finance key covers workspace reads and billing reads and writes.
Those controls do not grant a universal phone, number, or webhook key. Check capabilities for the key you actually received. Each client request still requires agency access, client membership and assignment, key reach, and the endpoint’s required scope.
An agency can select authorized clients or invite owners to complete setup. Client enrollment or prepared assets do not prove activation; check each service’s verified result in the portal. Agency retail invoicing and KaiCalls platform billing are separate arrangements.
Advanced: partner-managed workspaces and billing
Partner-managed workspace creation is a separate integration path for an enabled partner arrangement. Use your separately issued partner-scoped key and workspaces:write. Public referral registration and the business-scoped Partner integration preset do not grant this authority.
Need this arrangement? Request partner-managed API access with your company, integration use case, expected client setup, and intended payer. KaiCalls reviews eligibility and required scopes; submitting a request does not grant access or activate billing.
{
"name": "Customer business name",
"external_ref": "YOUR_CUSTOMER_REFERENCE",
"metadata": {
"source": "your-platform"
}
}Save the returned business ID and check existing customer records before retrying creation. Workspace creation alone does not create an agent, allocate a phone number, or activate a paid plan. Do not assume external_ref makes retries idempotent.
Eligible partner-billed accounts can read GET /partner-billing with billing:read for their current available plan keys, prices, and statement. Fetch current prices before quoting a customer; public examples do not establish your commercial terms.
POST /partner-billing with business_id and a supported plan enables a charge-bearing entitlement when eligibility checks pass. Use it only with billing:write after agreeing on the customer’s payer and plan. Existing direct subscriptions have payer protections. Custom terms are not a general self-service entitlement.
Pausing, cancelling, or tearing down workspaces requires the relevant lifecycle authority. Do not treat ordinary workspaces:write as permission for every lifecycle action.
Resolve a failed request
- 401 · Authentication
- Confirm the full key is loaded and the Authorization: Bearer header is present. A key prefix alone is not a usable token.
- 403 · Permissions or access
- Check the required scope and accessible workspaces in capabilities. Agency and partner operations can require additional membership, role, or billing eligibility.
- 429 · Rate limit
- Respect Retry-After when returned and retry with backoff.
- Timeout on a write
- Check whether the record or call already exists before retrying. Reuse the original call idempotency key for the same logical call.
For support, share the endpoint, HTTP status, business ID, request ID, and a redacted response. Keep the full key and signing secrets private. Review API errors or authentication for more detail.