Skip to main content
Use POST /v1/calls to start a single outbound voice call. PAM accepts the request and places the call asynchronously.

Create a Call

curl https://api.pamhq.com/v1/calls \
  -X POST \
  -H "Authorization: Bearer $PAM_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: call_01HV7K4ZD3Q9X8P1M8Y2K9A0BC" \
  -d '{
    "agentSlug": "voice-recall",
    "toNumber": "+15555550199",
    "fromNumber": "+15555550123",
    "welcomeMessage": "Hi Ada, this is PAM Motors following up on your service recall.",
    "dynamicVariables": {
      "contact_first_name": "Ada",
      "contact_last_name": "Lovelace",
      "dealership_name": "PAM Motors",
      "recall_id": "24V-123",
      "service_ids": "RECALL_SERVICE",
      "vin": "1HGBH41JXMN109186",
      "vehicle_year": "2021",
      "vehicle_make": "Honda",
      "vehicle_model": "Accord"
    },
    "metadata": {
      "externalContactId": "contact_123"
    },
    "externalReferenceId": "touchpoint_123",
    "webhookUrl": "https://partner.example.com/pam/webhooks"
  }'
Successful requests return 202 Accepted:
{
  "data": {
    "conversationId": null,
    "status": "queued"
  },
  "meta": {
    "requestId": "req_abc123"
  }
}
queued means PAM accepted the request and will place the call asynchronously. PAM creates a conversationId after the call is placed. Subsequent call lifecycle webhooks such as call.started, call.ended, and call.analyzed include conversationId. If PAM cannot place the call, PAM sends a call.failed webhook. Use data.dispatchRequestId, top-level externalReferenceId, the original Idempotency-Key, or your request metadata to reconcile the failed call attempt. If webhookUrl is provided, PAM uses it for call.failed even when no conversationId was created yet.

Request Fields

FieldRequiredDescription
agentSlugone of agentSlug or agentIdStable slug for a PAM-managed voice agent, such as voice-recall or voice-retention.
agentIdone of agentSlug or agentIdUUID of a specific agent.
toNumberyesCustomer phone number in E.164 format.
fromNumberPAM-managed agents onlySender phone number in E.164 format. For custom agents with a configured number, PAM uses the agent’s number.
welcomeMessagePAM-managed voice agents onlyOpening text used as the Retell begin message.
dynamicVariablesPAM-managed recall and retention agents onlyPublic string variables used to build the voice agent context and tools. See PAM Agents for the required variables for each managed agent.
metadatanoOpaque reconciliation data stored with the conversation.
externalReferenceIdnoOpaque caller-owned reference echoed as top-level externalReferenceId on webhook events for this call. PAM does not interpret this value. It does not need to be globally unique and is not a replacement for idempotencyKey.
idempotencyKeyrequired if Idempotency-Key header is not sentStable key for safely retrying this create request. Prefer the Idempotency-Key header for new integrations.
webhookUrlnoHTTPS URL that receives webhook events for this call instead of the default webhook registration URL. Event subscriptions, custom headers, and signing secret still come from your matching webhook registration.
Your API key determines the client organization for attribution and billing. Do not send clientOrgId in the request body. Use externalReferenceId when your system needs to map webhooks back to one of your own objects, such as a touchpoint, campaign, or workflow run. PAM stores the value and echoes it on webhooks when provided. For PAM-managed agents, PAM generates internal prompt context blocks from the submitted dynamicVariables plus server-owned client configuration. Those generated context blocks are not returned by call GET or list responses.

Idempotency

An idempotency key is required. Send it in the Idempotency-Key header or as idempotencyKey in the JSON body. Use the same key when retrying a request after a network error or timeout. If PAM has already accepted a call request for the same key and client organization, the retry returns the current status. If the call has already been placed, the response may also include the resulting conversationId.

List Calls

Use GET /v1/calls to list voice call conversations for your organization.
curl "https://api.pamhq.com/v1/calls?limit=20" \
  -H "Authorization: Bearer $PAM_API_KEY"
