# OnCallClerk API Reference

> Base URL: `https://api.oncallclerk.com`
> Version: v1
> Last updated: 2026-03-12

## Authentication

All API requests require a Bearer token in the `Authorization` header.

```
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
```

API keys can be generated from the OnCallClerk dashboard settings. Each key is scoped to your account and has full access to all endpoints.

---

## Agents

Create, manage, and configure AI voice agents.

### List Agents

```
GET /agents
```

Returns all voice agents associated with your account.

**Response:**

```json
{
  "success": true,
  "data": [
    {
      "id": "agt_abc123",
      "business_name": "Acme Corp",
      "agent_name": "Reception",
      "phone_number": "+14155551234",
      "voice_id": "f5HLTX707KIM4SzJYzSz",
      "greeting": "Hello, thanks for calling Acme Corp!",
      "system_prompt": "You are a helpful receptionist...",
      "status": "active",
      "escalation_policy": "complex",
      "forwarding_number": "+14155559876",
      "created_at": "2025-01-15T10:30:00Z",
      "updated_at": "2025-01-20T14:00:00Z"
    }
  ]
}
```

### Get Agent

```
GET /agents/{agentId}
```

Retrieve a single voice agent by its ID.

**Path Parameters:**

| Parameter | Type   | Required | Description                          |
|-----------|--------|----------|--------------------------------------|
| agentId   | string | Yes      | The unique identifier of the agent.  |

**Response:**

```json
{
  "success": true,
  "data": {
    "id": "agt_abc123",
    "business_name": "Acme Corp",
    "agent_name": "Reception",
    "phone_number": "+14155551234",
    "phone_number_sid": "PN...",
    "voice_id": "f5HLTX707KIM4SzJYzSz",
    "greeting": "Hello, thanks for calling Acme Corp!",
    "system_prompt": "You are a helpful receptionist...",
    "voice_settings": {
      "personality": "friendly",
      "name": "Kevin"
    },
    "functions_enabled": ["calendar", "email"],
    "forwarding_number": "+14155559876",
    "escalation_number": "+14155550000",
    "escalation_policy": "complex",
    "business_hours": {
      "enabled": true,
      "timezone": "America/New_York",
      "schedule": {
        "monday": { "open": "09:00", "close": "17:00", "enabled": true },
        "tuesday": { "open": "09:00", "close": "17:00", "enabled": true },
        "wednesday": { "open": "09:00", "close": "17:00", "enabled": true },
        "thursday": { "open": "09:00", "close": "17:00", "enabled": true },
        "friday": { "open": "09:00", "close": "17:00", "enabled": true },
        "saturday": { "open": "00:00", "close": "00:00", "enabled": false },
        "sunday": { "open": "00:00", "close": "00:00", "enabled": false }
      }
    },
    "faq": [
      { "question": "What are your hours?", "answer": "We are open 9–5 Mon–Fri." }
    ],
    "status": "active",
    "created_at": "2025-01-15T10:30:00Z",
    "updated_at": "2025-01-20T14:00:00Z"
  }
}
```

### Create Agent

```
POST /agents
```

Create and deploy a new AI voice agent.

> **Note:** Every account starts with a default agent already created. Call `GET /agents` to see your existing agents and `GET /usage` to check your plan's agent limit before creating a new one.

**Request Body:**

| Parameter          | Type              | Required | Description                                                               |
|--------------------|-------------------|----------|---------------------------------------------------------------------------|
| business_name      | string            | Yes      | The business name the agent represents.                                   |
| agent_name         | string            | Yes      | A friendly name for the agent (e.g. 'Reception', 'Support').             |
| voice_id           | string            | Yes      | The ID of the voice to use. See the Voices endpoint for available options.|
| greeting           | string            | Yes      | The greeting spoken when a call is answered.                              |
| system_prompt      | string            | Yes      | Instructions that define the agent's behavior and personality.            |
| forwarding_number  | string            | No       | Phone number to forward calls to when escalation is triggered.            |
| escalation_number  | string            | No       | Dedicated escalation phone number.                                        |
| escalation_policy  | string            | No       | 'never' \| 'complex' \| 'requested' \| 'always'. Defaults to 'never'.   |
| business_hours     | BusinessHours     | No       | Business hours configuration. Omit or disable for 24/7.                   |
| faq                | FAQ[]             | No       | Array of FAQ entries the agent can reference during calls.                 |
| voice_settings     | VoiceSettings     | No       | Additional voice customization: personality and display name.              |
| functions_enabled  | string[]          | No       | Array of enabled function names (e.g. ["calendar", "email", "sheets"]). Defaults to []. |

