Schedule a campaign

POST /api/v1/campaigns/{campaignId}/schedule Books the send of a draft campaign for a future instant, and answers 202. Called on a campaign that is already scheduled, it moves it to the new instant. Nothing is sent by this call — the campaign leaves on its own at the time you booked.

Authorization

Role in the organizationThis endpoint
OWNERAllowed
ADMINAllowed
MEMBERRefused — 403
A key carries the role its creator holds in this organization — never a role on AgentsMail itself. See API keys.

Path parameters

ParameterTypeDescription
campaignIdstringUnique identifier of a campaign

Request body

FieldTypeRequiredDescription
scheduledAtstringyesISO 8601 instant with an explicit offset, at least one minute in the future
json
{"scheduledAt": "2026-08-12T07:00:00Z"}

Example

bash
curl -X POST -H "x-api-key: $AGENTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"scheduledAt": "2026-08-12T07:00:00Z"}' \
  "https://www.agentsmail.io/api/v1/campaigns/$CAMPAIGN_ID/schedule"

Response

  • 202 Accepted — the campaign is scheduled for the instant returned in scheduledAt.
  • 400 Bad Request — scheduledAt is missing, has no offset, is in the past or less than a minute away (details carries the issue); or the content has no unsubscribe link.
  • 401 Unauthorized — missing or invalid key, or its owner left the organization.
  • 403 Forbidden — the key's owner is a member of the organization, not an admin.
  • 404 Not Found — no such campaign, or it belongs to another organization. The API never confirms that an id exists to a caller who has no right to it.
  • 409 Conflict — the sending domain is not verified yet, the balance cannot cover the campaign's recipients, its list was removed, or the campaign is paused, sending, sent or failed. Nothing is booked.
  • 429 Too Many Requests — over 120 requests in a minute for this key.

Response fields

FieldTypeDescription
successbooleanIndicates if the operation was successful
data.campaignIdstringThe campaign that was scheduled
data.statusstringAlways scheduled
data.scheduledAtstringThe instant actually stored, in UTC, rounded to the minute

Example response

json
{
  "success": true,
  "data": {
    "campaignId": "6c6c6c6c-5555-4aaa-8bbb-999900001111",
    "status": "scheduled",
    "scheduledAt": "2026-08-12T07:00:00.000Z"
  }
}

Notes

A date with no timezone is refused, never read as UTC. 2026-08-12T09:00:00 answers 400: the API does not guess an offset you did not write. Write 2026-08-12T07:00:00Z, or 2026-08-12T09:00:00+02:00 — both name the same instant.
  • The schedule is kept to the minute: the seconds you pass are dropped. Read scheduledAt in the response to know the exact departure.
  • Calling it again on a scheduled campaign moves the departure; the previous time no longer applies. There is never more than one departure per campaign.
  • A paused campaign answers 409: resume it in the app, or put it back to draft with Unschedule a campaign and schedule it again.
  • To send now instead, use Send a campaign.
Never schedule without explicit human approval for that specific campaign. A scheduled campaign leaves on its own; approval for one send never covers the next one.