Skip to main content

Get started

Quickstart: the API

API key to a finished call in curl: voice, Finn, audience, deployment, webhook.

What you'll do

Go from an API key to a finished, analyzed call using only curl: pick a voice, create a Finn, call a list of contacts, get the result pushed to your server, then read the call. It takes about 15 minutes. Every request here is a real request against your organization.

API key → voice → Finn → audience + phone number → deployment → calls → call.completed webhook → GET /calls/{call_uuid}

The objects

ObjectWhat it isHow you get one
FinnA voice agent: its voice, instructions, first line, call settings and the questions answered after each call. Configuration only; it makes no calls on its own.POST /finns (api-finns)
VoiceA voice a Finn can speak with, identified by voice_id.GET /voices (api-voices)
Phone numberA number your organization owns. Outbound deployments dial from it; inbound deployments answer on it.GET /phone_numbers, or rent one (api-phone-numbers)
AudienceA list of contacts to call. Each contact has a phone_number, a country_code, an optional name and any custom fields.POST /audiences (api-audiences)
DeploymentA Finn put to work on a number. Outbound: dials every contact in an audience. Inbound: answers calls to the number.POST /deployments or POST /deployments/inbound (api-deployments)
CallOne conversation, with its status, duration and post-call analysis answers.GET /calls/{call_uuid} (api-calls)
Webhook endpointA URL on your server that receives a signed call.completed event after every call.Dashboard only (api-webhooks)

There are two ways to make an outbound call:

Single call: POST /callsOutbound deployment: POST /deployments
Who it callsOne number per requestEvery contact in an audience
Caller IDA shared Finn number in India (+91), whatever the destinationYour own number
NeedsA FinnA Finn, an audience and a phone number
Use it forTesting, and one-off calls triggered by an eventCampaigns and anything that should come from your number

Before you start

  • An API key. In the dashboard, open Settings → Integrations → API keys and create one. It's shown once. Every key has full access to your organization, so keep it on your server. See authentication.
  • Credits. There are no test keys and no sandbox: every call in this guide is a real, billed phone call. Top up in the dashboard if your balance is low, and while you're testing, only call numbers you control.
  • A phone number for step 5. If your organization has none, rent one in the dashboard or with POST /phone_numbers. Renting needs an approved compliance application and is charged to your wallet. You can do steps 1 to 4 without one.

Put the key in an environment variable. Every example below reads it from there:

export FINN_API_KEY="finn_live_..."

1. Check your key and balance

curl https://api.hirefinn.ai/api/v1/wallet \
  -H "Authorization: Bearer $FINN_API_KEY"
{
  "success": true,
  "data": { "credits": 4175, "currency": "INR", "price_per_credit": 7, "monetary_value": 29225, "low_balance": false }
}

Every successful response is { "success": true, "data": ... }. Every error is { "error": "<code>", "message": "..." } with an HTTP status. A 401 with api_key_required means the header is missing or malformed; invalid_api_key means the key is unknown or revoked.

2. Pick a voice

curl "https://api.hirefinn.ai/api/v1/voices?search=rachel" \
  -H "Authorization: Bearer $FINN_API_KEY"
{
  "success": true,
  "data": [
    {
      "voice_id": "21m00Tcm4TlvDq8ikWAM",
      "name": "Rachel",
      "description": "Calm, young American female voice.",
      "preview_url": "https://example.com/voices/rachel-preview.mp3",
      "category": "premade",
      "labels": { "accent": "american", "gender": "female", "age": "young" },
      "languages": ["en"]
    }
  ]
}

Leave out search to list every voice you can use. Listen to preview_url, then copy the voice_id. Voice IDs aren't UUIDs; use them exactly as returned.

3. Create a Finn

name and voice are the only required fields. This example also sets the first line, the instructions, a call length limit and one question to answer after each call.

curl -X POST https://api.hirefinn.ai/api/v1/finns \
  -H "Authorization: Bearer $FINN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Renewal reminders",
    "voice": "21m00Tcm4TlvDq8ikWAM",
    "time_zone": "America/New_York",
    "begin_message": "Hi {{ name }}, this is Maya from Acme. Do you have a minute to talk about your renewal?",
    "system_prompt": "You are Maya from Acme. Confirm whether the customer wants to renew their plan. Keep answers short. If they want to cancel, thank them and end the call.",
    "max_call_duration_minutes": 5,
    "post_call_analysis": [
      { "name": "Wants to renew", "type": "Yes/No", "description": "Did the customer confirm they want to renew?" }
    ]
  }'

The response is 201 Created with the full Finn. Save data.id:

export FINN_ID="8f14e45f-ceea-467a-9f6a-1c0e5b2a77d1"

The Finn is a draft. {{ name }} is filled from each contact's name on deployment calls. A voice that isn't one of your voices returns 400 invalid_request. Every field, its limits and its default are in api-finns; what to write in the prompt is in agents-prompting.

4. Place a test call to yourself

Before you call anyone else, hear the Finn on your own phone:

curl -X POST https://api.hirefinn.ai/api/v1/calls \
  -H "Authorization: Bearer $FINN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "finn_id": "'"$FINN_ID"'",
    "to_number": "4155550142",
    "country_code": "1"
  }'
{
  "success": true,
  "data": { "call_uuid": "b7e3c9a2-4d1f-4e8b-9a6c-2f5d8e1b3c70", "finn_id": "8f14e45f-ceea-467a-9f6a-1c0e5b2a77d1", "to_number": "4155550142", "status": "initiated" }
}

