Guides
Campaigns
Run campaigns from the systems that already know your customers. A campaign moves through the same steps as in the console: draft, checks, test, approval, schedule, report.
The lifecycle
Create a draft
POST /campaignsName it, give it a subject and a sending domain, and start from a template, your own HTML or a starter design, in your brand look unless you ask for the original.
Check it
POST /campaigns/{id}/validateValidation runs the same checks a send does and says which ones block it. Render it to see the message as a recipient would, as HTML or plain text.
Send a test
POST /campaigns/{id}/testTest copies go only to people on your account, 30 an hour, with "[Test]" before the subject and an unsubscribe link that goes nowhere.
Approve it
POST /campaigns/{id}/approveApproval keeps the campaign exactly as it stands, and every blocking check must pass. Change anything afterwards and it must be approved again.
Schedule it
POST /campaigns/{id}/scheduleSend now or at a time. Scheduling twice never sends twice. A campaign that is sending can be paused and resumed, and one that has not started can be cancelled back to a draft.
Read the report
GET /campaigns/{id}/reportEach measure with its definition and rate, clicks by link, a timeline, the subject test's result, and plain observations comparing it with your usual results.
What applies to every campaign
- A campaign goes to subscribed contacts only: those with any of its
audienceTags, or everyone subscribed if it has none. Pending contacts are never sent marketing. - Without the Campaigns add-on, a campaign must fit in what is left of the free allowance; with it, the list must fit the plan. Either is answered
402 payment_requiredwhen scheduling. - Campaigns and automations share one hourly sending allowance, set by your plan.
Marketing is not transactional
/campaignsCreate a campaign
Creates a draft. Its design starts from a template, from an email's HTML you send, or from a starter design, in your brand look unless you ask for the original. A domainId that is not one of yours is left empty. Set the topic, segment, subject test and brief afterwards with PATCH /campaigns/:id. Needs audience:write.
Body
- namestringrequired
- Your name for the campaign, 1 to 120 characters.
- subjectstringoptional
- Up to 200 characters. From the imported HTML's title if left out.
- preheaderstringoptional
- The preview line, up to 200 characters.
- fromNamestringoptional
- Up to 100 characters.
- fromLocalstringoptional
- The part of the from address before the @; "news" if left out.
- domainIduuid | nulloptional
- The sending domain.
- replyTostring (email) | nulloptional
- Where replies go.
- audienceTagsstring[]optional
- Up to 20 tags; the campaign goes to subscribed contacts with any of them, or everyone if empty.
- templateIdstringoptional
- A built in template ("builtin:...") or one of your own, as the starting design.
- look'brand' | 'original'optional
- Start in your brand look ("brand", the default) or the template's own.
- htmlstringoptional
- An existing email's HTML, up to 900,000 characters, read into the design (see POST /campaigns/import-html).
- bodystringoptional
- Plain body text in the older body language, up to 100,000 characters; leave it out to start from a design.
curl -X POST https://app.rykonmail.com/api/v1/campaigns \
-H "Authorization: Bearer $RYKON_MAIL_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "API docs example",
"subject": "Our autumn collection is here",
"preheader": "Twelve new pieces, made in small batches.",
"fromName": "Northwind Traders",
"fromLocal": "news",
"domainId": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
"replyTo": "hello@northwind-local.test",
"audienceTags": [
"vip"
]
}'{
"id": "9e210b02-8326-4122-a449-2196ccd8cc38",
"name": "API docs example",
"subject": "Our autumn collection is here",
"preheader": "Twelve new pieces, made in small batches.",
"from_name": "Northwind Traders",
"from_local": "news",
"domain_id": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
"domain": "northwind-local.test",
"reply_to": "hello@northwind-local.test",
"body": "",
"audience_tags": [
"vip"
],
"segment": null,
"topic_id": null,
"experiment": null,
"experiment_result": null,
"brief": {},
"updated_by": null,
"state": "draft",
"state_reason": null,
"scheduled_at": null,
"started_at": null,
"finished_at": null,
"created_at": "2026-10-30T06:14:34.949Z",
"updated_at": "2026-10-30T06:14:34.949Z"
}In the reference: Create a campaign
/campaigns/{id}/scheduleSchedule or send a campaign
Sends now, or at a time. Only a draft whose approval still covers it as it stands can be scheduled (409 otherwise). Without the Campaigns add-on a campaign must fit in what is left of the free allowance, and with it the list must fit the plan; either answers 402. Scheduling twice never sends twice. Needs audience:write.
Path parameters
- iduuidrequired
- The campaign's id.
Body
- atstring (date-time) | nulloptional
- When to send; now if null or left out.
curl -X POST https://app.rykonmail.com/api/v1/campaigns/9e210b02-8326-4122-a449-2196ccd8cc38/schedule \
-H "Authorization: Bearer $RYKON_MAIL_KEY" \
-H "Content-Type: application/json" \
-d '{
"at": "2026-10-30T08:15:19Z"
}'{
"id": "9e210b02-8326-4122-a449-2196ccd8cc38",
"name": "API docs example",
"subject": "Our autumn collection is here",
"preheader": "Twelve new pieces, made in small batches.",
"from_name": "Northwind Traders",
"from_local": "news",
"domain_id": "965a5cd1-455b-4c7d-8ae3-f68caf0c7993",
"domain": "northwind-local.test",
"reply_to": "hello@northwind-local.test",
"body": "",
"audience_tags": [
"vip"
],
"segment": null,
"topic_id": "bea753b0-6132-4bc2-bc2a-18ff86ed0079",
"experiment": null,
"experiment_result": null,
"brief": {},
"updated_by": "key sa1pteyz44qbm",
"state": "scheduled",
"state_reason": null,
"scheduled_at": "2026-10-30T08:15:18.947Z",
"started_at": null,
"finished_at": null,
"created_at": "2026-10-30T06:14:34.949Z",
"updated_at": "2026-10-30T06:15:19.947Z"
}In the reference: Schedule or send a campaign
Every campaign endpoint
- GET
/campaignsList campaigns - POST
/campaignsCreate a campaign - POST
/campaigns/import-htmlRead an email's HTML - GET
/campaigns/{id}Get a campaign - PATCH
/campaigns/{id}Update a campaign - DEL
/campaigns/{id}Delete a campaign - GET
/campaigns/{id}/studioGet a campaign's design - PUT
/campaigns/{id}/designSave a campaign's design - POST
/campaigns/{id}/validateCheck a campaign - GET
/campaigns/{id}/renderRender a campaign - POST
/campaigns/{id}/testSend a test - POST
/campaigns/{id}/approveApprove a campaign - POST
/campaigns/{id}/scheduleSchedule or send a campaign - POST
/campaigns/{id}/pausePause a send - POST
/campaigns/{id}/resumeResume a send - POST
/campaigns/{id}/cancelCancel a campaign - POST
/campaigns/{id}/duplicateDuplicate a campaign - GET
/campaigns/{id}/reportGet a campaign's report - GET
/campaigns/{id}/versionsList a campaign's versions
Automations
Journeys that start when someone subscribes, through a form or a tag, and stop the moment they unsubscribe. Each email in a journey reaches a person once.
- GET
/automationsList automations - POST
/automationsCreate an automation - GET
/automations/{id}Get an automation - PUT
/automations/{id}Save an automation - DEL
/automations/{id}Delete an automation - POST
/automations/{id}/activateSwitch an automation on - POST
/automations/{id}/pausePause an automation - GET
/automations/{id}/runsList an automation's people