**Example Request:**

```json
{
  "business_name": "Acme Corp",
  "agent_name": "Reception",
  "voice_id": "f5HLTX707KIM4SzJYzSz",
  "greeting": "Hello, thanks for calling Acme Corp! How can I help?",
  "system_prompt": "You are a professional receptionist for Acme Corp. Be friendly, answer questions about the business, and take messages when needed.",
  "escalation_policy": "complex",
  "forwarding_number": "+14155559876",
  "faq": [
    {
      "question": "What are your business hours?",
      "answer": "We are open Monday through Friday, 9am to 5pm Eastern."
    }
  ]
}
```

**Response:**

```json
{
  "success": true,
  "agent": {
    "id": "agt_abc123",
    "business_name": "Acme Corp",
    "agent_name": "Reception",
    "voice_id": "f5HLTX707KIM4SzJYzSz",
    "status": "active",
    "phone_number": null,
    "created_at": "2025-01-15T10:30:00Z"
  }
}
```

### Update Agent

```
PUT /agents/{agentId}
```

Update a voice agent's configuration. Only include the fields you want to change.

**Path Parameters:**

| Parameter | Type   | Required | Description                          |
|-----------|--------|----------|--------------------------------------|
| agentId   | string | Yes      | The unique identifier of the agent.  |

**Request Body:** Any fields from the Create Agent body. Only provided fields are updated.

**Example Request:**

```json
{
  "greeting": "Hi there! You've reached Acme Corp.",
  "escalation_policy": "always",
  "business_hours": {
    "enabled": true,
    "timezone": "America/Chicago",
    "schedule": {
      "monday": { "open": "08:00", "close": "18:00", "enabled": true },
      "tuesday": { "open": "08:00", "close": "18:00", "enabled": true },
      "wednesday": { "open": "08:00", "close": "18:00", "enabled": true },
      "thursday": { "open": "08:00", "close": "18:00", "enabled": true },
      "friday": { "open": "08:00", "close": "18:00", "enabled": true },
      "saturday": { "open": "10:00", "close": "14:00", "enabled": true },
      "sunday": { "open": "00:00", "close": "00:00", "enabled": false }
    }
  }
}
```

**Response:**

```json
{
  "success": true,
  "updatedAgent": {
    "id": "agt_abc123",
    "greeting": "Hi there! You've reached Acme Corp.",
    "escalation_policy": "always",
    "updated_at": "2025-01-21T09:15:00Z"
  }
}
```

### Delete Agent

```
DELETE /agents/{agentId}
```

Permanently delete a voice agent and release its phone number.

**Path Parameters:**

| Parameter | Type   | Required | Description                                  |
|-----------|--------|----------|----------------------------------------------|
| agentId   | string | Yes      | The unique identifier of the agent to delete. |

**Response:**

```json
{
  "success": true
}
```

> ⚠️ This action is irreversible. All transcripts for this agent will also be deleted.

### Assign Phone Number to Agent

```
POST /agents/{agentId}/phone
```

Assign or change the phone number for an agent. The number must first be acquired via the Phone Numbers endpoint.

**Path Parameters:**

| Parameter | Type   | Required | Description                          |
|-----------|--------|----------|--------------------------------------|
| agentId   | string | Yes      | The unique identifier of the agent.  |

**Request Body:**

| Parameter       | Type   | Required | Description                                              |
|-----------------|--------|----------|----------------------------------------------------------|
| requestedNumber | string | Yes      | The phone number to assign (E.164 format, e.g. '+14155551234'). |