202 Accepted means the call was accepted for dialing, not that anyone answered. Your phone rings from an Indian +91 number. A single call doesn't use the Finn's max_call_duration_minutes, idle reminder or end-on-silence settings; deployment calls do. Don't retry a POST /calls whose result you didn't get: it can ring the same phone twice. See api-idempotency.

5. Call a list: audience and deployment

Find a number to call from. List your numbers and pick one whose status is Live and that no running deployment is using. Its id is the phone_number_id.

curl "https://api.hirefinn.ai/api/v1/phone_numbers" \
  -H "Authorization: Bearer $FINN_API_KEY"
export PHONE_NUMBER_ID="6b1f0c2e-3d4a-4f5b-9c8d-2e7a1b9f4c03"

Create an audience. Start with one contact: yourself. country_code and phone_number are required on every contact; extra keys such as plan become custom fields you can use as {{ plan }} in the Finn's begin_message and system_prompt.

curl -X POST https://api.hirefinn.ai/api/v1/audiences \
  -H "Authorization: Bearer $FINN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Renewals test",
    "contacts": [
      { "name": "Dan", "phone_number": "4155550142", "country_code": "+1", "plan": "gold" }
    ]
  }'

The response is 201 Created with the audience and contacts_added. Save data.id:

export AUDIENCE_ID="c2d9e7a4-51b8-4e0f-8a63-9f1d2b7c5e48"

Start the deployment. This starts dialing straight away.

curl -X POST https://api.hirefinn.ai/api/v1/deployments \
  -H "Authorization: Bearer $FINN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "finn_id": "'"$FINN_ID"'",
    "phone_number_id": "'"$PHONE_NUMBER_ID"'",
    "audience_id": "'"$AUDIENCE_ID"'"
  }'

The response is 201 Created with the deployment, status pending, and the Finn becomes live. Save data.id as DEPLOYMENT_ID. Follow progress with GET /deployments/{id}: completed_calls counts up to total_calls, and an outbound deployment ends as completed once it has dialed everyone.

The common rejections: 402 insufficient_credits (the wallet must cover at least half the audience in one-minute calls), 409 deployment_already_active (this Finn already has a live deployment), 409 phone_number_in_use (another deployment holds the number) and 422 audience_not_ready (the audience has no contacts). The full list is in api-deployments.

To have the Finn answer calls on the number instead, use POST /deployments/inbound with finn_id and phone_number_id.

6. Receive results by webhook

Webhook endpoints are added in the dashboard, not through the API:

  1. Open Settings → Integrations → Webhooks, click Add endpoint and enter a public https:// URL. To receive events on your laptop, use a tunnel; see local-development.
  2. Copy the signing secret (whsec_...). It's shown once.
  3. In your handler, verify the X-Finn-Signature header against the raw body, store the event, then return 2xx within 10 seconds. A ready-made handler is in webhook-security.

After each call ends, answered or not, every endpoint receives one call.completed event, usually within about 5 minutes:

{
  "event": "call.completed",
  "created_at": "2026-09-18T11:14:09.000Z",
  "data": {
    "call_uuid": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
    "finn_id": "8f14e45f-ceea-467a-9f6a-1c0e5b2a77d1",
    "deployment_id": "0e8a4c71-9b2d-4f36-a5e1-7c3d9b2f6a10",
    "status": "completed",
    "to_number": "+14155550142",
    "duration_seconds": 97,
    "call_successful": true,
    "analysis": [
      { "question_name": "Wants to renew", "question_type": "Yes/No", "answer": "Yes", "needs_review": false, "reasoning": "Customer said they want to keep the plan.", "extracted_at": "2026-09-18T11:14:07.000Z" }
    ]
  }
}

This example is shortened; webhook-post-call lists every field. An endpoint only receives calls that end after you add it, and a delivery that fails 3 times is not sent again, so keep step 7 as your fallback.

7. Read the call

curl https://api.hirefinn.ai/api/v1/calls/3f2504e0-4f89-11d3-9a0c-0305e82c3301 \
  -H "Authorization: Bearer $FINN_API_KEY"

This returns the same call with billing added. The record appears only after the call ends, so a GET right after POST /calls returns 404 call_not_found: wait for the webhook, or retry with a backoff. analysis can be empty for a few minutes after the call while it's being worked out. There is no endpoint to list calls: keep the call_uuid values from POST /calls and from webhooks.

8. Stop the deployment

An outbound deployment stops by itself when it has dialed everyone. To stop it early:

curl -X POST "https://api.hirefinn.ai/api/v1/deployments/$DEPLOYMENT_ID/stop" \
  -H "Authorization: Bearer $FINN_API_KEY"

Calls already in progress finish. A stopped deployment can't be restarted; create a new one. Inbound deployments stop with POST /deployments/inbound/{finn_id}/stop.

Before you go to production

  • Handle errors by error code, not message. Don't retry other 4xx. Retry 429 after Retry-After. Errors that need someone to act in the dashboard, such as topping up or compliance, include an action_url. See api-errors.
  • Writes aren't idempotent. A retried create can make a second Finn, audience or call. Check state before retrying. See api-idempotency.
  • Dedupe webhook events on data.call_uuid. See webhook-retries.
  • Respect calling rules. Finn doesn't enforce calling hours or consent for you. See compliance.
  • Mind the limits. Each endpoint group has a per-key rate limit. See api-rate-limits.

Next

  • API reference: every endpoint and schema in one place.
  • api-finns: every Finn field, and which calls use the call settings.
  • webhooks: when events are sent, and the per-Finn data webhook.