Skip to main content

API reference

Audiences

Contact lists and their members.

Beta. Every endpoint on this page is live and documented as shipped. Shapes can still change before general availability.

Overview

An audience is a named list of contacts that an outbound deployment dials. The Audiences API creates audiences, adds and removes contacts, lists them and archives audiences you no longer need. To dial an audience, pass its id as audience_id to POST /deployments; see api-deployments.

Base URL: https://api.hirefinn.ai/api/v1. Auth: Authorization: Bearer finn_live_.... See authentication.

Every contact needs a country_code. Finn builds the number it dials from country_code plus phone_number, so a contact without a country code is rejected.

Endpoints

MethodPathRate limit (per API key)
GET/audiences300 per minute, shared by all audience reads
GET/audiences/{audience_id}Read bucket
GET/audiences/{audience_id}/contactsRead bucket
POST/audiences60 per minute, shared by all audience writes
POST/audiences/{audience_id}/contactsWrite bucket
DELETE/audiences/{audience_id}/contacts/{phone}Write bucket
DELETE/audiences/{audience_id}Write bucket

The audience object

{
  "id": "c2d9e7a4-51b8-4e0f-8a63-9f1d2b7c5e48",
  "name": "October renewals",
  "contact_count": 2,
  "source": "api",
  "is_dynamic": false,
  "created_at": "2026-10-01T08:30:12.000Z",
  "updated_at": null
}
FieldTypeNotes
idstringUUID.
namestringDisplay name.
contact_countintegerNumber of contacts in the audience.
sourcestringapi for audiences created through this API. Audiences created in the dashboard show their origin, for example manual_upload.
is_dynamicbooleantrue for audiences kept in sync from an external source. Dynamic audiences cannot be deployed through the API.
created_atstringISO 8601.
updated_atstring or nullISO 8601. null until the audience is first edited.

Archived audiences are not returned by any endpoint.

The contact object

On input, a contact is an object with these keys. Every other key becomes a custom field: a column stored with the contact and passed with it when a deployment dials.

FieldTypeRequiredRules
country_codestring or numberyes1 to 4 digits, optionally prefixed with +, for example "+91" or 1.
phone_numberstring or numberyesThe number without its country code: 4 to 14 digits, with country code and number together at most 15 digits. Spaces, dashes, dots and parentheses are stripped. A number starting with + must begin with its country_code, which is then removed.
namestringnoUp to 255 characters, no line breaks.
any other keystring, number or booleannoUp to 50 custom fields per contact. Key: 1 to 64 characters, without commas, double quotes or line breaks, and not name, phone_number or country_code in any letter case. Value: up to 500 characters, no line breaks. null values are skipped.

Contacts are stored as { "name", "phone_number", "country_code", ...custom fields } with phone_number as digits only and country_code with a leading +:

{ "name": "Asha Rao", "phone_number": "9876543210", "country_code": "+91", "plan": "gold" }

Two contacts are duplicates when country_code plus phone_number is the same number. Duplicates, within one request or against contacts already in the audience, are skipped and counted in duplicates_skipped.

Limits: at most 5,000 contacts per request and 50,000 contacts per audience.

List audiences

GET /audiences

Returns your organization's audiences, newest first.

Query parameterTypeDefaultNotes
limitinteger501 to 200. Out-of-range values are clamped.
offsetinteger0Number of items to skip.
curl "https://api.hirefinn.ai/api/v1/audiences?limit=50" \
  -H "Authorization: Bearer $FINN_API_KEY"
{
  "success": true,
  "data": [
    {
      "id": "c2d9e7a4-51b8-4e0f-8a63-9f1d2b7c5e48",
      "name": "October renewals",
      "contact_count": 2,
      "source": "api",
      "is_dynamic": false,
      "created_at": "2026-10-01T08:30:12.000Z",
      "updated_at": null
    }
  ],
  "limit": 50,
  "offset": 0
}

There is no total count. Page with offset until a page returns fewer than limit items.

Retrieve an audience

GET /audiences/{audience_id}

curl https://api.hirefinn.ai/api/v1/audiences/c2d9e7a4-51b8-4e0f-8a63-9f1d2b7c5e48 \
  -H "Authorization: Bearer $FINN_API_KEY"

Returns { "success": true, "data": { ... } } with one audience object.

Create an audience

POST /audiences

FieldTypeRequiredNotes
namestringyes1 to 255 characters after trimming.
contactsarraynoUp to 5,000 contact objects. Omit to create an empty audience and add contacts later.
curl -X POST https://api.hirefinn.ai/api/v1/audiences \
  -H "Authorization: Bearer $FINN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "October renewals",
    "contacts": [
      { "name": "Asha Rao", "phone_number": "9876543210", "country_code": "+91", "plan": "gold" },
      { "name": "Dan Hill", "phone_number": "+14155550142", "country_code": "1", "plan": "silver" }
    ]
  }'

Response 201 Created:

{
  "success": true,
  "data": {
    "id": "c2d9e7a4-51b8-4e0f-8a63-9f1d2b7c5e48",
    "name": "October renewals",
    "contact_count": 2,
    "source": "api",
    "is_dynamic": false,
    "created_at": "2026-10-01T08:30:12.000Z",
    "updated_at": null
  },
  "contacts_added": 2,
  "duplicates_skipped": 0
}

If any contact fails validation, nothing is created and the response is 400 invalid_request with a details array of up to 50 { "index", "message" } entries pointing at the failing contacts:

