Skip to main content
flag
Mon - Fri   10:00 – 18:00

Place a Click to Call

API Documentation / Voice Click to Call / Place a Click to Call

Base URL for your account: https://cpaas.studio

GET POST /api/voice/v1/click2call

Places one Click to Call from one of your account's DIDs. Requires a key scoped to voice.click2call or all. A 202 means the call was accepted — it is billed later, after the CDR, and only if it connects. Only one Click to Call may be in flight per account.

Parameters

Param Type Required Notes
did_id integer yes A Click to Call-eligible active DID belonging to your account.
agent_number string yes The agent leg. 10 digits, 0 + 10 digits, or country code + 10 digits — all normalized.
customer_number string yes The customer leg. Same normalization. Must differ from agent_number.
reference string, max 64 no Your own label, echoed back and usable in the status lookup. Not unique.

Request example

curl -X POST "https://cpaas.studio/api/voice/v1/click2call" \
  -H "X-API-KEY: cpk_xxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Idempotency-Key: 9d1f-4a2c-agent-42" \
  -d "did_id=812" \
  -d "agent_number=9526071065" \
  -d "customer_number=9812345678" \
  -d "reference=lead-4471"
<?php
$ch = curl_init('https://cpaas.studio/api/voice/v1/click2call');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'X-API-KEY: cpk_xxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
        'Idempotency-Key: 9d1f-4a2c-agent-42',
        'Content-Type: application/json',
    ],
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode([
        'did_id' => 812,
        'agent_number' => '9526071065',
        'customer_number' => '9812345678',
        'reference' => 'lead-4471',
    ]),
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

Success response (data)

{
    "uid": "CC7Q2M4X8A1B",
    "event_id": "c2c-AB12CD34EF",
    "reference": "lead-4471",
    "status": "submitted",
    "disposition": null,
    "agent_number": "9526071065",
    "customer_number": "9812345678",
    "ring_time": 20,
    "duration_seconds": null,
    "billsec": null,
    "billing_status": "pending",
    "billable_units": null,
    "recording_available": false,
    "submitted_at": "2026-09-11T10:20:30+00:00",
    "answered_at": null,
    "completed_at": null,
    "created_at": "2026-09-11T10:20:30+00:00"
}

Errors

Code Status When
C2C_DID_INVALID 422 did_id is unknown, not your account's, inactive, or not Click to Call-eligible.
C2C_NUMBER_INVALID 422 agent_number or customer_number will not normalize for your account.
C2C_LOOPBACK 422 agent_number and customer_number are the same.
C2C_CONCURRENT_CALL 409 A Click to Call is already in flight on your account, at or above your plan's concurrency limit. The refused attempt is still logged — its uid is in error.details.
BILLING_NO_ACTIVE_PLAN 402 Your account has no active Click to Call plan.
BILLING_PLAN_QUOTA_EXHAUSTED 402 Your plan's quota is used up and it does not allow overdraft.
REQ_IDEMPOTENCY_KEY_CONFLICT 409 The Idempotency-Key header matches a prior request but this body is different.
SYS_PROVIDER_ERROR 502 The operator rejected the call or was unreachable — safe to retry.
REQ_VALIDATION_FAILED 422 Any field-level rule failure not covered by a more specific code above. Sending a field this endpoint does not accept — ring_time, for example — lands here too, with REQ_FIELD_NOT_PERMITTED against that field in error.details.

Notes

  • A 202 means accepted, not connected and not billed. Billing is charged once, after the CDR, only on a call that actually connected — poll the status endpoint for the outcome.
  • What a call costs depends on your assigned plan's pulse setting: per call ("full call"), or per 30/60-second pulse of connected time (billsec — ring time is never charged). A plan on unlimited (validity) billing is not charged per call.
  • On a plan with overdraft enabled, quota is not checked before dialing, because the amount is not known until the call ends — it may go negative, and the shortfall is settled automatically the next time a plan is assigned. Without overdraft, a request is refused up front once the quota is used up.
  • The number of Click to Call requests that may be in flight per account at once is set by your assigned plan (falling back to a platform default). A request over that limit is refused with 409 C2C_CONCURRENT_CALL — the attempt is still recorded and still has a uid, so it appears in your logs.
  • An optional Idempotency-Key request header replays the original call on an identical retry within 24 hours; a different body under the same key is a conflict, never a silent no-op.
  • One request is one call. There is no batching, no scheduling, and no recipient list.
  • Ring time is a fixed platform setting (20 seconds) and is not settable per call. It is returned in every response for reference, but sending a ring_time field is rejected rather than ignored, so a value you set can never silently fail to apply.

Need more context? See Getting started for authentication, the response envelope, and the full error-code reference.