Skip to main content

Endpoint

POST https://api.graine.ai/api/v1/batches/ Also available as POST /batches/upload (Merlin alias — identical behaviour). Creating a batch immediately begins dispatching calls to all contacts (unless scheduled_start is set).

Headers

HeaderRequiredDescription
AuthorizationYesBearer gat_<token>
Content-TypeYesapplication/json

Request Body

FieldTypeRequiredDescription
campaign_idstringYesThe campaign this batch belongs to
contactsContact[]YesList of contacts to call (see schema below)
organization_idstringNoDefaults to token’s org
scheduled_startdatetimeNoWhen to begin dispatching. null = immediately
concurrency_limitintegerNoMax concurrent calls. Overrides campaign setting
max_retries_overrideintegerNoOverrides campaign.retry_policy.max_retries for this batch
call_contextobjectNoAdditional context passed to the telephony layer
metadataobjectNoArbitrary metadata stored with the batch

Contact schema

FieldTypeRequiredDescription
phone_numberstringYesE.164 format (e.g. +919876543210)
call_variablesobjectNoPer-contact substitution variables for the agent
callee_name must be in call_variables for each contact (not in campaign default_call_variables). The AI agent uses this in its greeting — without it, the agent cannot address the person by name.

scheduled_start timezone handling

ValueBehaviour
null (default)Dispatch begins immediately
Naive datetime (no Z / offset)Interpreted in the campaign’s timezone (e.g. "2026-05-10T11:00:00" → 11 AM IST)
UTC datetime (with Z)Used as-is

Example Request

{
  "campaign_id": "cmp_abc123",
  "organization_id": "org_xyz",
  "contacts": [
    {
      "phone_number": "+919876543210",
      "call_variables": {
        "callee_name": "Rajesh Sharma",
        "current_plan": "Basic Health",
        "renewal_date": "2026-07-01",
        "premium": "12000"
      }
    },
    {
      "phone_number": "+919876543211",
      "call_variables": {
        "callee_name": "Priya Mehta",
        "current_plan": "Family Floater",
        "renewal_date": "2026-06-15",
        "premium": "28000"
      }
    }
  ],
  "concurrency_limit": 10,
  "scheduled_start": null
}

Schedule for a specific time

{
  "campaign_id": "cmp_abc123",
  "contacts": [...],
  "scheduled_start": "2026-05-12T09:00:00"
}
This starts at 9:00 AM in the campaign’s timezone (e.g. Asia/Kolkata).

Responses

200 OK

{
  "batch_id": "btc_xyz001",
  "campaign_id": "cmp_abc123",
  "organization_id": "org_xyz",
  "status": "in_progress",
  "total_contacts": 2,
  "created_at": "2026-05-10T09:00:00Z"
}
Save the returned batch_id — use it to track progress, export results, or pause/cancel this batch independently.

400 Bad Request

{ "detail": "campaign_id is required" }

404 Not Found

{ "detail": "Campaign not found or does not belong to this org" }

Code Examples

import requests

url = "https://api.graine.ai/api/v1/batches/"
headers = {
    "Authorization": "Bearer gat_your_token",
    "Content-Type": "application/json"
}
payload = {
    "campaign_id": "cmp_abc123",
    "contacts": [
        {
            "phone_number": "+919876543210",
            "call_variables": {
                "callee_name": "Rajesh Sharma",
                "current_plan": "Basic Health",
                "renewal_date": "2026-07-01",
                "premium": "12000"
            }
        }
    ],
    "concurrency_limit": 10
}

response = requests.post(url, json=payload, headers=headers)
batch = response.json()
print(batch["batch_id"])
const response = await fetch("https://api.graine.ai/api/v1/batches/", {
  method: "POST",
  headers: {
    "Authorization": "Bearer gat_your_token",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    campaign_id: "cmp_abc123",
    contacts: [
      {
        phone_number: "+919876543210",
        call_variables: {
          callee_name: "Rajesh Sharma",
          current_plan: "Basic Health",
          renewal_date: "2026-07-01",
          premium: "12000"
        }
      }
    ],
    concurrency_limit: 10
  })
});

const batch = await response.json();
console.log(batch.batch_id);

Next Steps

Monitor Contacts

Track per-contact call status

Export Results

Download call outcomes as CSV

Pause or Cancel

Control batch execution mid-flight

Troubleshoot Stuck Batch

Debug why calls aren’t going out