You can filter by status, agentId, toNumber, fromNumber, createdAfter, and createdBefore. Results are cursor-paginated:
{
  "data": [
    {
      "id": "b7ee8d1b-5e3e-4a1a-8f0a-9e2a4f8f1aa2",
      "conversationId": "b7ee8d1b-5e3e-4a1a-8f0a-9e2a4f8f1aa2",
      "status": "in_progress",
      "agentId": "2c4a1e72-7a5d-4b6e-9c2a-01a78b7b3f3f",
      "agentVersionId": "7a9c7b3e-8d0f-4c40-a156-dcc78c89b127",
      "fromNumber": "+15555550123",
      "toNumber": "+15555550199",
      "dynamicVariables": {
        "contact_first_name": "Ada",
        "contact_last_name": "Lovelace",
        "dealership_name": "PAM Motors",
        "recall_id": "24V-123"
      },
      "metadata": {
        "externalContactId": "contact_123"
      },
      "startedAt": "2026-04-10T14:00:02.010Z",
      "endedAt": null,
      "endReason": null,
      "createdAt": "2026-04-10T13:59:58.000Z",
      "updatedAt": "2026-04-10T14:00:02.010Z",
      "provider": "retell",
      "providerCallId": "call_abc123",
      "recordingUrl": null,
      "transcriptUrl": null,
      "durationMs": null,
      "costCents": null,
      "analysis": null
    }
  ],
  "meta": {
    "requestId": "req_abc123",
    "pagination": {
      "cursor": null,
      "hasMore": false
    }
  }
}
If hasMore is true, pass the returned cursor in the next request.

Get Call Status

Use GET /v1/calls/{id} to get the current status for one voice call conversation.
curl https://api.pamhq.com/v1/calls/b7ee8d1b-5e3e-4a1a-8f0a-9e2a4f8f1aa2 \
  -H "Authorization: Bearer $PAM_API_KEY"
{
  "data": {
    "id": "b7ee8d1b-5e3e-4a1a-8f0a-9e2a4f8f1aa2",
    "conversationId": "b7ee8d1b-5e3e-4a1a-8f0a-9e2a4f8f1aa2",
    "status": "completed",
    "agentId": "2c4a1e72-7a5d-4b6e-9c2a-01a78b7b3f3f",
    "agentVersionId": "7a9c7b3e-8d0f-4c40-a156-dcc78c89b127",
    "fromNumber": "+15555550123",
    "toNumber": "+15555550199",
    "dynamicVariables": {
      "contact_first_name": "Ada",
      "contact_last_name": "Lovelace",
      "dealership_name": "PAM Motors",
      "recall_id": "24V-123"
    },
    "metadata": {
      "externalContactId": "contact_123"
    },
    "startedAt": "2026-04-10T14:00:02.010Z",
    "endedAt": "2026-04-10T14:03:41.000Z",
    "endReason": "user_hangup",
    "createdAt": "2026-04-10T13:59:58.000Z",
    "updatedAt": "2026-04-10T14:03:41.000Z",
    "provider": "retell",
    "providerCallId": "call_abc123",
    "recordingUrl": "https://recordings.example/abc.mp3",
    "transcriptUrl": null,
    "durationMs": 219000,
    "costCents": 42,
    "analysis": {
      "status": "completed",
      "result": {
        "call_successful": true
      },
      "durationMs": 1200
    }
  },
  "meta": {
    "requestId": "req_abc123"
  }
}
These read endpoints are useful when a webhook is delayed, retried, or missed by your system.

Status Meanings

StatusMeaning
queuedPAM accepted the request, but the call has not started yet.
in_progressThe call has started and is still open.
completedThe call ended normally. Check endReason for why it ended.
failedPAM could not place the call or the call hit an unrecoverable error.
cancelledThe call was cancelled before normal completion.

Lifecycle Webhooks

Subscribe to these events to follow the call:
EventWhen it fires
call.startedThe call started.
call.endedThe call has ended and the transcript has been persisted.
call.analyzedPost-call analysis is available.
call.failedPAM could not place the call.
Webhook payloads are canonical PAM payloads. Provider-specific Retell identifiers and raw provider payloads are not part of the external contract. Voice lifecycle webhook data includes dispatchRequestId and idempotencyKey when PAM can associate the event with the original create-call request. If you provided externalReferenceId, PAM includes it as a top-level field on every lifecycle webhook for the call, including pre-conversation call.failed events.

Close a Call

Use POST /v1/calls/{id}/close to close an open voice conversation. The {id} is the conversationId from call lifecycle webhooks or from an idempotent create-call retry after PAM has created the conversation. A pre-placement call.failed event may not have a conversationId; use dispatchRequestId, top-level externalReferenceId, the original Idempotency-Key, or your request metadata to reconcile that case.
curl https://api.pamhq.com/v1/calls/b7ee8d1b-5e3e-4a1a-8f0a-9e2a4f8f1aa2/close \
  -X POST \
  -H "Authorization: Bearer $PAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "admin_closed"
  }'
If reason is omitted, PAM uses admin_closed.

Common Errors

  • 400 validation_error — missing idempotency key, invalid phone format, invalid or non-HTTPS webhookUrl, both agentId and agentSlug were provided, or neither was provided.
  • 400 validation_errorfromNumber is missing for a PAM-managed agent.
  • 400 validation_error — a managed agent request is missing required dynamicVariables.
  • 401 unauthorized — missing, expired, revoked, or invalid API key.
  • 404 not_found — the agent could not be resolved or the conversation does not belong to the authenticated client.