Skip to main content

API reference

Calls

Placing calls and reading call records.

Beta. This endpoint is not final. Field names and response shapes can change before general availability.

Overview

The Calls API places outbound calls and reads records of calls that have already happened, inbound or outbound. A call is always tied to a deployment, which supplies the Finn, the voice, the phone number, and the prompt configuration. You do not pass an agent to this API. You pass a deployment ID and the variables that deployment expects.

If you want to launch many calls at once, use a campaign through outbound campaigns rather than looping this endpoint. Per-call creation is intended for event-driven calls: a form submission, a webhook from your CRM, a support ticket escalation.

Place a call

curl -X POST https://api.hirefinn.ai/v1/calls \
  -H "Authorization: Bearer $FINN_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-48812-callback" \
  -d '{
    "deployment_id": "dep_7yQ2m4Kx",
    "to": "+14155550142",
    "variables": {
      "customer_name": "Ada Lovelace",
      "order_id": "48812"
    },
    "metadata": {
      "crm_record": "lead_9931"
    }
  }'
FieldTypeRequiredNotes
deployment_idstringyesOutbound deployment to run. See api-deployments.
tostringyesDestination in E.164 format, including the + and country code.
variablesobjectnoValues substituted into the prompt. Keys must match the variables the deployment declares. See agents-variables.
metadataobjectnoOpaque key/value pairs echoed back on the call record and on webhooks.
fromstringnoOverrides the deployment's outbound number. Must be a number on your account.

Whether from overrides are permitted on every plan is not yet settled. If the deployment already has a number pool attached, omit from and let routing choose.

Always send an Idempotency-Key. A retried POST without one places a second real call to a real person. See api-idempotency.

The response returns immediately with a queued call. Dialing has not started yet.

{
  "id": "call_3xR8dNqA",
  "deployment_id": "dep_7yQ2m4Kx",
  "direction": "outbound",
  "status": "queued",
  "to": "+14155550142",
  "from": "+14085550199",
  "created_at": "2026-07-30T09:14:02Z",
  "metadata": { "crm_record": "lead_9931" }
}

Call status

StatusMeaning
queuedAccepted, waiting for a concurrency slot.
dialingCarrier is placing the call.
in_progressAnswered, agent is talking.
completedCall ended normally. Transcript and analysis follow.
failedCould not be placed. Check error.
no_answerRang out with no pickup.
busyCarrier returned busy.
canceledCanceled before it connected.

Do not poll for status. Subscribe to call events instead, described in webhook-events. Polling burns rate limit and still lags the actual call.

A call sitting in queued usually means you are at your concurrency ceiling. Calls queue rather than fail, so a burst of POSTs looks accepted and then stalls. Read concurrency before you size a burst.

Retrieve a call

curl https://api.hirefinn.ai/v1/calls/call_3xR8dNqA \
  -H "Authorization: Bearer $FINN_API_KEY"

The completed record includes the fields above plus:

FieldTypeNotes
started_atstringISO 8601, when the call connected. Null if never answered.
ended_atstringISO 8601.
duration_secondsintegerBilled talk time. Zero for unanswered calls.
outcomestringBusiness result. See call-outcomes.
transcriptarrayTurn objects with speaker and text.
recording_urlstringPresent only if recording is enabled and consent rules allow it. See recording-consent.
analysisobjectPost-call extraction. See post-call-analysis.
errorobjectPresent on failed. Contains code and message.

Transcript and analysis are not populated the instant a call ends. If you fetch on the completed webhook and find analysis empty, that is expected timing, not a missing field. The exact ordering guarantee between call completion and analysis availability is not yet settled.

recording_url is short-lived. Treat it as a download link, not a permanent address. Retention is governed by your workspace policy in retention.

List calls

curl -G https://api.hirefinn.ai/v1/calls \
  -H "Authorization: Bearer $FINN_API_KEY" \
  --data-urlencode "deployment_id=dep_7yQ2m4Kx" \
  --data-urlencode "status=completed" \
  --data-urlencode "created_after=2026-07-01T00:00:00Z" \
  --data-urlencode "limit=50"

Filters: deployment_id, direction, status, outcome, created_after, created_before. Results are cursor paginated, newest first. See api-pagination.

Listing is not an export path. Pulling a large history through this endpoint will hit api-rate-limits long before it finishes. For bulk history, use the export in call-logs.

TypeScript example

const res = await fetch("https://api.hirefinn.ai/v1/calls", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.FINN_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": `ticket-${ticketId}-callback`,
  },
  body: JSON.stringify({
    deployment_id: "dep_7yQ2m4Kx",
    to: "+14155550142",
    variables: { customer_name: "Ada Lovelace", order_id: "48812" },
  }),
});

if (!res.ok) {
  const err = await res.json();
  throw new Error(`${res.status} ${err.error?.code}: ${err.error?.message}`);
}

const call = await res.json();
console.log(call.id, call.status);

Cancel a queued call

curl -X DELETE https://api.hirefinn.ai/v1/calls/call_3xR8dNqA \
  -H "Authorization: Bearer $FINN_API_KEY"

Cancel works only while a call is queued. Once dialing starts the carrier owns it and the request returns a conflict. Error shapes are listed in api-errors.