---
title: "Batch Call Upload"
url: https://docs.aila.fyi/api-reference/batch-upload
source: https://docs.aila.fyi/llms.txt
---

# Batch Call Upload

Upload 1 to 100 call recordings to Aila in one asynchronous request. Use it to send calls from a system Aila doesn't connect to directly, or to backfill history.

**Before you start:**
- Your API key needs the `calls:write` scope. See [Authentication](https://docs.aila.fyi/api-reference/authentication).
- Your organization needs the API upload connection enabled. If the request returns `404 Upload connection not found`, email [support@aila.fyi](mailto:support@aila.fyi).

---

## Endpoint Specification
```http
POST https://app.aila.fyi/api/v1/calls/upload/batch
Authorization: Bearer <YOUR_API_KEY>
Content-Type: application/json
```
### Request Body Schema

| Field | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| `calls` | Array | Yes | Array of 1 to 100 call objects. |
| `calls[].audio_url` | String (URL) | Yes | URL Aila can download the audio from. Aila copies the file into its own storage. |
| `calls[].recorded_at` | String (ISO 8601) | Yes | Timestamp when the call occurred. |
| `calls[].agent_name` | String | Yes | Name of the team member on the call. |
| `calls[].agent_email` | String (Email) | Yes | Email of the team member. If no Aila user has this email, Aila creates one as a **Member** and adds them to your organization. |
| `calls[].contact_name` | String | No | Customer or lead name. |
| `calls[].contact_phone` | String | No | Customer phone number in E.164 format. |
| `calls[].duration` | Integer | No | Call length in seconds. |
| `calls[].external_id` | String | No | ID from your dialer or telephony system. |
| `calls[].tags` | `Array ` | No | Up to 10 metadata tags. |
| `calls[].metadata` | Object | No | Key-value dictionary of custom metadata. |

### Example Request
```json
{
  "calls": [
    {
      "audio_url": "https://storage.example.com/recordings/call_001.mp3",
      "recorded_at": "2026-08-24T14:30:00Z",
      "agent_name": "Sarah Connor",
      "agent_email": "sarah@company.com",
      "contact_name": "John Smith",
      "contact_phone": "+15551234567",
      "external_id": "dialer_rec_987"
    }
  ]
}
```
### Response

The API returns `202 Accepted`:
```json
{
  "success": true,
  "data": {
    "batch_id": "ai_call_batch_...",
    "total_calls": 2,
    "status": "queued",
    "calls": [
      { "call_id": "ai_call_...", "external_id": "dialer_rec_987", "status": "queued" },
      { "call_id": null, "external_id": "dialer_rec_988", "status": "failed", "error": "..." }
    ],
    "status_url": "https://app.aila.fyi/api/v1/batches/ai_call_batch_..."
  }
}
```
A batch can partly succeed. Check each call's `status`; failed calls have `call_id: null` and an `error`.

---

## Polling Batch Status

Query batch progress using the status URL:
```http
GET https://app.aila.fyi/api/v1/batches/{batch_id}
Authorization: Bearer <YOUR_API_KEY>
```
### Batch Status Response
```json
{
  "success": true,
  "data": {
    "batch_id": "batch_abc123",
    "total_calls": 10,
    "processed": 8,
    "failed": 0,
    "in_progress": 2,
    "status": "processing",
    "progress_percentage": 80,
    "calls": [
      { "call_id": "ai_call_...", "external_id": "dialer_rec_987", "status": "complete" }
    ],
    "created_at": "2026-09-30T14:30:00.000Z",
    "estimated_completion": "2026-09-30T14:40:00.000Z"
  }
}
```
Batch `status` is `queued`, `processing`, `completed`, or `failed`. Each call's `status` is `queued`, `processing`, `complete`, or `failed`.

Subscribe to the [`call.completed` webhook](https://docs.aila.fyi/api-reference/webhooks) instead of polling if you need to act on each call.