**Example:**

```json
{
  "requestedNumber": "+14155551234"
}
```

---

### Configure Email Function

```
PUT /agent/{agentId}/functions/email
```

Enable the email function and set which recipients your agent is allowed to email. Accepts full email addresses (`james@example.com`) or entire domains (`@example.com`). Emails are sent from `agent@oncallclerk.com`.

**Path Parameters:**

| Parameter | Type   | Required | Description                          |
|-----------|--------|----------|--------------------------------------|
| agentId   | string | Yes      | The unique identifier of the agent.  |

**Request Body:**

| Parameter                    | Type     | Required | Description                                                                 |
|------------------------------|----------|----------|-----------------------------------------------------------------------------|
| enabled                      | boolean  | Yes      | Whether the email function is enabled.                                      |
| params.permitted_recipients  | string[] | Yes      | Allowed email addresses or domains. Use `@domain.com` to allow an entire domain. |

**Example:**

```json
{
  "enabled": true,
  "params": {
    "permitted_recipients": [
      "james@houses4cash.co.uk",
      "@houses4cash.co.uk"
    ]
  }
}
```

**Response:**

```json
{
  "success": true
}
```

---

## Phone Numbers

Search and acquire phone numbers to assign to your voice agents.

### Search Available Numbers

```
GET /phone-numbers/available
```

Search for available phone numbers that can be acquired and assigned to agents.

**Query Parameters:**

| Parameter | Type   | Required | Description                                    |
|-----------|--------|----------|------------------------------------------------|
| country   | string | No       | ISO country code. Defaults to 'US'.            |
| areaCode  | string | No       | Filter by area code (e.g. '415').              |
| contains  | string | No       | Search for numbers containing this string.     |
| pageSize  | number | No       | Number of results per page. Defaults to 10, max 50. |
| page      | number | No       | Page number for pagination. Starts at 0.       |

**Response:**

```json
{
  "success": true,
  "data": {
    "numbers": [
      {
        "phoneNumber": "+14155551234",
        "friendlyName": "(415) 555-1234",
        "region": "CA",
        "isoCountry": "US",
        "type": "local",
        "capabilities": {
          "voice": true,
          "SMS": true,
          "MMS": true
        }
      }
    ],
    "page": 0,
    "pageSize": 10,
    "country": "US"
  }
}
```

### Get Regulatory Bundles

```
GET /phone-numbers/regulatory-bundles/{isoCountry}
```

Get existing regulatory bundles for a specific country. Required for acquiring numbers in regulated countries (e.g. GB, DE, AU).

**Path Parameters:**

| Parameter  | Type   | Required | Description                                    |
|------------|--------|----------|------------------------------------------------|
| isoCountry | string | Yes      | Two-letter ISO country code (e.g. 'GB', 'DE'). |

**Response:**

```json
{
  "success": true,
  "data": {
    "bundles": [
      {
        "sid": "BU...",
        "status": "twilio-approved",
        "isoCountry": "GB",
        "name": "Acme Corp - GB Bundle"
      }
    ]
  }
}
```

### Create Regulatory Bundle

```
POST /phone-numbers/regulatory-bundle
```

Create a new regulatory bundle for a country. Submit business or individual compliance data along with identity documents.

**Request Body:**

| Parameter       | Type                         | Required | Description                                 |
|-----------------|------------------------------|----------|---------------------------------------------|
| isoCountryCode  | string                       | Yes      | Two-letter ISO country code.                |
| complianceType  | 'business' \| 'individual'   | No       | Type of compliance submitter. Defaults to 'business'. |
| complianceData  | ComplianceData               | No       | Business or individual compliance details.  |
| proofOfIdentity | File                         | No       | Identity document upload (multipart/form-data). |
| proofOfAddress  | File                         | No       | Address verification document (multipart/form-data). |

**ComplianceData for business type:**

