Skip to main content

Endpoint

POST https://api.graine.ai/api/v1/campaigns/ Also available as POST /campaigns/create (Merlin alias — identical behaviour).

Headers

HeaderRequiredDescription
AuthorizationYesBearer gat_<token>
Content-TypeYesapplication/json

Request Body

FieldTypeRequiredDescription
namestringYesHuman-readable campaign name
agent_idstringYesID of the AI agent that will make calls
phone_numbersstring[]YesOne or more E.164 outbound caller IDs
organization_idstringNoDefaults to the token’s org
phone_number_strategystringNoround_robin (default) · random · least_loaded
working_hours_enforcedbooleanNoWhether to enforce the per-day calling windows
timezonestringNoIANA timezone string (e.g. Asia/Kolkata). Applies to working_hours
working_hoursobjectNoPer-day schedule — see schema below
retry_policyobjectNoRetry configuration — see schema below
default_call_variablesobjectNoKey-value pairs merged into every contact’s call context
metadataobjectNoArbitrary metadata. concurrency_limit controls max parallel calls

working_hours schema

{
  "monday":    { "start": "09:00", "end": "18:00", "enabled": true },
  "tuesday":   { "start": "09:00", "end": "18:00", "enabled": true },
  "wednesday": { "start": "09:00", "end": "18:00", "enabled": true },
  "thursday":  { "start": "09:00", "end": "18:00", "enabled": true },
  "friday":    { "start": "09:00", "end": "18:00", "enabled": true },
  "saturday":  { "start": "10:00", "end": "14:00", "enabled": false },
  "sunday":    { "start": "10:00", "end": "14:00", "enabled": false }
}
Times are in HH:MM 24-hour format. Days where enabled: false never receive calls.

retry_policy schema

FieldTypeDefaultDescription
max_retriesinteger3Total retry attempts per contact
strategystringfixedfixed or exponential backoff
cooldown_minutesinteger30Wait time between retry attempts
callee_name should live in each contact’s call_variables, not in default_call_variables. The AI uses it in its greeting — if it’s missing the agent cannot address the person by name.

Example Request

{
  "name": "Q2 Insurance Renewals",
  "organization_id": "org_xyz",
  "agent_id": "agent_abc123",
  "phone_numbers": ["+919876543210", "+919876543211"],
  "phone_number_strategy": "round_robin",
  "working_hours_enforced": true,
  "timezone": "Asia/Kolkata",
  "working_hours": {
    "monday":    { "start": "09:00", "end": "18:00", "enabled": true },
    "tuesday":   { "start": "09:00", "end": "18:00", "enabled": true },
    "wednesday": { "start": "09:00", "end": "18:00", "enabled": true },
    "thursday":  { "start": "09:00", "end": "18:00", "enabled": true },
    "friday":    { "start": "09:00", "end": "18:00", "enabled": true },
    "saturday":  { "start": "10:00", "end": "14:00", "enabled": false },
    "sunday":    { "start": "10:00", "end": "14:00", "enabled": false }
  },
  "retry_policy": {
    "max_retries": 3,
    "strategy": "fixed",
    "cooldown_minutes": 30
  },
  "default_call_variables": {
    "language": "en",
    "product": "Health Insurance"
  },
  "metadata": {
    "concurrency_limit": 20
  }
}

Responses

200 OK

{
  "campaign_id": "cmp_abc123",
  "name": "Q2 Insurance Renewals",
  "status": "draft",
  "organization_id": "org_xyz",
  "agent_id": "agent_abc123"
}
Save the returned campaign_id — you’ll need it when creating batches.

400 Bad Request

{ "detail": "agent_id is required" }

401 Unauthorized

{ "detail": "Invalid or expired token" }

Code Examples

import requests

url = "https://api.graine.ai/api/v1/campaigns/"
headers = {
    "Authorization": "Bearer gat_your_token",
    "Content-Type": "application/json"
}
payload = {
    "name": "Q2 Insurance Renewals",
    "agent_id": "agent_abc123",
    "phone_numbers": ["+919876543210"],
    "timezone": "Asia/Kolkata",
    "retry_policy": {
        "max_retries": 3,
        "strategy": "fixed",
        "cooldown_minutes": 30
    }
}

response = requests.post(url, json=payload, headers=headers)
campaign = response.json()
print(campaign["campaign_id"])
const response = await fetch("https://api.graine.ai/api/v1/campaigns/", {
  method: "POST",
  headers: {
    "Authorization": "Bearer gat_your_token",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    name: "Q2 Insurance Renewals",
    agent_id: "agent_abc123",
    phone_numbers: ["+919876543210"],
    timezone: "Asia/Kolkata",
    retry_policy: { max_retries: 3, strategy: "fixed", cooldown_minutes: 30 }
  })
});

const campaign = await response.json();
console.log(campaign.campaign_id);

Next Steps

Create a Batch

Upload contacts and start dispatching

Campaign Lifecycle

Pause, resume, or cancel