Skip to main content

API reference

Deployments

Campaigns and inbound bindings.

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

What a deployment is

A deployment binds a Finn to a phone number and a direction. Outbound deployments pull contacts from an audience and dial them. Inbound deployments answer calls arriving on a number you own. The same Finn can back several deployments at once, so you can run a daytime campaign and a 24/7 receptionist from one agent definition.

Read concepts for the object model and inbound-vs-outbound for how the two directions differ operationally.

Create an outbound deployment

curl -X POST https://api.hirefinn.ai/v1/deployments \
  -H "Authorization: Bearer $FINN_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: dep-q3-winback-01" \
  -d '{
    "name": "Q3 winback",
    "direction": "outbound",
    "finn_id": "finn_8Kd2mQ",
    "audience_id": "aud_71xBva",
    "from_number": "+14155550123",
    "timezone": "America/New_York",
    "schedule": {
      "days": ["mon", "tue", "wed", "thu", "fri"],
      "window": { "start": "09:00", "end": "17:00" }
    },
    "max_concurrency": 5
  }'

timezone governs the schedule window. It is evaluated against the deployment timezone, not the contact's, in the current shape. Whether per-contact local-time dialing lands before general availability is not yet settled.

Create an inbound binding

An inbound deployment has no audience and no schedule. It is a binding: calls to phone_number_id route to finn_id.

curl -X POST https://api.hirefinn.ai/v1/deployments \
  -H "Authorization: Bearer $FINN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Main line receptionist",
    "direction": "inbound",
    "finn_id": "finn_3Rp9tW",
    "phone_number_id": "pn_4Ld8ce",
    "max_concurrency": 10
  }'

One number holds one active inbound binding. Posting a second inbound deployment for a number that already has one returns 409 conflict. Deactivate the existing binding first, or the API will not tell you which deployment is winning. See api-phone-numbers to list numbers and their current bindings.

Fields

FieldTypeApplies toNotes
namestringbothLabel shown in the dashboard. Not unique.
directionenumbothinbound or outbound. Cannot be changed after creation.
finn_idstringbothThe agent that handles the call.
audience_idstringoutboundContacts to dial. See api-audiences.
from_numberstringoutboundE.164. Must be a number on your account.
phone_number_idstringinboundThe number to bind.
timezonestringoutboundIANA name. Required when schedule is present.
schedule.daysarrayoutboundLowercase three-letter day names.
schedule.windowobjectoutboundstart and end as 24-hour HH:MM.
max_concurrencyintegerbothSimultaneous calls this deployment may hold.
statusenumbothRead-only. See below.

Passing an outbound-only field on an inbound deployment is rejected rather than ignored. Do not rely on silent field-dropping.

Status

StatusMeaning
draftCreated but never activated. No calls.
activeDialing, or accepting inbound calls.
pausedStopped by you. Contacts not yet dialed stay queued.
completedOutbound only. Audience exhausted.

Creation returns draft. Activate separately:

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

Pause with /deployments/{id}/pause. Pausing does not drop calls already in progress. They finish, then no new calls start.

List and read

curl "https://api.hirefinn.ai/v1/deployments?direction=outbound&status=active&limit=25" \
  -H "Authorization: Bearer $FINN_API_KEY"

Filters: direction, status, finn_id. Paging follows api-pagination.

import os, requests

BASE = "https://api.hirefinn.ai/v1"
headers = {"Authorization": f"Bearer {os.environ['FINN_API_KEY']}"}

r = requests.get(f"{BASE}/deployments", headers=headers,
                 params={"status": "active", "limit": 100})
r.raise_for_status()

for d in r.json()["data"]:
    print(d["id"], d["direction"], d["name"], d.get("max_concurrency"))

What will go wrong

  • Sum of max_concurrency exceeds your account limit. Deployments do not reserve capacity. They compete for it. An outbound campaign can starve your inbound line. Read concurrency before setting these.
  • Activating with an empty audience. The deployment goes active, dials nothing, then reports completed. Check the audience count first.
  • from_number not on your account. Rejected at create time with 422, not at dial time.
  • Editing an active deployment. Changes to schedule and max_concurrency apply going forward only. Calls in flight keep the old values.
  • Retrying a create without an idempotency key. You get two deployments and two campaigns. Send Idempotency-Key on every create. See api-idempotency.

Per-call results arrive by webhook, not by polling the deployment. Subscribe to call events described in webhook-events.