Graine AI
API referenceCampaigns

Resume a campaign

Start dialling again from where the pause left off.

Start dialling again from where the pause left off.

Every batch this campaign paused is resumed with it. Contacts keep their remaining retries, and the working hours still apply — resuming outside the dialling window queues the work for the next open one rather than dialling immediately.

409 when there is nothing to resume. A cancelled campaign cannot be restarted: cancelling skipped its undialled contacts and removed their scheduled jobs, so "resuming" it would silently do nothing. Completed and archived campaigns answer 409 for the same reason. An expired campaign has run past its end_time; push that forward with PATCH and it re-activates on its own.

Rate limit: 2000 requests per minute per organization, counted together with every endpoint that has no stricter limit of its own. Exceeding it returns 429 with Retry-After; the X-RateLimit-* response headers report your remaining allowance on every call.

POST
/v2/campaigns/{campaign_id}/resume
/v2/campaigns/31ff3ea9-8bb5-433f-868f-286ac3c31328/resume

The Authorization access token

Authorization

Authorization
Required
Bearer <token>

Your Graine API key. Create one in the dashboard under Developers, or via POST /v2/api-keys. Send it as Authorization: Bearer <key>.

In: header

Path Parameters

campaign_id
Required
Campaign Id

Campaign identifier.

Query Parameters

organization_idOrganization Id

Must match the organisation the API key belongs to.

Response Body

200

The campaign at status 'active'.

batch_idBatch Id | null

The batch created from contacts on this request, if any were supplied. Null on every other read — a campaign can hold many batches; list them with GET /v2/campaigns/{campaign_id}/batches.

total_contactsTotal Contacts

Contacts across every batch.

Default: 0

skipped_countSkipped Count | null

Contacts of that list that were left out — each names an agent_language the agent doesn't have. Null when every contact was added, and on every other read.

skipped_rowsSkipped Rows | null

The contacts left out, each with its CSV line (the header is line 1) or its position in contacts, and why: the first 100. Null when every contact was added, and on every other read.

@minItems 0

@minItems 0

@minItems 0

campaign_id
Required
Campaign Id

Campaign identifier.

organization_idOrganization Id | null

The organisation this campaign belongs to. Always your own.

name
Required
Name | null

Human label for the campaign.

agent_id
Required
Agent Id | null

Agent that places every call.

phone_numbersPhone Numbers

Caller IDs this campaign dials from.

@minItems 0

@minItems 0

@minItems 0

phone_number_strategyPhone Number Strategy

round_robin | random | least_loaded.

Default: "round_robin"

phone_number_indexPhone Number Index

Round-robin cursor: the position the next call starts from.

Default: 0

timezoneTimezone

IANA timezone the working hours and the window are evaluated in.

Default: "UTC"

working_hours_enforcedWorking Hours Enforced

False dials around the clock, subject only to start_time/end_time.

Default: false

working_hoursWorking Hours

Per-day dialling windows, keyed by lowercase day name.

max_concurrent_callsMax Concurrent Calls | null

Ceiling on this campaign's SIMULTANEOUS calls. Omit for no campaign ceiling. It can only LOWER what the organisation's limit and the fair share across active campaigns already allow — raising it past the org limit has no effect.

retry_policy
Required
Retry Policy

What happens after a busy or a no-answer.

follow_up_policy
Required
Follow Up Policy

Callbacks after the first cycle ends.

transliteration
Required
Transliteration

Name-script rewriting inherited by every batch.

start_timeStart Time | null

ISO-8601 UTC. Nothing dials before this.

end_timeEnd Time | null

ISO-8601 UTC. Nothing dials after this; the campaign then expires.

default_call_variablesDefault Call Variables

Prompt variables applied to every call, overridable per contact.

default_call_contextDefault Call Context

Free-form context applied to every call.

status
Required
Status

created | active | paused | completed | cancelled | expired | archived. A campaign is born 'created' and becomes 'active' when its first batch dials. 'archived' is what DELETE leaves behind; 'cancelled' is what the cancel action does.

metadataMetadata

Whatever you stored on the campaign.

total_batchesTotal Batches

Batches created under this campaign.

Default: 0

active_batchesActive Batches

Batches not yet finished.

Default: 0

completed_contactsCompleted Contacts

Contacts that reached a completed call, counted ONCE regardless of how many attempts it took. Use this for progress, not completed_calls.

Default: 0

completed_callsCompleted Calls

Calls that completed, retries included.

Default: 0

failed_callsFailed Calls

Calls that failed.

Default: 0

busy_callsBusy Calls

Calls that hit a busy line.

Default: 0

no_answer_callsNo Answer Calls

Calls that rang out.

Default: 0

voicemail_callsVoicemail Calls

Calls answered by a voicemail box. A SUBSET of no_answer_calls, never a peer of it — do not add it to the others to form a total.

Default: 0

in_progress_callsIn Progress Calls

Calls live right now.

Default: 0

follow_up_callsFollow Up Calls

Follow-up calls placed.

Default: 0

follow_up_exhaustedFollow Up Exhausted

Contacts whose follow-up attempts ran out.

Default: 0

created_atCreated At | null

ISO-8601 UTC.

updated_atUpdated At | null

ISO-8601 UTC.

started_byStarted By | null

