Authentication
All API requests require an API key passed in the X-API-Key header.
X-API-Key: your_api_key_here
Creating an API Key
API Key Scopes
Control what each key can access.
| Scope | Description |
|---|---|
Full Access | Read and write access to all resources |
Read Only | List and view contacts, lists, and campaigns |
Contacts Only | Create, update, and delete contacts and lists |
Campaigns Only | View and control campaigns |
Request Format
How to structure your API requests.
Use query parameters: /contacts?page=1&search=John
Require a JSON body with Content-Type: application/json
UUIDs returned when creating resources, also visible in the app
All fields are optional unless marked (required)
Contacts
Manage your contact database programmatically.
/contacts
Read Only
Returns a paginated list of contacts.
| Parameter | Type | Description |
|---|---|---|
page | integer | Page number (default: 1) |
per_page | integer | Items per page (default: 25) |
search | string | Search by name or phone number |
{
"items": [
{
"id": "uuid",
"phone_number": "(555) 123-4567",
"e164_number": "+15551234567",
"first_name": "John",
"last_name": "Doe",
"email": "[email protected]",
"timezone": "America/New_York",
"tags": ["lead", "priority"],
"opted_out": false,
"created_at": "2026-01-15T10:30:00Z"
}
],
"total": 150,
"page": 1,
"per_page": 25,
"pages": 6
}
/contacts/{id}
Read Only
Returns details for a single contact.
/contacts
Contacts Only
Creates a new contact.
| Field | Type | Required | Description |
|---|---|---|---|
phone_number | string | Yes | Phone number (auto-converted to E.164) |
first_name | string | No | Contact's first name |
last_name | string | No | Contact's last name |
email | string | No | Email address |
timezone | string | No | IANA timezone (e.g. America/New_York) |
tags | string[] | No | List of tags |
list_ids | string[] | No | UUIDs of lists to add contact to |
{
"phone_number": "(555) 123-4567",
"first_name": "John",
"last_name": "Doe",
"email": "[email protected]",
"tags": ["lead", "priority"],
"list_ids": ["uuid-of-list"]
}
/contacts/{id}
Contacts Only
Updates an existing contact. Only include fields you want to change.
/contacts/{id}
Contacts Only
Permanently deletes a contact.
/contacts/{id}/opt-out
Contacts Only
Opts out a contact so they no longer receive messages.
{
"id": "uuid",
"opted_out": true,
"opted_out_at": "2026-03-06T15:00:00Z"
}
/contacts/{id}/opt-in
Contacts Only
Re-activates an opted-out contact.
/contacts/batch
Contacts Only
Creates multiple contacts in a single request. Duplicates (by phone number) are skipped.
{
"contacts": [
{ "phone_number": "(555) 100-0001", "first_name": "Alice" },
{ "phone_number": "(555) 100-0002", "first_name": "Bob" },
{ "phone_number": "(555) 100-0003", "first_name": "Carol" }
],
"list_ids": ["uuid-of-list"]
}
{
"total_submitted": 3,
"created": 2,
"duplicates_skipped": 1,
"errors": 0
}
Lists
Organize contacts into targeted groups.
/lists
Read Only
Returns all contact lists with pagination.
{
"items": [
{
"id": "uuid",
"name": "Hot Leads",
"description": "High priority contacts",
"contact_count": 42,
"created_at": "2026-01-10T08:00:00Z"
}
],
"total": 5
}
/lists
Contacts Only
Creates a new contact list.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | List name |
description | string | No | List description |
/lists/{id}
Read Only
Returns details for a single list.
/lists/{id}
Contacts Only
Updates a list's name or description.
/lists/{id}
Contacts Only
Deletes a list. Contacts in the list are not deleted.
Campaigns
View and control your outreach campaigns.
/campaigns
Read Only
Returns all campaigns.
{
"items": [
{
"id": "uuid",
"name": "Spring Outreach",
"status": "ACTIVE",
"created_at": "2026-02-01T09:00:00Z"
}
],
"total": 3
}
/campaigns/{id}
Read Only
Returns details for a single campaign.
/campaigns/{id}/start
Campaigns Only
Starts a campaign. The campaign must be in a startable state.
/campaigns/{id}/stop
Campaigns Only
Stops a running campaign.
Webhooks
Receive real-time event data pushed to your external systems.
| Event | Description |
|---|---|
appointment_scheduled | Fires when a call is scheduled. Includes contact name, phone, and time. |
contact_opted_out | Fires when a contact opts out of receiving messages. |
call_completed | Fires when a call attempt completes (connected, missed, or failed). |
campaign_engagement_completed | Fires when the campaign finishes engaging a contact. |
Webhook Setup
Sent as POST requests with JSON body
Includes a signing secret for verification
Failed deliveries are logged in the app
Error Handling
API errors return standard HTTP status codes with a JSON body.
{
"detail": "Contact not found"
}
| Code | Meaning |
|---|---|
| 200 | Success |
| 201 | Created |
| 400 | Bad request (invalid data) |
| 401 | Unauthorized (missing or invalid API key) |
| 403 | Forbidden (insufficient scope) |
| 404 | Resource not found |
| 422 | Validation error (check request body) |
| 429 | Rate limited |
| 500 | Server error |
Rate Limits
API requests are subject to rate limiting. If you exceed the limit, you will receive a 429 response. Wait and retry after a short delay.
cURL Examples
Quick-start examples you can run in your terminal.
curl -H "X-API-Key: your_key_here" \
https://company.arnis.ai/api/v1/contacts
curl -X POST \
-H "X-API-Key: your_key_here" \
-H "Content-Type: application/json" \
-d '{"phone_number": "(555) 123-4567", "first_name": "John"}' \
https://company.arnis.ai/api/v1/contacts
curl -X POST \
-H "X-API-Key: your_key_here" \
-H "Content-Type: application/json" \
-d '{
"contacts": [
{"phone_number": "(555) 200-0001", "first_name": "Alice"},
{"phone_number": "(555) 200-0002", "first_name": "Bob"}
],
"list_ids": ["your-list-uuid"]
}' \
https://company.arnis.ai/api/v1/contacts/batch
curl -X POST \
-H "X-API-Key: your_key_here" \
https://company.arnis.ai/api/v1/campaigns/your-campaign-uuid/start