Guides

Batches

Call a list of contacts from a CSV file, on a schedule, with skipped rows explained.

A batch is a CSV of contacts plus an agent. You upload it, schedule it, and the platform creates one call per row. Every call in a batch is a normal execution: it gets its own transcript, cost and webhooks.

In the dashboard: Deploy → Batches.

The CSV

text
contact_number,name,due_date,consent
+919876500123,Asha,20 October,yes
+919876500124,Ravi,22 October,yes
+919876500125,Meera,25 October,
  • A contact_number column is required. Without it: The CSV must have a contact_number column.
  • Numbers must be E.164. Spaces and hyphens inside a number are removed first. A row whose number is still invalid is dropped and counted only in total_contacts.
  • Every other column becomes a variable for that call, exactly like user_data in Outbound calling.
  • consent is a special column when your account requires consent; see Compliance. Values read as consent: 1, true, yes, y, consent, given, haan, हाँ.
  • The file must be text. A spreadsheet or PDF renamed to .csv is refused.

Create a batch

bash
curl -X POST https://api.sevennadi.si/batches \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef" \
  -F "agent_id=3c90c3cc-0d44-4b50-8822-8dd25736052a" \
  -F "file=@contacts.csv" \
  -F "from_phone_numbers=+918012345678" \
  -F 'retry_config={"enabled": true, "max_retries": 2}' \
  -F "webhook_url=https://hooks.example.test/batch"

Response, 201:

json
{
  "batch_id": "5f0c2d7e9a1b4c3d8e6f7a8b9c0d1e2f",
  "state": "created",
  "valid_contacts": 3,
  "total_contacts": 3,
  "skipped_contacts": 1,
  "skipped_rows": [
    {"contact_number": "+919876500125", "reason": "no consent: the row has no consent and the account requires it"}
  ]
}
Form fieldMeaning
agent_idRequired
fileRequired. The CSV
from_phone_numbersCaller IDs. Repeat the field, or send a JSON array or a comma-separated list. Rows rotate through them in order
retry_configA JSON object, as for single calls. max_retries must be 1 to 3
webhook_urlWhere this batch's call webhooks go, instead of the agent's URL

skipped_rows at this point is a preview: rows on your do-not-call list, rows without consent when it is required, and numbers on the do-not-disturb registry when dnd_check is block. Nothing has been called yet.

Schedule it

A batch does nothing until it is scheduled.

bash
curl -X POST https://api.sevennadi.si/batches/5f0c2d7e9a1b4c3d8e6f7a8b9c0d1e2f/schedule \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef" \
  -F "scheduled_at=2026-10-14T10:30:00+05:30" \
  -F "bypass_call_guardrails=false"
json
{"message": "success", "state": "scheduled"}

The time needs a UTC offset and must be at least two minutes ahead. Start times are rounded up to the next ten minutes. You can schedule again to move a batch that is still created or scheduled; later it answers 400 with Batch is already running (or its status).

What happens at the start time

For each row the compliance rules are applied again, now including the per-number daily cap:

  • A row that fails is not called. It is added to the batch's skipped_rows with the reason.
  • A row outside the agent's calling hours, in that recipient's timezone, becomes a rescheduled call for the next allowed start.
  • Every other row becomes a queued call.

All calls are queued together. Your account's concurrency limit decides how many run at once; the rest wait their turn.

Follow a batch

bash
curl https://api.sevennadi.si/batches/5f0c2d7e9a1b4c3d8e6f7a8b9c0d1e2f \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"
json
{
  "batch_id": "5f0c2d7e9a1b4c3d8e6f7a8b9c0d1e2f",
  "status": "running",
  "scheduled_at": "2026-10-14T05:00:00Z",
  "file_name": "contacts.csv",
  "valid_contacts": 3,
  "total_contacts": 3,
  "from_phone_number": "+918012345678",
  "from_phone_numbers": ["+918012345678"],
  "execution_status": {"completed": 1, "in-progress": 1},
  "skipped_contacts": 1,
  "skipped_rows": [{"contact_number": "+919876500125", "reason": "no consent: the row has no consent and the account requires it"}],
  "created_at": "2026-10-13T09:40:00Z",
  "updated_at": "2026-10-13T09:41:10Z",
  "humanized_created_at": "1 minute ago"
}
Batch statusMeaning
createdUploaded, not scheduled
scheduledWaiting for its start time
runningCalls are queued or in progress
completedEvery call reached a final status. A call waiting for an automatic retry is not final
stoppedYou stopped it
failedThe agent was deleted before the start time

execution_status counts the batch's calls by call status. GET /batches/{agent_id}/all lists an agent's batches.

Executions

GET /v2/batches/{batch_id}/executions returns the calls, paged (page_number from 1, page_size 1 to 50, default 20):

json
{"page_number": 1, "page_size": 20, "total": 2, "has_more": false, "data": [{"id": "...", "status": "completed", "batch_id": "5f0c2d7e9a1b4c3d8e6f7a8b9c0d1e2f"}]}

Each execution of a batch also carries batch_run_details with its status and how often it was retried. GET /batches/{batch_id}/executions returns the same calls as one unpaged list.

Stop or delete

  • POST /batches/{batch_id}/stop: calls not yet dialled become stopped; live calls are hung up. Answers {"message": "success", "state": "stopped"}. A batch that is not scheduled or running answers 404 with Batch is not queued or running.
  • DELETE /batches/{batch_id}: stops it if active, then removes it from lists.

When the balance runs out

A batch is not burnt through at zero balance. It stays running, GET /batches/{batch_id} shows "paused_reason": "balance-low", and its remaining calls stay queued. After a top-up they are queued again automatically. See Billing.

Limitations

  • Rows are stored with the batch; there is no endpoint to add or edit rows after upload. Create a new batch instead.
  • skipped_rows in the create response is only a preview. The daily cap depends on the day the batch runs, so the final list is set at the start time.
  • If your account is restricted to verified numbers, a batch containing unverified numbers is refused with 403, listing up to five of them.
  • A stopped batch cannot be resumed.