POST /api/v1/templates/{templateId}/test-send
Sends one email — the template as it stands — to an address you choose, so a human can check
rendering in a real inbox before any campaign is built on it. It is the API side of the "Send a test"
button on the template screen.
json
{"success": true, "data": {"templateId": "…", "email": "you@example.com", "status": "test_sent"}}A test spends a real send. It goes out through the same path as a campaign — same sender
address as the campaign will use, 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.subject and content override what is rendered, never who you are. They exist so the editor
can test the draft it is showing, before saving. The templateId still decides everything that
matters: which organization is allowed to send, which suppression list is checked, and which
identity signs the message. Passing HTML does not turn this into a free-form send endpoint.
What a test writes: nothing. No send row is created, so no statistic moves anywhere. Two
consequences follow, the same ones as for a campaign test:
| In a real send | In a test |
|---|---|
| Open tracking pixel | Absent — the pixel is addressed by a send row |
| Links rewritten for clicks | Not rewritten — click tracking is addressed by a send row |
| Merge tags per recipient | Preview sample data, the same the preview panel shows |
| Unsubscribe link | A preview link that unsubscribes nobody |
| Condition | Answer |
|---|---|
| everything allowed | 200 — the test was sent |
missing or malformed email | 400 — nothing was sent |
| no unsubscribe link in the content | 400 — same check as /render, nothing sent |
| mass sending switched off account-wide | 409 — nothing was sent |
| organization not allowed to send | 409 — nothing was sent |
| address on the organization's suppression list | 409 — nothing was sent |
| over the test cap | 409 — 10 tests per hour and per user |
| unknown, or another organization | 404 |
The test cap is shared with campaign tests. Ten tests per hour and per user, campaigns and
templates combined — spending it on
/campaigns/{campaignId}/test-send blocks this endpoint too,
and the other way round. The cap lives in the service, so the screen and the API draw on the same
budget: neither is a way around the other.Authorization
| Role in the organization | This endpoint |
|---|---|
OWNER | Allowed |
ADMIN | Allowed |
MEMBER | Refused — 403 |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
email | string | yes | Where the test goes |
subject | string | no | Overrides the template's defaultSubject for this test only |
content | string | no | Overrides the template's HTML for this test only |
Example
bash
curl -X POST -H "x-api-key: $AGENTMAIL_API_KEY" -H "content-type: application/json" \
"https://www.agentsmail.io/api/v1/templates/$TEMPLATE_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 amemberof the organization, not anadmin.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
| Field | Type | Description |
|---|---|---|
success | boolean | Indicates if the operation was successful |
data.status | string | sent, or the reason it did not go out |
Example response
json
{
"success": true,
"data": {
"status": "subscribed"
}
}