Send a transactional message
POST/v1/transactional/messages
Requires an API key with the transactional:send scope. About keys and scopes
Works with integration and partner keys, not agent keys.
Send Idempotency-Key. A retry with the same key and body repeats nothing. Most writes replay the first response; a transactional send returns the message as it stands now. About idempotency
Sends a one-off message to one recipient — a receipt, a password reset, a confirmation — bypassing campaigns. It ignores marketing preferences (it is the critical tier) but respects suppression. Agent keys are refused with 403.
Channels. Give email, push, or both. With both, each one the contact can receive is sent. fallbackOrder: ["email", "push"] tries them in that order instead: the first the contact can receive goes, and each later one waits as a fallback (fallbackFor), sent only when the one before it fails, is skipped or bounces (an email gets 15 minutes to bounce), else skipped with reason fallback_not_needed. A fallback is charged only when it goes; with no room left in the plan by then it is skipped with reason plan_limit_reached. A channel the contact cannot receive, or the plan has no room for, is passed over and listed in skippedChannels with its error code; only when none is left does the send fail, with that channel's error. So without fallbackOrder too, a 202 can leave a channel unsent: check skippedChannels. The response lists one message per channel stored, and one per cc or bcc copy. Each copy is its own message with its own bounces, and an address that cannot take one is listed in skippedCopies while the send goes on.
Data. data holds the values the content reads as {{ data.<key> }}, once for every channel: a stored template, inline email, and the push title and body. Inline content (email or push) whose {{ data.<key> }} tag has no value in data, and no default, is refused with 400 rather than sent blank.
Email. Inline (subject, from, html, optional text, previewText, replyTo), or a stored template named by template (its alias, such as password-reset, or its id). The template's published version is rendered when the request is accepted and supplies the envelope; each envelope field given overrides it. The result needs a subject and a from (409 TEMPLATE_ENVELOPE_INCOMPLETE), and the from domain must be verified. A template never published is 409 TEMPLATE_NOT_PUBLISHED. Email is tracked only when tracking asks, and never for a contact in the EEA or the UK; threading continues a conversation. attachments, threading and tracking sit inside email.
Push. push takes the notification fields (title, body, actionUrl, …) beside pushProjectId, which is needed only when the workspace has several push projects. Unlike email, push needs the contact's push consent (consent.push) besides a device that allows notifications.
Recipient. to names one contactId, externalId or email, and nothing else: set a contact's name or attributes with POST /v1/contacts/identify first. An email that matches no contact creates one for transactional mail only.
Retries. Send an Idempotency-Key header to make a retry safe. A retry with the same key and request returns the first result, with Idempotency-Replay: true, and sends nothing again; the same key with a different request is 409 IDEMPOTENCY_KEY_REUSED. Without a key, every request sends: a retry after a timeout can send the message twice. A replay answers from the messages as they are now, so its status can differ from the first answer, and an externalId or email recipient the first request created or updated stays so even when the send itself was refused. Set correlationId to your own reference: it is echoed on each message's webhooks and its read, and GET /v1/messages?correlationId= finds them. sendAt times the send, email and push alike.
Header parameters
Idempotency-KeystringoptionalMakes a retry safe for as long as what the request created exists: a repeat with the same key and body gets the first response again, with
Idempotency-Replay: true. The same key with another request is 409IDEMPOTENCY_KEY_REUSED. Use a new key, such as a UUID, for each new request.8–255 characters
Kirora-WorkspacestringoptionalPartner keys only: the child workspace to act in, by the external id the partner gave it. Without it, a partner key acts in its own workspace. Any other key that sends it is refused with 403, and an unknown workspace is 404.
pattern
^[A-Za-z0-9._:-]{1,128}$
Request body
toobjectrequiredWho receives it.
Any of 3 shapes
- By contact id
1 child attribute
contactIdstringrequiredAn existing contact.
uuid
- By external id
1 child attribute
externalIdstringrequiredYour own id for an existing contact, as set with identify.
1–255 characters
- By email
1 child attribute
emailstringrequiredThe recipient's address. An email send to an address no contact has creates a transactional-only contact; a push-only send needs an existing contact.
email · up to 320 characters
datamap<string, any>optionalValues the content reads as
{{ data.<key> }}: a stored template, inline email and the pushtitleandbodyalike.keys: pattern
^[A-Za-z0-9_-]{1,64}$sensitivebooleanoptionalSet when the message carries a secret (a reset link, a one-time code): its content is kept only while the message is queued or sending, and removed once sending finishes, whatever the workspace's retention says.
correlationIdstringoptionalYour own reference for this send, echoed on its webhooks and its read.
1–255 characters
emailobjectoptionalInline (
subject,from,html), or a stored template bytemplate; either may carryattachments,threading,tracking,ccandbcc.Any of 2 shapes
- Stored template
10 child attributes
templatestringrequiredThe template's alias, such as
password-reset, or its id.subjectstringoptionalThe subject line. Merge tags are allowed.
1–998 characters
previewTextstringoptionalShown by inboxes after the subject. Merge tags are allowed; keep it near 100 characters.
1–255 characters
fromstringoptionalThe sender address, on a verified sending domain.
1–320 characters
replyTostringoptionalWhere replies go; the part before the @ must be ASCII.
email
attachmentsEmailAttachmentInput[]optionalFiles it carries: up to 10, 10 MB in all.
at least 1 item · at most 10 items
3 child attributes
filenamestringrequiredIts extension sets the type it is sent as.
1–255 characters
contentstringrequiredThe file, base64-encoded.
base64
contentIdstringoptionalShows an image inside the body instead of attaching it: the HTML refers to it as
<img src="cid:<contentId>">.pattern
^[A-Za-z0-9._-]{1,100}$
threadingEmailThreadingInputoptionalPlaces it in an existing conversation, as the
In-Reply-ToandReferencesheaders.2 child attributes
inReplyTostringrequiredThe
Message-IDof the email being replied to, angle brackets included.pattern
^<[^<>\s@]+@[^<>\s@]+>$referencesstring[]optionalThe
Message-IDs earlier in the conversation, oldest first (up to 20).at least 1 item · at most 20 items
trackingTransactionalEmailTrackingInputoptionalOpen and click tracking; off unless asked for. Contacts whose
countryis in the EEA or the UK are never tracked.2 child attributes
opensbooleanoptionalTrack opens with a pixel.
default
falseclicksbooleanoptionalRewrite links to track clicks.
default
false
ccstring[]optionalAddresses that get a copy and are shown in its
Ccline. Each goes as its own message, with its own bounces and complaints, and counts as one email. Up to 14 acrossccandbcc.at least 1 item · at most 14 items
bccstring[]optionalAddresses that get a copy without being shown to anyone. Sent and counted as
ccis.at least 1 item · at most 14 items
- Inline content
12 child attributes
subjectstringrequiredThe subject line. Merge tags are allowed.
1–998 characters
previewTextstringoptionalShown by inboxes after the subject. Merge tags are allowed; keep it near 100 characters.
1–255 characters
htmlstringrequiredThe HTML body. Rendered from the design when one is set.
1–512,000 characters
textstringoptionalThe plain-text alternative.
1–512,000 characters
fromstringrequiredThe sender address, on a verified sending domain.
1–320 characters
replyTostringoptionalWhere replies go; the part before the @ must be ASCII.
email
attachmentsEmailAttachmentInput[]optionalFiles it carries: up to 10, 10 MB in all.
at least 1 item · at most 10 items
3 child attributes
filenamestringrequiredIts extension sets the type it is sent as.
1–255 characters
contentstringrequiredThe file, base64-encoded.
base64
contentIdstringoptionalShows an image inside the body instead of attaching it: the HTML refers to it as
<img src="cid:<contentId>">.pattern
^[A-Za-z0-9._-]{1,100}$
threadingEmailThreadingInputoptionalPlaces it in an existing conversation, as the
In-Reply-ToandReferencesheaders.2 child attributes
inReplyTostringrequiredThe
Message-IDof the email being replied to, angle brackets included.pattern
^<[^<>\s@]+@[^<>\s@]+>$referencesstring[]optionalThe
Message-IDs earlier in the conversation, oldest first (up to 20).at least 1 item · at most 20 items
trackingTransactionalEmailTrackingInputoptionalOpen and click tracking; off unless asked for. Contacts whose
countryis in the EEA or the UK are never tracked.2 child attributes
opensbooleanoptionalTrack opens with a pixel.
default
falseclicksbooleanoptionalRewrite links to track clicks.
default
false
ccstring[]optionalAddresses that get a copy and are shown in its
Ccline. Each goes as its own message, with its own bounces and complaints, and counts as one email. Up to 14 acrossccandbcc.at least 1 item · at most 14 items
bccstring[]optionalAddresses that get a copy without being shown to anyone. Sent and counted as
ccis.at least 1 item · at most 14 items
mergeTagsbooleanoptionalSet to
falsefor HTML that is already finished:{{then goes out exactly as written, and nothing is checked or filled in.{{unsubscribe_url}}and{{web_version_url}}still work. Defaults totrue.
pushTransactionalPushInputoptionalA push notification to the contact's devices. Give
push,email, or both.14 child attributes
titlestringrequiredThe notification title (up to 100 characters).
1–100 characters
bodystringrequiredThe notification text (up to 500 characters).
1–500 characters
actionUrlstringoptionalThe HTTPS page opened when the notification is tapped.
uri · up to 2,048 characters
imageUrlstringoptionalA large picture: web and Android show it; iOS needs the app's service extension.
uri · up to 2,048 characters
iconUrlstringoptionalWeb only; iOS and Android show the app's own notification icon.
uri · up to 2,048 characters
datamap<string, string>optionalUp to 10 string key-value pairs passed to the app untouched, for deep links and in-app routing.
at most 10 keys · keys: pattern
^[A-Za-z0-9_.-]{1,64}$· values: up to 1,024 charactersbuttonsobject[]optionalUp to 2 action buttons.
at least 1 item · at most 2 items
2 child attributes
titlestringrequiredThe button label.
1–30 characters
urlstringrequiredThe HTTPS page the button opens.
uri · up to 2,048 characters
collapseKeystringoptionalA newer notification with the same key replaces the older one on the device.
pattern
^[A-Za-z0-9_-]{1,64}$soundstringoptionalThe name of a sound the app ships; the device's default if unset.
1–64 characters
badgeintegeroptionalThe number shown on the iOS app icon.
min 0 · max 99999
ttlDurationOrZeroInputoptionalHow long a provider keeps trying an offline device, up to 28 days; zero delivers now or never. Defaults to one day.
2 child attributes
valueintegerrequiredmin 0
unitstringrequiredone of
seconds,minutes,hours,days
urgencystringoptionalhighasks the push service to deliver promptly, even to a sleeping device;normallets it wait for a good moment to save battery. Device settings and the app still decide whether and how it is shown. Unset, a transactional push ishighand any othernormal.one of
high,normaloverridesobjectoptionalFields that differ on one platform, each replacing the shared one there (a whole
datamap, not merged key by key). On iOS and AndroidactionUrlmay be an app link such asmyapp://orders; the shared one and the web one must be HTTPS.3 child attributes
iosobjectoptionalReplaces shared fields on iOS.
14 child attributes
titlestringoptionalThe notification title (up to 100 characters).
1–100 characters
bodystringoptionalThe notification text (up to 500 characters).
1–500 characters
actionUrlstringoptionalpattern
^[a-z][a-z0-9+.-]*:\S+$· up to 2,048 charactersimageUrlstringoptionalA large picture: web and Android show it; iOS needs the app's service extension.
uri · up to 2,048 characters
iconUrlstringoptionalWeb only; iOS and Android show the app's own notification icon.
uri · up to 2,048 characters
datamap<string, string>optionalUp to 10 string key-value pairs passed to the app untouched, for deep links and in-app routing.
at most 10 keys · keys: pattern
^[A-Za-z0-9_.-]{1,64}$· values: up to 1,024 charactersbuttonsobject[]optionalUp to 2 action buttons.
at least 1 item · at most 2 items
2 child attributes
titlestringrequiredThe button label.
1–30 characters
urlstringrequiredThe HTTPS page the button opens.
uri · up to 2,048 characters
collapseKeystringoptionalA newer notification with the same key replaces the older one on the device.
pattern
^[A-Za-z0-9_-]{1,64}$soundstringoptionalThe name of a sound the app ships; the device's default if unset.
1–64 characters
badgeintegeroptionalThe number shown on the iOS app icon.
min 0 · max 99999
ttlDurationOrZeroInputoptionalHow long a provider keeps trying an offline device, up to 28 days; zero delivers now or never. Defaults to one day.
2 child attributes
valueintegerrequiredmin 0
unitstringrequiredone of
seconds,minutes,hours,days
urgencystringoptionalhighasks the push service to deliver promptly, even to a sleeping device;normallets it wait for a good moment to save battery. Device settings and the app still decide whether and how it is shown. Unset, a transactional push ishighand any othernormal.one of
high,normalinterruptionLevelstringoptionalHow iOS presents it:
passivearrives silently,time-sensitivecan break through Focus when the user allows it, and needs the app's Time Sensitive Notifications capability.one of
passive,active,time-sensitivethreadIdstringoptionalNotifications with the same thread are grouped together in Notification Center.
pattern
^[A-Za-z0-9_.-]{1,64}$
androidobjectoptionalReplaces shared fields on Android.
13 child attributes
titlestringoptionalThe notification title (up to 100 characters).
1–100 characters
bodystringoptionalThe notification text (up to 500 characters).
1–500 characters
actionUrlstringoptionalpattern
^[a-z][a-z0-9+.-]*:\S+$· up to 2,048 charactersimageUrlstringoptionalA large picture: web and Android show it; iOS needs the app's service extension.
uri · up to 2,048 characters
iconUrlstringoptionalWeb only; iOS and Android show the app's own notification icon.
uri · up to 2,048 characters
datamap<string, string>optionalUp to 10 string key-value pairs passed to the app untouched, for deep links and in-app routing.
at most 10 keys · keys: pattern
^[A-Za-z0-9_.-]{1,64}$· values: up to 1,024 charactersbuttonsobject[]optionalUp to 2 action buttons.
at least 1 item · at most 2 items
2 child attributes
titlestringrequiredThe button label.
1–30 characters
urlstringrequiredThe HTTPS page the button opens.
uri · up to 2,048 characters
collapseKeystringoptionalA newer notification with the same key replaces the older one on the device.
pattern
^[A-Za-z0-9_-]{1,64}$soundstringoptionalThe name of a sound the app ships; the device's default if unset.
1–64 characters
badgeintegeroptionalThe number shown on the iOS app icon.
min 0 · max 99999
ttlDurationOrZeroInputoptionalHow long a provider keeps trying an offline device, up to 28 days; zero delivers now or never. Defaults to one day.
2 child attributes
valueintegerrequiredmin 0
unitstringrequiredone of
seconds,minutes,hours,days
urgencystringoptionalhighasks the push service to deliver promptly, even to a sleeping device;normallets it wait for a good moment to save battery. Device settings and the app still decide whether and how it is shown. Unset, a transactional push ishighand any othernormal.one of
high,normalchannelIdstringoptionalThe Android notification channel to post in, which the app creates; it sets the sound and importance a person can tune, e.g. one for offers and one for orders.
pattern
^[A-Za-z0-9_.-]{1,64}$
webobjectoptionalReplaces shared fields on web.
12 child attributes
titlestringoptionalThe notification title (up to 100 characters).
1–100 characters
bodystringoptionalThe notification text (up to 500 characters).
1–500 characters
actionUrlstringoptionalThe HTTPS page opened when the notification is tapped.
uri · up to 2,048 characters
imageUrlstringoptionalA large picture: web and Android show it; iOS needs the app's service extension.
uri · up to 2,048 characters
iconUrlstringoptionalWeb only; iOS and Android show the app's own notification icon.
uri · up to 2,048 characters
datamap<string, string>optionalUp to 10 string key-value pairs passed to the app untouched, for deep links and in-app routing.
at most 10 keys · keys: pattern
^[A-Za-z0-9_.-]{1,64}$· values: up to 1,024 charactersbuttonsobject[]optionalUp to 2 action buttons.
at least 1 item · at most 2 items
2 child attributes
titlestringrequiredThe button label.
1–30 characters
urlstringrequiredThe HTTPS page the button opens.
uri · up to 2,048 characters
collapseKeystringoptionalA newer notification with the same key replaces the older one on the device.
pattern
^[A-Za-z0-9_-]{1,64}$soundstringoptionalThe name of a sound the app ships; the device's default if unset.
1–64 characters
badgeintegeroptionalThe number shown on the iOS app icon.
min 0 · max 99999
ttlDurationOrZeroInputoptionalHow long a provider keeps trying an offline device, up to 28 days; zero delivers now or never. Defaults to one day.
2 child attributes
valueintegerrequiredmin 0
unitstringrequiredone of
seconds,minutes,hours,days
urgencystringoptionalhighasks the push service to deliver promptly, even to a sleeping device;normallets it wait for a good moment to save battery. Device settings and the app still decide whether and how it is shown. Unset, a transactional push ishighand any othernormal.one of
high,normal
pushProjectIdstringoptionalReaches the contact's devices on every app of the project. Needed only when the workspace has more than one push project.
uuid
sendAtstringoptionalWhen to send, up to 90 days ahead, with its UTC offset. Suppression and push reachability are checked when the request is accepted and again when it goes. A
fallbackOrderfallback keeps this time but goes only after the message before it fails, is skipped or bounces.date-time
fallbackOrderstring[]optionalWith both
pushandemail, each once, in the order to try them: the first the contact can receive is sent, and the next only if it fails, is skipped or bounces. Left out, each channel the contact can receive is sent.at least 1 item
Returns
Returns 202 Accepted with a TransactionalSendResult in data. It can also return 409 Conflict, 413 Payload Too Large or 415 Unsupported Media Type; see the statuses below. Otherwise returns an error; Errors lists every code and which to retry.
202 AcceptedAccepted: one message per channel sent.409 ConflictThe request conflicts with current state — a duplicate unique value, or a resource whose status does not allow this operation.413 Payload Too LargeThe body is larger than this operation accepts (PAYLOAD_TOO_LARGE).415 Unsupported Media TypeThe body is not JSON, or not the upload the operation takes (UNSUPPORTED_MEDIA_TYPE).
messagesTransactionalMessage[]required8 child attributes
idstringrequireduuid
channelstringrequiredone of
email,pushstatusstringrequiredone of
queued,sending,skipped,sent,failed,delivered,bounced,complainedcorrelationIdstring | nullrequiredThe
correlationIdgiven when it was sent, if any.createdAtstringrequireddate-time
sendAtstring | nullrequiredWhen a timed message goes out; null when it went at once.
date-time
fallbackForstring | nullrequiredWith
fallbackOrder: the message this one stands in for. It waits asqueueduntil that one ends: sent when it failed, was skipped or bounced, else skipped with reasonfallback_not_needed. Null otherwise.uuid
copyobject | nullrequiredSet on a
ccorbcccopy; null on the message itself.2 child attributes
kindstringrequiredone of
cc,bccofstringrequiredThe message it is a copy of.
uuid
skippedChannelsTransactionalSkippedChannel[]requiredChannels given that were not sent, each with the reason: the contact cannot receive it, or the plan has no room for it.
3 child attributes
channelstringrequiredone of
email,pushcodestringrequiredIts error code, such as
SUPPRESSED.messagestringrequired
skippedCopiesTransactionalSkippedCopy[]requiredccorbccaddresses that got no copy, each with the reason.4 child attributes
emailstringrequiredkindstringrequiredone of
cc,bcccodestringrequiredIts error code, such as
SUPPRESSED.messagestringrequired
Headers on 202 Accepted
Idempotency-Replaystringoptionaltruewhen this is the stored response to an earlier request with the same key.one of
true