Test a campaign

POST /api/v1/campaigns/{campaignId}/test-send Sends one email — the campaign exactly as it is written — to an address you choose, so a human can check inbox placement and rendering before the real send. It is the API side of the "Send a test" button.
json
{"success": true, "data": {"campaignId": "…", "email": "you@example.com", "status": "test_sent"}}
A test spends a real send. It goes out through the same path as a campaign — same sending identity, same configuration set, same subject and HTML, no [TEST] prefix — and counts against the 24 h sending quota. Unlike POST /api/v1/render, this endpoint is not free to call in a loop.
What a test writes: nothing. No send row is created, so the campaign's counters, its status and its statistics are untouched. Two consequences follow from that, and they are the reason the endpoint is honest about its limits:
In a real sendIn a test
Open tracking pixelAbsent — the pixel is addressed by a send row
Links rewritten for clicksNot rewritten — click tracking is addressed by a send row
Merge tags per recipientPreview sample data, the same the preview panel shows
Unsubscribe linkA preview link that unsubscribes nobody
That last row matters: the unsubscribe page unsubscribes on load. A test carrying a real contact's token would unsubscribe that contact on the first click — including a spam filter's pre-click. So a test always carries the inert preview link, in the body and in the List-Unsubscribe header.
ConditionAnswer
draft or scheduled, everything allowed200 — the test was sent
missing or malformed email400 — nothing was sent
no unsubscribe link in the content400 — same check as /render, nothing sent
mass sending switched off account-wide409 — nothing was sent
organization not allowed to send409 — nothing was sent
address on the organization's suppression list409 — nothing was sent
campaign sending, sent or failed409 — a test is for a campaign in preparation
more than 10 tests in the last hour, same user409 — the cap is shared with the UI
unknown campaign, or another organization404
The cap is carried by the user behind the key, not by the endpoint. Ten tests per hour, shared with the "Send a test" button in the app — calling the API is not a way around the interface's budget.

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.

Example

bash
curl -X POST -H "x-api-key: $AGENTMAIL_API_KEY" -H "content-type: application/json" \
  "https://www.agentsmail.io/api/v1/campaigns/$CAMPAIGN_ID/test-send" \
  -d '{ "email": "you@example.com" }'

Response

  • 200 OK — the call succeeded.
  • 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 resource, or it belongs to another organization. The API never confirms that an id exists to a caller who has no right to it.
  • 429 Too Many Requests — over 120 requests in a minute for this key.

Response fields

FieldTypeDescription
successbooleanIndicates if the operation was successful
data.statusstringsent, or the reason it did not go out

Example response

json
{
  "success": true,
  "data": {
    "status": "subscribed"
  }
}