Skip to main content
POST
AhaSend Go SDK
The AhaSend API creates a draft marketing campaign. Access requires campaigns:write. Only name is required. You can set all other fields in this request, or later with Update Campaign. The response gives ready and issues: while the campaign has issues, it cannot be sent. See Issues. Design: The design comes from one source:
  • content.mjml creates an advanced design, and content.html creates an html design. content.markup creates a simple design from AhaML: a content.html beside it is ignored, and a content.mjml beside it is refused. With content that has none of them, set editor. An editor that does not agree with the content is refused.
  • editor without content creates an empty design, which you can complete in the dashboard’s editor.
  • template_id copies the design of a campaign template. The copy belongs to the campaign: later changes to the campaign template do not change it. A campaign template with no HTML is refused. A template_id that names no campaign template of your account is refused with 400 campaign template not found. template_id cannot go with editor or content.
  • Without any of them, the campaign has no design yet.
Content rules:
  • MJML must pass strict validation. For a validation error, the message gives the line of each problem.
  • AhaML must follow the AhaML rules. A refused write lists the problems in errors, each with its line and column when it has a place in the AhaML. See AhaML errors.
  • In MJML and HTML, images and stylesheets must use full https:// URLs, such as https://example.com/logo.png. The API refuses relative paths, such as images/logo.png, and http:, //, data:, cid: and other schemes. A URL that starts with a template variable, such as {{ logo_url }}, is allowed. AhaML URLs follow the AhaML URL rules. The API cannot upload files.
  • The MJML, the HTML, the AhaML and a text written by hand can each be at most 200 KB.
  • The HTML must have an unsubscribe link before you can send the campaign. In AhaML, write it as <Link href="{{ unsubscribe_url }}">…</Link>. See Unsubscribe link.
Sender, subject and audience:
  • from.email must be on a domain of your account with valid DNS records. A paused domain is accepted here, but Send Campaign and Test Campaign refuse it.
  • reply_to is an address only, without a display name.
  • In subject and preheader, line breaks become spaces, and spaces at the start and end are removed. An empty subject or preview text counts as none.
  • The API checks the subject, the preview text, the sender and the reply-to by the same rules as the dashboard, and its error messages use the same words.
  • list_ids and segment_ids hold the lists and segments of your account to send to. exclude_list_ids and exclude_segment_ids hold the lists and segments whose contacts get no message. A list or segment that you give twice counts once. See Audience for the rules.
  • An audience field that you send must leave the campaign at least one list or segment to send to, so list_ids can be [] with a segment in segment_ids. A list or segment that does not exist, more than 50 lists or 10 segments, or a list or segment that is both included and excluded is refused with 400.
  • To find the ID of a list or a segment, use List Lists or List Segments, or see where to find the ID in the dashboard.
  • When a segment of the audience is being built again, the API answers 409 with The campaign's audience is being updated. Try again in a minute. This refusal is stored for the Idempotency-Key, so retry with a new key.
This operation accepts an Idempotency-Key header. See Idempotency.

Authorizations

Authorization
string
header
required

API key for authentication. Non-empty Security Requirement values are AhaSend API-key roles. Roles listed within one requirement object are jointly required; separate requirement objects are alternatives.

Headers

Idempotency-Key
string

Optional idempotency key for safe request retries. Must be a unique string for each logical request. An identical request with a completed stored outcome returns the original status and body. An in-progress execution returns 409, a changed method/path/body returns 422, and a released 5xx execution may run again. Keys for non-secret responses expire after 24 hours. API-key create responses include a one-time secret_key, so successful encrypted replay responses for those operations expire after 5 minutes.

Maximum string length: 255

Path Parameters

account_id
string<uuid>
required

Account ID

Body

application/json

A new draft campaign. Every field but name can be set later with Update Campaign. The design comes from at most one source: an editor, content, both, or a template_id. With none of them the campaign has no design yet.

name
string
required

Campaign name. Spaces around it are dropped.

Required string length: 1 - 255
subject
string | null

The subject line. Line breaks become spaces and spaces around it are dropped; an empty subject is no subject.

preheader
string | null

The preview text, cleaned as subject is.

from
object | null

The sender. email must be on a domain of this account with valid DNS. A paused domain is accepted here and refused when the campaign is sent.

reply_to
string<email> | null

The reply-to address, an address only, without a display name.

list_ids
string<uuid>[]

The lists to send to, in order. A list named twice counts once. Each must be a list of this account. A campaign uses at most 50 lists and 10 segments, included and excluded together, and an audience field that is set must leave it at least one list or segment to send to, so [] is accepted with segment_ids.

