Skip to main content
POST
AhaSend Go SDK
The AhaSend API creates a transactional template. Access requires templates:write. The subject, preview text, sender, reply-to and content go to the template’s draft. Sends cannot use the template until you publish it: pass publish: true, or call Publish Template. A create with publish: true and no content to publish is refused with 400 and creates nothing. Editor:
  • content.mjml creates an advanced template, and content.html creates an html template.
  • content.markup creates a simple template from AhaML. A content.html beside it is ignored, and a content.mjml beside it is refused.
  • Without content.mjml, content.html or content.markup, set editor. An editor that does not agree with the content is refused.
  • You cannot change the editor after you create the template.
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.
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 transactional template. Its fields go to its draft, as a dashboard save does; publish: true publishes the draft in the same request, so sends use it.

name
string
required

Template name. Spaces around it are dropped.

Required string length: 1 - 255
editor
enum<string>

Required when content holds none of markup, mjml and html. content.markup means simple, also beside content.html; content.mjml means advanced and content.html alone means html. An editor that disagrees with the content is refused.

Available options:
advanced,
simple,
html
subject
string | null

The subject. Line breaks become spaces and spaces around it are dropped.

Maximum string length: 998
preheader
string | null

The preview text. Line breaks become spaces and spaces around it are dropped.

Maximum string length: 500
from
object | null

The default sender. email must be on a domain of this account with valid DNS records that is not paused.

reply_to
object | null

The default reply-to address. It needs a from, and its name must be empty.

content
object

The content of a template write. It holds at most one of mjml and html, never both markup and mjml, and at least one of markup, mjml, html and text. The content that Get Template answers, the working copy, can be sent back as it is: an mjml or html equal to the current one is held to the size limit but not compiled again or held to the HTML checks, and keeps the stored HTML. While a draft exists, a design equal to the published copy's, which Get Published Template answers, takes the published copy's stored design in the same way, and a draft that then equals the published copy is dropped. Leave content out of a write that does not change it: for a simple template, a write that sends markup back is held to the AhaML rules and limits too. A write has no check of what the caller read: a content read before a dashboard save and sent back after it replaces the design that save stored.

A simple design is written as AhaSend Markup (AhaML) in markup. Its html is made from the design: beside markup it is ignored without any check, and without markup it is ignored when it equals the working copy's stored HTML, and refused otherwise, an empty html included. The content read from a simple design can so be sent back as it is, markup_error included: AhaML that prints the same as the stored design keeps that design and its HTML, and AhaML that prints the same as the published copy takes the published copy's design and HTML. A design that breaks a rule of AhaML, also one saved in the dashboard, is refused when it is written back, such as an image that is not an https:// URL.

The text follows these rules:

  • Beside a new markup, mjml or html, a missing text keeps the draft's text when it is custom, and that text must still render, as a sent text must; otherwise, and on a create, it makes the text from the new HTML. A null text makes the text from the new HTML, and so does a text equal to a text made from an earlier HTML: the draft's made text, or the published copy's made text when the draft does not hold that text as custom. A read content can so be sent back with a changed design. Any other text is stored as made when it equals the text made from the new HTML, and as custom otherwise. To keep a made text beside a new design, send the design first and the text in a second request.
  • Otherwise a text equal to the draft's custom text keeps it; one equal to the text made from the draft's HTML is stored as made; any other is stored as custom. A null text makes the text again from the draft's HTML, and is refused when there is no HTML.

Line ends written as CRLF are stored as LF, and a blank text is refused. markup, mjml, html and a custom text each have a size limit.

publish
boolean
default:false

Publish the draft once it is written.

Response

Template created. The Template object is the working copy, the draft while the request left one; has_draft says whether it did.

A transactional template, as one of its copies. Get Template and the answer of every template write give its working copy: its draft while it has one, and its published copy otherwise. Get Published Template and List Templates give its published copy, the one a send uses. has_draft says whether a draft exists.

object
enum<string>
required

Object type identifier

Available options:
template
id
string<uuid>
required

Pass as template_id to Create Template Message to send this template

created_at
string<date-time>
required

When the template was created

updated_at
string<date-time>
required

When the template's name or this copy last changed

name
string
required

Template name, as it appears in the dashboard

subject
string
required

This copy's subject, set on the template page. Empty until one is set. A send uses the published subject, unless it names its own subject.

preheader
string
required

This copy's preview text, which a send of the published copy injects into the delivered HTML when it is set

variables
object[]
required

Every variable this copy's design uses. A send of this template uses the published copy's variables, which Get Published Template returns, and takes the values only from each recipient's substitutions. Every recipient must give a value for each required variable; if one does not, the request is rejected and no message is sent. Each variable's kind says what shape of value to send.

from
object | null
required

This copy's default sender. A send that names no from uses the published copy's. Null when the copy has none; a send of a published copy with none must name one.

Example:
reply_to
object | null
required

This copy's default reply-to address. A send that sets no reply-to, also one that names its own from, uses the published copy's. Null when the copy has none. It has the shape of a send request's reply_to; its name is always empty.

Example:
editor
enum<string>
required

The editor the template is designed with. It never changes after the template is created.

  • advanced: designed in MJML, with the dashboard's advanced editor.
  • simple: designed with the dashboard's simple editor. Its HTML is made from the design and can be read but not changed through the API. A read or write answer of one item gives the design as AhaSend Markup (AhaML) in content.markup; a list does not. A write changes the design with content.markup.
  • html: an HTML template, uploaded or written by hand.
Available options:
advanced,
simple,
html
has_draft
boolean
required

Whether the template has a draft, changes saved in the dashboard or through the API that are not published yet. Get Template returns the draft while one exists.

content
object | null

This copy's content. Null when it has no body, as for the published copy of a template that was never published. List Templates leaves this field out; every other operation that returns a Template sets it.

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