Who started its latest run: {type: member | api_key | system, id, at}. A person is their member id. Null on a campaign that has not started.

approved_byApproved By | null

The workspace Admin who approved that start, when the workspace requires approval: {type: member, id, at, request_id}. Null when it started without needing one.

400

1000 — malformed or contradictory input: an unknown status filter or timezone, a start_time or end_time without a timezone offset, an end_time at or before start_time or more than 365 days ahead, or an empty patch body. 1002 — a required parameter is missing.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

401

1100 — missing, unknown or inactive API key. 1101 — a browser session token was presented.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

402

1400 — the organisation's credit balance cannot fund a call, so nothing was started. Top up and retry.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

403

1102 — the key is valid but lacks the scope this endpoint requires, or names another organisation. GET /v2/scopes reports which scopes the key holds.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

404

1200 — no such campaign, or no such agent, in this organisation. A campaign belonging to another organisation answers 404, never 403, so ids cannot be probed.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

409

1201 — the campaign's state does not allow this action: pausing, resuming or cancelling a campaign that has already been cancelled, completed, expired or archived; editing a cancelled or archived campaign; or deleting one that still has batches running. 1202 — the agent is switched off, so it takes no new calls: switch it on and try again. 1203 — the agent was deleted, so it takes no new calls.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

422

1001 — the body or query failed validation — an unknown field, a value out of range, or a working-hours time that is not 24-hour HH:MM. The message names the first offending field.

error
Required
integer

Stable integer code from the error table. Branch on this, not on the message.

message
Required
string

One human-readable sentence. Wording may change; the code will not.

429

1300 — per-organisation rate limit exceeded. Carries Retry-After.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

503

1501 — a service this endpoint depends on is unreachable or returned a 5xx.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

504

1502 — a service this endpoint depends on did not respond in time.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

curl -X POST "https://api.graine.ai/v2/campaigns/31ff3ea9-8bb5-433f-868f-286ac3c31328/resume?organization_id=string" \
  -H "Authorization: Bearer <token>"

The campaign at status 'active'.

{
  "batch_id": "fa08ae9d-239f-4a99-8d76-d4dec51311b4",
  "total_contacts": 3000,
  "skipped_count": 2,
  "skipped_rows": [
    {
      "row": 7,
      "reason": "agent_language \"fr\" is not one of this agent's languages: en, hi, ta."
    }
  ],
  "campaign_id": "31ff3ea9-8bb5-433f-868f-286ac3c31328",
  "organization_id": "string",
  "name": "Slot-2-Uttar-Pradesh",
  "agent_id": "6c6f4cc3-f56c-479d-8422-7f76694daa29",
  "phone_numbers": [
    "+917971442184"
  ],
  "phone_number_strategy": "round_robin",
  "phone_number_index": 0,
  "timezone": "Asia/Kolkata",
  "working_hours_enforced": true,
  "working_hours": {
    "monday": {
      "start": "08:00",
      "end": "20:00",
      "enabled": true
    },
    "saturday": {
      "start": "10:00",
      "end": "16:00",
      "enabled": true
    },
    "sunday": {
      "start": "10:00",
      "end": "16:00",
      "enabled": false
    }
  },
  "max_concurrent_calls": 10,
  "retry_policy": {
    "max_retries": 5,
    "strategy": "fixed_delay",
    "cooldown_minutes": 45,
    "base_delay_minutes": 15,
    "max_delay_minutes": 240,
    "respect_working_hours": true
  },
  "follow_up_policy": {
    "enabled": false,
    "max_attempts": 2,
    "cooldown_minutes": 1440,
    "triggers": [
      "after_retries_exhausted"
    ],
    "next_working_day_only": true,
    "follow_up_agent_id": "6c6f4cc3-f56c-479d-8422-7f76694daa29",
    "follow_up_prompt": "You spoke to this person yesterday. Open by referring to that call.",
    "follow_up_extra_logic": {}
  },
  "transliteration": {
    "enabled": true,
    "fields": [
      "callee_name"
    ],
    "target_language_code": "hi-IN",
    "source_language_code": "en-IN",
    "keep_original": true
  },
  "start_time": "2026-08-27T05:30:00.000Z",
  "end_time": "2026-08-31T11:00:00.000Z",
  "default_call_variables": {
    "campaign_offer": "monsoon-renewal"
  },
  "default_call_context": {},
  "status": "paused",
  "metadata": {
    "region": "uttar-pradesh",
    "slot": "2"
  },
  "total_batches": 1,
  "active_batches": 1,
  "completed_contacts": 412,
  "completed_calls": 451,
  "failed_calls": 88,
  "busy_calls": 37,
  "no_answer_calls": 120,
  "voicemail_calls": 14,
  "in_progress_calls": 3,
  "follow_up_calls": 0,
  "follow_up_exhausted": 0,
  "created_at": "2026-08-26T10:48:18.239Z",
  "updated_at": "2026-08-26T10:51:46.003Z",
  "started_by": {
    "type": "member",
    "id": "member-live-0f1e2d3c",
    "at": "2026-08-26T10:51:46.003Z"
  },
  "approved_by": {
    "type": "member",
    "id": "member-live-9a8b7c6d",
    "at": "2026-08-26T10:52:10.411Z",
    "request_id": "apr_3f9c1d2e4b5a6978c0d1"
  }
}