Send Test Email
Sends a one-off preview of a campaign message to specific contacts, rendered with their data so personalisation can be checked before the real send. Note the unusual shape: the campaign, message, and project are passed in the request body rather than looked up by ID, so this can preview unsaved edits. Test sends do not touch campaign status or stats, but they do consume balance and respect sender blocking.
Authorization
Authorization In: header
Path Parameters
ID of the project sending the test.
Request Body
application/json
The campaign to preview. Passed in full rather than by ID so unsaved changes can be tested.
Attribute filters combined with groupType.
Contact attribute distinct id to filter on.
Attribute type. Defaults to string when omitted.
Comparison operator for the attribute value.
Value to compare the attribute against.
Event filters evaluated over the last 24 hours only.
Analytics event name.
Whether the contact performed the event in the last 24 hours.
How filters in this group are combined.
When true, the group is ANDed with $subscribed == true. Set by email sending, not the filter UI.
Contacts to send the preview to. Their properties drive personalisation, so use real contacts to see realistic output.
The specific message (subject, body, sender) to render. Pick one variant for an A/B campaign.
The sending project, supplying branding and sender identity for the render.
Response Body
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://www.saasco.com/api/v2/projects/string/emails/send-test" \ -H "Content-Type: application/json" \ -d '{ "campaign": { "id": "string", "createdAt": "string", "updatedAt": "string", "projectId": "string", "name": "string", "status": "DRAFT" }, "contacts": [ { "id": "string", "createdAt": "string", "updatedAt": "string", "projectId": "string", "distinctId": "string", "toDelete": true, "properties": { "property1": "string", "property2": "string" } } ], "message": { "id": "string", "createdAt": "string", "updatedAt": "string", "projectId": "string", "emailCampaignId": "string", "label": "string", "fromName": "string", "fromEmailUsername": "string", "fromDomain": "string", "text": "string", "subjectHTML": "string", "previewTextHTML": "string", "bodyHTML": "string", "bodyJSON": { "property1": null, "property2": null }, "previewTextJSON": { "property1": null, "property2": null }, "subjectJSON": { "property1": null, "property2": null } }, "project": { "id": "string", "createdAt": "string", "updatedAt": "string", "name": "string", "slug": "string", "balance": 0, "balanceVersion": -9007199254740991, "autoTopUpEnabled": true } }'{
"message": "string",
"success": true
}{
"code": "BAD_REQUEST",
"message": "Invalid input data",
"issues": []
}{
"code": "UNAUTHORIZED",
"message": "Authorization not provided",
"issues": []
}{
"code": "FORBIDDEN",
"message": "Insufficient access",
"issues": []
}{
"code": "INTERNAL_SERVER_ERROR",
"message": "Internal server error",
"issues": []
}Stop Sending Email Campaign
Pauses a campaign that is currently sending. Any in-flight batch is cancelled and the campaign moves to PAUSED, keeping its pagination cursor so Resume Sending Email Campaign can pick up where it stopped. Emails already handed to the provider still go out.
Count Campaign Emails
How many emails the campaign covers. The meaning shifts with campaign state: while it is still SENDING this is a live count of contacts currently matching the audience, so it can move between calls as contacts subscribe or unsubscribe. In every other state it counts the Email rows actually created. Treat it as a projection before the send finishes and a fact afterwards.