Endpoint
POST https://api.graine.ai/api/v1/campaigns/
Also available as POST /campaigns/create (Merlin alias — identical behaviour).
Header Required Description AuthorizationYes Bearer gat_<token>Content-TypeYes application/json
Request Body
Field Type Required Description namestring Yes Human-readable campaign name agent_idstring Yes ID of the AI agent that will make calls phone_numbersstring[] Yes One or more E.164 outbound caller IDs organization_idstring No Defaults to the token’s org phone_number_strategystring No round_robin (default) · random · least_loadedworking_hours_enforcedboolean No Whether to enforce the per-day calling windows timezonestring No IANA timezone string (e.g. Asia/Kolkata). Applies to working_hours working_hoursobject No Per-day schedule — see schema below retry_policyobject No Retry configuration — see schema below default_call_variablesobject No Key-value pairs merged into every contact’s call context metadataobject No Arbitrary 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
Field Type Default Description max_retriesinteger 3Total retry attempts per contact strategystring fixedfixed or exponential backoffcooldown_minutesinteger 30Wait 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