- `businessName`, `registrationAuthority`, `registrationNumber`, `website`
- `businessStreet`, `businessCity`, `businessRegion`, `businessPostalCode`, `businessCountry`
- `repFirstName`, `repLastName`, `repPhoneNumber`, `repEmail`

**ComplianceData for individual type:**

- `firstName`, `lastName`, `email`, `phoneNumber`, `birthDate`
- `individualStreet`, `individualCity`, `individualRegion`, `individualPostalCode`, `individualCountry`

**Response:**

```json
{
  "success": true,
  "bundleSid": "BU..."
}
```

---

## Transcripts

Access call transcripts, summaries, and conversation logs for your agents.

### List Transcripts

```
GET /agents/{agentId}/transcripts
```

Get all call transcripts for a specific agent, ordered by most recent first.

**Path Parameters:**

| Parameter | Type   | Required | Description                          |
|-----------|--------|----------|--------------------------------------|
| agentId   | string | Yes      | The unique identifier of the agent.  |

**Query Parameters:**

| Parameter | Type   | Required | Description                                                                         |
|-----------|--------|----------|-------------------------------------------------------------------------------------|
| limit     | number | No       | Maximum number of transcripts to return. Defaults to 50.                             |
| offset    | number | No       | Number of transcripts to skip for pagination.                                        |
| type      | string | No       | Filter by call type: 'Sales Inquiry', 'Support Request', 'General Info', 'Complaint', 'Feedback', 'Booking', 'Cancellation'. |
| outcome   | string | No       | Filter by outcome: 'Resolved', 'Escalated', 'Follow-up Required', 'Lead Captured', etc. |

**Response:**

```json
{
  "success": true,
  "data": {
    "transcripts": [
      {
        "id": "tr_xyz789",
        "date": "2025-01-20",
        "time": "14:32:00",
        "duration": 185,
        "duration_minutes": 3.08,
        "caller": "+14155559999",
        "type": "Sales Inquiry",
        "outcome": "Lead Captured",
        "rating": 5,
        "summary": "Caller asked about pricing for the enterprise plan. Expressed interest in a demo. Contact info captured.",
        "conversation": [
          { "speaker": "agent", "text": "Hello, thanks for calling Acme Corp!" },
          { "speaker": "caller", "text": "Hi, I wanted to ask about your pricing." },
          { "speaker": "agent", "text": "Of course! We have three plans..." }
        ],
        "agentId": "agt_abc123",
        "created_at": "2025-01-20T14:32:00Z"
      }
    ]
  }
}
```

### Get Transcript

```
GET /agents/{agentId}/transcripts/{transcriptId}
```

Retrieve a single transcript by ID with full conversation log.

**Path Parameters:**

| Parameter    | Type   | Required | Description                               |
|--------------|--------|----------|-------------------------------------------|
| agentId      | string | Yes      | The unique identifier of the agent.       |
| transcriptId | string | Yes      | The unique identifier of the transcript.  |

---

## Voices

Browse available AI voices for your agents.

### List Voices

```
GET /voices
```

Returns all available voices that can be assigned to agents.

**Response:**

```json
{
  "success": true,
  "data": [
    {
      "id": "f5HLTX707KIM4SzJYzSz",
      "name": "Kevin",
      "accent": "American",
      "description": "Professional, warm, and articulate",
      "gender": "Male"
    },
    {
      "id": "KR1TkIhkSykEjI4B0DtH",
      "name": "Sarah",
      "accent": "American",
      "description": "Confident, friendly, and approachable",
      "gender": "Female"
    }
  ]
}
```

**Available Voices:**

