Skip to main content
The AhaSend Campaigns API creates marketing campaigns, sends them to your lists and segments and reports the results. This page gives the steps from a new campaign to its report, and the rules that apply to all campaign operations.

Campaign Templates and Campaigns

A campaign template is a reusable design. In the dashboard, campaign templates are under Marketing > Templates. When you create a campaign with a template_id, the campaign copies the design of that campaign template. The copy belongs to the campaign: later changes to the campaign template do not change the campaign, and you can delete the campaign template without an effect on the campaign. Campaign templates and transactional templates are different resources. The campaign template operations do not return transactional templates, and the transactional template operations do not return campaign templates.

Prerequisites

Before you create a campaign, make sure you have:
  • An API key with the campaigns scopes that you need, and the templates scopes to manage campaign templates. Copying a campaign template with template_id on Create Campaign needs only campaigns:write. See Scopes.
  • A verified sender domain that is not paused. See domain setup.
  • A list or a segment with contacts who can get marketing email. Create lists and add contacts with the Lists API, create segments with the Segments API, or do both in the dashboard. See Build and Send a Campaign for where to find the ID of a list or a segment.

Build and Send a Campaign

1

Make the design

Create a reusable design with Create Campaign Template, or give the design to the campaign itself in the next step. A design is MJML, HTML, AhaML for a Simple Editor design, or an empty design that you complete in the dashboard’s editor.
2

Create the campaign

Call Create Campaign with a name. All other fields are optional. You can set them in the same request, or later with Update Campaign.
3

Set the sender, audience, subject, preview text and content

  • from is the sender. Its address must be on a domain of your account with valid DNS records.
  • list_ids and segment_ids hold the IDs of the lists and segments to send to. exclude_list_ids and exclude_segment_ids hold the IDs of the lists and segments whose contacts get no message. See Audience. To find the ID of a list or a segment, use List Lists or List Segments, or open it under Marketing > Lists or Marketing > Segments in the dashboard: the ID is the last part of the page’s URL. Before you send, the audience must have contacts who can get the campaign.
  • subject is the subject line, and preheader is the preview text that most inboxes show after the subject.
  • content is the design. On create only, template_id can copy the design of a campaign template instead. Update Campaign does not accept template_id.
4

Fix the issues

Get Campaign returns ready and issues. While ready is false, each issue gives a code and a message that tells you what to fix. See Issues.
5

Send a test

Test Campaign sends the campaign to up to 5 addresses, so you can check it in a real inbox. See Test Sends.
6

Send now or later

Send Campaign sends the campaign now, or at the time in send_at. To return a validating or scheduled campaign to draft, use Unschedule Campaign. A campaign in any other status, waiting_for_review included, cannot be unscheduled.
7

Read the results

Get Campaign Stats returns the counters and rates of the campaign. List Campaign Recipients returns the recipients in one status or with one bounce classification.

Audience

A campaign sends to the lists in list_ids and the segments in segment_ids, less the contacts of the lists in exclude_list_ids and the members of the segments in exclude_segment_ids.
  • The audience needs at least one list or segment to send to. So list_ids can be [] when segment_ids has a segment, and exclusions alone are refused with 400.
  • A campaign uses at most 50 lists and 10 segments, included and excluded together.
  • A list or a segment cannot be both included and excluded.
  • An exclusion wins. A contact with any membership of an excluded list, whatever its status, gets no message, and neither does a member of an excluded segment, also when an included list or segment reaches the contact.
  • A contact reached through several lists and segments gets one message. It is recorded under a list when a list reaches the contact, so an unsubscribe stays per list when it can.
  • An included list reaches its confirmed members. An included segment reaches its members who can get marketing email. See Members and reachable contacts.
  • A contact who unsubscribes from an email that a campaign sent through a list leaves that list. A contact who unsubscribes from an email sent through a segment, or reports it as spam, is unsubscribed account-wide and gets no more marketing email from your account.
  • A campaign that uses a segment that is building or failed, included or excluded, cannot be sent. See States.
  • A list or a segment that was deleted is left out of the campaign’s audience fields.
In List Campaign Recipients, a recipient reached through a list has list_name, and one reached through a segment has segment_id and segment_name instead.

Campaign Status

When a send reaches the daily marketing limit of your account, it continues later. send_resumes_at gives the time when it continues. In the dashboard, the page of a scheduled, sending or sent campaign shows your daily marketing limit.

Changes Only to Drafts

You can change, delete, test and send a campaign only while its status is draft. For a campaign in any other status, these operations answer 409 with campaign is not a draft. To change a campaign that is validating or scheduled, unschedule it first. The campaign goes back to draft. Change it, then send it again. A campaign that has queued mail, or that is in another status, cannot go back to draft. To send the same campaign again, use Duplicate Campaign, which makes a new draft from a campaign in any status. The API and the dashboard change the same campaign.

Issues

A draft campaign is ready when it has no issues. Send Campaign refuses a campaign with issues with 400, and the response holds the issues. Every campaign must have an unsubscribe link. The HTML of the design must use {{ unsubscribe_url }} or {{ unsubscribe_link }}, with or without filters. Without one of them, the campaign has the issue unsubscribe_link_missing, and Send Campaign refuses it. A test send does not need the unsubscribe link, so you can test a design before you add it.

Test Sends

A test send goes to 1 to 5 addresses, and your account can send 50 test emails per day (UTC). Test Campaign gives the rules of the daily limit.

Idempotency

These operations accept an Idempotency-Key header:
  • Create Campaign Template and Update Campaign Template.
  • Create Campaign, Update Campaign and Duplicate Campaign.
  • Send Campaign, Unschedule Campaign and Test Campaign.
The API stores the answer that the operation itself gives to a key, including a refusal (4xx), and replays it for every retry with the same key. So a refusal from the operation stays a refusal for that key. After you fix the cause, for example after you add the missing subject or after the status of the campaign changes, send the request again with a new Idempotency-Key. Test Campaign is the one exception: it does not store a 4xx answer. The API does not store a 5xx, or a 401, 403 or rate-limit 429, which come before the operation runs. You can retry these with the same key. Stored answers expire after 24 hours. See Idempotency. A campaign 409 has one of three forms: Only Update Campaign, Send Campaign, Unschedule Campaign and Test Campaign have a status conflict among the operations with a key. Test Campaign does not store its status conflict, so it never answers in the third form. The other campaign and campaign template operations with a key answer 409 only in the first form. Do not use the message to tell the forms apart. See Idempotency.

Scopes

The templates scopes give access to transactional templates and campaign templates together. To choose lists and segments by ID, a campaign write needs only campaigns:write. To find the IDs, you need lists:read or segments:read. See Permission scopes.

API Operations