Skip to content
ChangelogBook a demoSign up

Send with the API

AudienceMarketers and developers
PrerequisitesA message built in Build an email or Build an SMS, and an API key

An API-triggered campaign sends when your own systems call it, with the recipients and their personalization supplied on each call. Use it for messages your application decides to send, such as an order confirmation or a password reset.

Set up the campaign

  1. Go to Native Delivery → Campaigns and add a campaign.
  2. Set the Schedule type to API-triggered.
  3. Build your message content.
  4. Select Activate.

An API-triggered campaign has no audience and no schedule. The API trigger card takes the place of the schedule settings. It shows a Sample payload for this campaign, generated with your message's own personalization variables, that you can copy and run.

A campaign carries one message. Dynamic content isn't supported in API-triggered campaigns.

Trigger a send

Send a POST to the trigger endpoint with your API key as a bearer token. Create keys under Settings → API keys.

curl -X POST 'https://api.hightouch.com/api/v1/campaigns/{campaignId}/trigger' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "recipients": [
      { "handle": "sam@example.com", "properties": { "First name": "Sam" } }
    ]
  }'

Copy the sample payload from the API trigger card instead of writing this by hand. It carries your campaign's ID, your workspace's regional host, and your message's actual variable names.

Personalization keys are the variable names as they appear in the editor, not the underlying column names. If two variables in one message share a name, the campaign won't activate until you rename one.

Up to 100 recipients per call. See the API reference for the full parameter list.

Recipients

Each recipient is identified one of two ways.

KeyUse it when
handleYou have the email address or phone number. Supply the personalization on the call.
idYou have the profile's primary key. Hightouch reads that profile's attributes and delivery address for you.

Sending by id requires a Warehouse attribute cache under Settings, plus a delivery address column mapped for the channel.

Personalization merges in order: the profile's own attributes, then any top-level properties, then that recipient's properties.

Read the response

A 200 returns one result per recipient, in the order you sent them.

{
  "results": [
    {
      "handle": "sam@example.com",
      "status": "accepted",
      "sendId": "..."
    },
    {
      "handle": "not-an-address",
      "status": "rejected",
      "reason": "invalid_handle"
    }
  ]
}

accepted means the message is queued, not that it was sent. Subscription preferences, send limits, and deliverability are all checked afterward, so an accepted recipient can still be skipped.

Rejections are per recipient and don't fail the call. A batch where every recipient is rejected still returns 200.

ReasonMeaning
invalid_handleNot a usable email address or phone number
missing_variablesThe message needs variables this call didn't supply. The names come back in missingVariables
invalid_idThe id was empty
missing_handle_or_idNeither key was supplied

Recipients sent by handle are validated as you call. Recipients sent by id are checked when the message is built, so their failures show up in the send status.

Check a send

Look up any accepted sendId to see what happened to it.

curl 'https://api.hightouch.com/api/v1/campaigns/{campaignId}/sends/{sendId}' \
  -H 'Authorization: Bearer YOUR_API_KEY'
StatusMeaning
sentHanded off for delivery, no result yet
deliveredDelivery was confirmed
bouncedThe address rejected it
failedThe send failed
droppedHightouch didn't send it. Some drops carry a reason

A send appears here once it's been attempted, so a lookup immediately after triggering returns 404. Retry instead of treating the first 404 as an error.

What you don't get

An API-triggered campaign has no audience and no schedule, which also means it has no runs. You get all-time campaign metrics, but no per-send breakdown, no runs list, and no Skipped or Expired counts.

Subscription topics, unsubscribes, bounced addresses, quiet hours, and frequency caps are all still enforced, so a recipient who unsubscribed doesn't receive an API-triggered marketing message.

Suppression lists are the exception. They're applied when a campaign builds its audience from your warehouse, and an API-triggered send has no audience to build, so they don't apply here. Filter those recipients out before you call.

Whether a message ignores subscription topics depends on marking it transactional, not on how it's triggered. See Subscriptions and consent.

Errors

CodeWhen
400The campaign isn't API-triggered, isn't active, has no published content, or carries more than one message
403Native Delivery isn't enabled for the workspace
404No campaign with that ID in this workspace
422The payload didn't validate: more than 100 recipients, missing fields, or unrecognized ones
429Too many requests. The limit is shared across all Hightouch API calls from your workspace

To test before activating, pass "draft": true and send from a draft campaign. Content and recipient validation still run, as do all send limits, so a draft send to an unsubscribed recipient is still skipped.

Next steps

Ready to get started?

Jump right in or a book a demo. Your first destination is always free.

Book a demoSign upBook a demo

Need help?

Our team is relentlessly focused on your success. Don't hesitate to reach out!

Feature requests?

We'd love to hear your suggestions for integrations and other features.

Privacy PolicyTerms of Service