| Name    | ID                     | Accent     | Gender | Description                          |
|---------|------------------------|------------|--------|--------------------------------------|
| Kevin   | f5HLTX707KIM4SzJYzSz  | American   | Male   | Professional, warm, and articulate   |
| Sarah   | KR1TkIhkSykEjI4B0DtH  | American   | Female | Confident, friendly, and approachable|
| Lucy    | 4BWwbsA70lmV7RMG0Acs  | British    | Female | Energetic, clear, and engaging       |
| Jake    | YLbQE9U7P1K6rBNJWNSv  | Australian | Male   | Young, reliable, and professional    |
| Dominic | h2I5OFX58E5TL5AitYwR  | American   | Male   | Elegant, sophisticated, and charming |
| Ava     | kdmDKE6EkgrWrrykO9Qt  | American   | Female | Elegant, sophisticated, and charming |
| Elise   | EST9Ui6982FZPSi7gCHi  | American   | Female | Professional and friendly             |
| Ryan    | 4e32WqNVWRquDa1OcRYZ  | American   | Male   | Professional and friendly             |
| Jon     | 7WggD3IoWTIPT19PNyrW  | American   | Male   | Knowing and poised                    |

---

## User

Manage your account profile and settings.

### Get Profile

```
GET /user
```

Retrieve the authenticated user's profile.

**Response:**

```json
{
  "success": true,
  "data": {
    "firstName": "Jane",
    "lastName": "Doe",
    "email": "jane@acmecorp.com",
    "company": "Acme Corp",
    "timezone": "America/New_York",
    "personalPhoneNumber": "+14155559876",
    "emailNotifications": true,
    "callNotifications": true,
    "weeklyReports": false
  }
}
```

### Update Profile

```
PUT /user
```

Update the authenticated user's profile. Only include fields to change.

**Request Body:**

| Parameter            | Type    | Required | Description                                     |
|----------------------|---------|----------|-------------------------------------------------|
| firstName            | string  | No       | First name.                                     |
| lastName             | string  | No       | Last name.                                      |
| company              | string  | No       | Company or business name.                       |
| timezone             | string  | No       | IANA timezone string (e.g. 'America/New_York'). |
| personalPhoneNumber  | string  | No       | Personal contact phone number.                  |
| emailNotifications   | boolean | No       | Enable email notifications.                     |
| callNotifications    | boolean | No       | Enable call event notifications.                |
| weeklyReports        | boolean | No       | Enable weekly performance reports via email.    |

### Delete Account

```
DELETE /user
```

Permanently delete the authenticated user's account, all agents, and all data.

**Response:**

```json
{
  "success": true
}
```

> ⚠️ This action is irreversible. All agents, phone numbers, transcripts, and settings will be permanently deleted.

---

## Subscription

Query your current subscription status and usage.

### Get Subscription

```
GET /subscription
```

Get the current subscription plan and usage limits for your account.

**Response:**

```json
{
  "success": true,
  "data": {
    "subscription": {
      "plan": "professional",
      "status": "active",
      "current_period_start": "2025-01-01T00:00:00Z",
      "current_period_end": "2025-02-01T00:00:00Z",
      "cancel_at_period_end": false
    },
    "usage": {
      "used": 142,
      "limit": 500
    }
  }
}
```

---

## Usage

Retrieve current usage and limits for your account.

### Get Usage

```
GET /usage
```

Returns your current plan, agent count, minute consumption, and billing period.

**Response:**

```json
{
  "success": true,
  "data": {
    "plan": "growth",
    "agents": {
      "used": 2,
      "limit": 3,
      "remaining": 1
    },
    "minutes": {
      "used": 142.3,
      "limit": 600,
      "remaining": 457.7
    },
    "phone_numbers": {
      "allowed": true
    },
    "billing_period": {
      "start": 1712016000,
      "end": 1714694400
    }
  }
}
```

**Response Fields:**

| Field | Type | Description |
|---|---|---|
| plan | string | Current plan name (e.g. `starter`, `growth`, `professional`) |
| agents.used | number | Number of agents currently created |
| agents.limit | number | Maximum agents allowed on your plan |
| agents.remaining | number | How many more agents you can create |
| minutes.used | number | Minutes consumed in the current billing period |
| minutes.limit | number | Total minutes included in your plan |
| minutes.remaining | number | Minutes remaining in the current billing period |
| phone_numbers.allowed | boolean | Whether phone numbers can be assigned. `false` when the account has no active subscription. |
| billing_period.start | number | Billing period start (Unix timestamp) |
| billing_period.end | number | Billing period end (Unix timestamp) |