{
  "error": "invalid_request",
  "message": "1 contact(s) failed validation",
  "details": [{ "index": 1, "message": "country_code is required" }]
}

There is no idempotency key. A retried create makes a second audience.

List contacts

GET /audiences/{audience_id}/contacts

Query parameterTypeDefaultNotes
limitinteger1001 to 1,000. Out-of-range values are clamped.
offsetinteger0Number of contacts to skip.
curl "https://api.hirefinn.ai/api/v1/audiences/c2d9e7a4-51b8-4e0f-8a63-9f1d2b7c5e48/contacts?limit=100" \
  -H "Authorization: Bearer $FINN_API_KEY"
{
  "success": true,
  "data": [
    { "name": "Asha Rao", "phone_number": "9876543210", "country_code": "+91", "plan": "gold" },
    { "name": "Dan Hill", "phone_number": "4155550142", "country_code": "+1", "plan": "silver" }
  ],
  "total": 2,
  "limit": 100,
  "offset": 0
}

Contacts are returned as stored, in file order, with every value as a string. To keep the contact file safe to open in a spreadsheet, Finn stores a name or custom field value that starts with =, @, + or - with a leading ', so "=SUM(A1)" comes back as "'=SUM(A1)". Values that look like numbers, such as "-12.5" or "+1 415 555 0142", are left alone, and so are the phone number and country code columns. Strip the leading ' if you need the original value. total is the number of contacts in the audience. Audiences uploaded in the dashboard keep their own column names, for example phone or mobile instead of phone_number.

Add contacts

POST /audiences/{audience_id}/contacts

FieldTypeRequiredNotes
contactsarrayyes1 to 5,000 contact objects.
curl -X POST https://api.hirefinn.ai/api/v1/audiences/c2d9e7a4-51b8-4e0f-8a63-9f1d2b7c5e48/contacts \
  -H "Authorization: Bearer $FINN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contacts": [
      { "name": "Ravi Menon", "phone_number": "9123456780", "country_code": "+91", "plan": "gold" }
    ]
  }'
{
  "success": true,
  "data": {
    "id": "c2d9e7a4-51b8-4e0f-8a63-9f1d2b7c5e48",
    "name": "October renewals",
    "contact_count": 3,
    "source": "api",
    "is_dynamic": false,
    "created_at": "2026-10-01T08:30:12.000Z",
    "updated_at": "2026-10-02T10:04:55.000Z"
  },
  "contacts_added": 1,
  "duplicates_skipped": 0
}

New custom field names are added as new columns. Validation works as on create: one invalid contact rejects the whole request.

Remove a contact

DELETE /audiences/{audience_id}/contacts/{phone}

phone is the full number including its country code, for example 919876543210. Digits are compared, so +91 98765-43210 matches the same contact; a + in the path should be URL-encoded as %2B or left out. Every contact with that number is removed.

curl -X DELETE https://api.hirefinn.ai/api/v1/audiences/c2d9e7a4-51b8-4e0f-8a63-9f1d2b7c5e48/contacts/919876543210 \
  -H "Authorization: Bearer $FINN_API_KEY"
{
  "success": true,
  "data": {
    "id": "c2d9e7a4-51b8-4e0f-8a63-9f1d2b7c5e48",
    "name": "October renewals",
    "contact_count": 2,
    "source": "api",
    "is_dynamic": false,
    "created_at": "2026-10-01T08:30:12.000Z",
    "updated_at": "2026-10-02T10:06:31.000Z"
  },
  "contacts_removed": 1
}

An audience cannot be emptied this way: removing its last contact returns 409 audience_would_be_empty. Archive the audience instead.

Adding and removing contacts is refused while a running deployment uses the audience (409 audience_in_use, with that deployment_id in the body). A deployment counts as running when its status is in_progress, active, running or live; pending and paused deployments don't block edits. Stop the deployment first.

Archive an audience

DELETE /audiences/{audience_id}

Archives the audience, as the dashboard does. It is not permanently deleted, but it disappears from every endpoint in this API and cannot be used for new deployments. Archiving does not stop a deployment that is already dialing it; stop that with api-deployments.

curl -X DELETE https://api.hirefinn.ai/api/v1/audiences/c2d9e7a4-51b8-4e0f-8a63-9f1d2b7c5e48 \
  -H "Authorization: Bearer $FINN_API_KEY"
{
  "success": true,
  "data": { "id": "c2d9e7a4-51b8-4e0f-8a63-9f1d2b7c5e48", "archived": true }
}

Errors

StatuserrorEndpointWhen
400invalid_requestallaudience_id is not a UUID; name missing or too long; contacts is not an array, is empty when required, or has more than 5,000 items; a contact fails validation (with details); phone is not a phone number.
401api_key_requiredallNo Bearer finn_live_... key.
401invalid_api_keyallKey unknown or revoked.
404audience_not_foundall except list and createNo active audience with that ID in your organization.
404contacts_file_missingcontact list, add, removeThe audience's contact file no longer exists.
404contact_not_foundremove contactNo contact with that number.
409audience_in_useadd, remove contactA deployment with status in_progress, active, running or live uses the audience. Body includes deployment_id.
409audience_not_editableadd, remove contactThe audience has no contact file to edit.
409audience_limit_exceededadd contactsThe audience would exceed 50,000 contacts.
409audience_would_be_emptyremove contactIt is the last contact.
429rate_limitedallOver the bucket's per-minute limit.
500internal_errorallUnexpected server error.

Error bodies have the shape { "error": "...", "message": "..." }; internal_error has no message. See api-errors.