Maximum array length: 50
segment_ids
string<uuid>[]

The segments to send to. A segment named twice counts once. Each must be a segment of this account. A contact reached through a list and a segment gets one message, recorded under the list. Responses return the segments by ID.

Maximum array length: 10
exclude_list_ids
string<uuid>[]

Lists whose contacts get no message from the campaign. A contact with any membership of one, whatever its status, is left out, also when an included list or segment reaches it. A list cannot be both in list_ids and here. Exclusions need at least one list or segment to send to. Responses return the lists by ID.

Maximum array length: 50
exclude_segment_ids
string<uuid>[]

Segments whose members get no message from the campaign, also when an included list or segment reaches them. A segment cannot be both in segment_ids and here. Exclusions need at least one list or segment to send to. Responses return the segments by ID.

Maximum array length: 10
editor
enum<string>

The editor of the design. Without content the campaign gets an empty design of this editor, which the dashboard's editor opens. With content, it is required when the content holds none of markup, mjml and html, and must agree with it otherwise; markup means simple, also beside html. Not accepted with template_id, whose editor the design keeps.

Available options:
advanced,
simple,
html
content
object

The content of the design, by the rules of TemplateContentInput. A campaign has no draft, so where those rules name the draft, they mean the campaign's design. Not accepted with template_id.

template_id
string<uuid>

A campaign template whose design the campaign copies. The copy is the campaign's own; later changes to the template do not reach it. A campaign template with no HTML is refused.

Response

Campaign created

A campaign as List Campaigns returns it, without its audience, content and issues.

object
enum<string>
required

Object type identifier

Available options:
campaign
id
string<uuid>
required

Campaign ID

created_at
string<date-time>
required

When the campaign was created

updated_at
string<date-time>
required

When the campaign's own fields last changed

name
string
required

Campaign name, as it appears in the dashboard. Recipients do not see it.

subject
string | null
required

The subject line. Null until one is set.

preheader
string | null
required

The preview text, which most inboxes show after the subject. Null until one is set.

from
object | null
required

The sender. Null until a complete sender is set, and when its domain was deleted. name is an empty string when the campaign has no sender name, so the object can be sent back as it is.

Example:
reply_to
string<email> | null
required

The reply-to address. Null when none is set.

status
enum<string>
required

Where the campaign is in its life. Only a draft can be changed or deleted.

  • draft: being prepared.
  • validating: scheduled, and its lists and segments are being checked.
  • waiting_for_review: held for a review before it sends.
  • scheduled: accepted, waiting for its send time.
  • sending: sending now.
  • paused: sending stopped for now; status_reason says why.
  • sent: every message was sent.
  • canceled: stopped before it finished; status_reason says why.
  • failed: could not be sent; status_reason says why.
Available options:
draft,
validating,
waiting_for_review,
scheduled,
sending,
paused,
sent,
canceled,
failed
status_reason
string | null
required

Why the campaign is in its status, when there is a reason to give. Null otherwise.

send_at
string<date-time> | null
required

When the campaign sends or sent, in UTC. Null until it is scheduled.

send_resumes_at
string<date-time> | null
required

When a send that reached the account's daily marketing limit continues, in UTC. Null otherwise.

finished_at
string<date-time> | null
required

When the send ended, in UTC. Null until then.

list_ids
string<uuid>[]
required

The lists the campaign sends to, in the order they were saved. A list that was deleted is left out.

segment_ids
string<uuid>[]
required

The segments the campaign sends to, by ID. A segment that was deleted is left out.

exclude_list_ids
string<uuid>[]
required

The lists whose contacts the campaign does not send to, by ID. A contact with any membership of one of them, whatever its status, is left out. A list that was deleted is left out.

exclude_segment_ids
string<uuid>[]
required

The segments whose members the campaign does not send to, by ID. A segment that was deleted is left out.

editor
enum<string> | null
required

The editor of the campaign's design. Null while the campaign has no design.

Available options:
advanced,
simple,
html
content
object | null
required

The content of the campaign's design. Null while it has no design, or its design has neither HTML nor text.

ready
boolean | null
required

Whether the draft has no issue, so it can be sent. Null unless the campaign is a draft.

issues
object[] | null
required

The reasons the draft cannot be sent yet, in a fixed order; empty when it is ready. Null unless the campaign is a draft.

markup_warnings
object[]

Warnings about the AhaML in content.markup, up to the first 100; empty when there are none. Present only in the answer to a write that carried content.markup.

Maximum array length: 100