---

## Errors

The API uses standard HTTP status codes and returns consistent error objects.

**Error Response Format:**

```json
{
  "success": false,
  "error": "Agent not found",
  "status": 404
}
```

**Status Codes:**

| Code | Description                                                                |
|------|----------------------------------------------------------------------------|
| 200  | Success. The request was completed as expected.                            |
| 201  | Created. A new resource was successfully created.                          |
| 400  | Bad Request. The request body is missing required fields or has invalid values. |
| 401  | Unauthorized. API key is missing, invalid, or expired.                     |
| 403  | Forbidden. You don't have permission to access this resource.              |
| 404  | Not Found. The requested resource does not exist.                          |
| 409  | Conflict. The resource already exists or there is a state conflict.        |
| 429  | Too Many Requests. Rate limit exceeded. Retry after the specified interval.|
| 500  | Internal Server Error. Something went wrong on our end.                    |

---

## Rate Limits

| Plan          | Limit              |
|---------------|--------------------|
| Starter       | 60 requests/min    |
| Professional  | 300 requests/min   |
| Enterprise    | Custom             |

---

## Type Reference

### VoiceAgentConfig

```typescript
interface VoiceAgentConfig {
  id: string
  business_name: string
  agent_name: string
  phone_number: string | null
  phone_number_sid: string | null
  voice_id: string
  greeting: string
  system_prompt: string
  voice_settings: VoiceSettings
  functions_enabled: string[]   // Array of enabled function names
  forwarding_number: string | null
  escalation_number: string | null
  escalation_policy: 'never' | 'complex' | 'requested' | 'always'
  business_hours: BusinessHours
  faq: FAQ[]
  status: 'active' | 'inactive' | 'suspended'
  created_at: string
  updated_at: string
}
```

### BusinessHours

```typescript
interface BusinessHours {
  enabled: boolean           // false = agent runs 24/7
  timezone: string           // IANA timezone (e.g. "America/New_York")
  schedule: {
    [day: string]: {
      open: string           // "09:00"
      close: string          // "17:00"
      enabled: boolean
    }
  }
}
```

### FAQ

```typescript
interface FAQ {
  question: string
  answer: string
}
```

### VoiceSettings

```typescript
interface VoiceSettings {
  personality?: string
  name?: string
}
```

### AgentTranscript

```typescript
interface AgentTranscript {
  id: string
  date: string
  time: string
  duration: number           // seconds
  duration_minutes: number
  caller: string             // E.164 phone number
  type: TranscriptType
  outcome: CallOutcome
  rating: number
  summary: string
  conversation: { speaker: 'agent' | 'caller'; text: string }[]
  agentId: string
  created_at: string
}

type TranscriptType =
  | 'Sales Inquiry'
  | 'Support Request'
  | 'General Info'
  | 'Complaint'
  | 'Feedback'
  | 'Booking'
  | 'Cancellation'

type CallOutcome =
  | 'Resolved'
  | 'Unresolved'
  | 'Escalated'
  | 'Follow-up Required'
  | 'Information Provided'
  | 'Lead Captured'
  | 'Cancelled'
  | 'No Action'
  | 'Unknown'
```

### AvailableNumber

```typescript
interface AvailableNumber {
  phoneNumber: string
  friendlyName: string
  region: string
  isoCountry: string
  type: string
  capabilities: {
    voice: boolean
    SMS: boolean
    MMS: boolean
  }
}
```

### RegulatoryBundle

```typescript
interface RegulatoryBundle {
  sid: string
  status: 'draft' | 'pending-review' | 'in-review' | 'twilio-approved' | 'provisionally-approved' | 'rejected' | 'canceled'
  isoCountry: string
  name: string
}
```

### UserProfile

```typescript
interface UserProfile {
  firstName?: string
  lastName?: string
  email?: string
  company?: string
  timezone?: string
  personalPhoneNumber?: string
  emailNotifications?: boolean
  callNotifications?: boolean
  weeklyReports?: boolean
}
```
