API
REST API
Every object you can touch in the dashboard is reachable over HTTP, with scoped API keys so a key can read contacts without being able to send.
app.sendheron.com/api-keys

What it does
The dashboard is one client of the API, not a privileged one. Contacts, tags, sequences, enrollments, templates, sending and analytics are all addressable over plain HTTP with a bearer token, and the whole reference is published, including a markdown copy of every page.
Keys carry scopes, and a request is rejected unless the key holds every scope the endpoint requires. Every one of them, not any one of them. A key you hand to a reporting script can read analytics without being able to send a single message.
There are 12 scopes: contacts:read, contacts:write, sequences:read, sequences:write, templates:read, templates:write, analytics:read, emails:send, suppressions:read, suppressions:write, sending:read and sending:write. They are deliberately coarse enough to reason about and fine enough to matter.
The shape of it
- 01
Mint a scoped key
Pick only the scopes the caller needs out of the 12.
- 02
Send a bearer token
One header. No session, no cookie, no CSRF token.
- 03
Get a real status code
Including a 403 when the key is missing a scope the route needs.
- 04
Respect two ceilings
One on the key, one on the organization. Both are per minute.
How it works
Authentication is one header. A key that lacks a scope the route requires gets a 403 rather than a silent empty result, which is the difference between a permissions problem you find in five minutes and one you find in production.
Rate limits are published rather than discovered, and there are two of them, both per minute. One key is capped at 100 requests. Your organization is capped separately and split by what a call costs: 1,200 for any GET, plus template validation and preview; 400 for every other mutation, including contact writes whose events may start an automatic enrollment; 200 for anything that dispatches or schedules mail, or enrols a contact in a sequence. That second ceiling is shared across every key you hold, so minting more keys buys no extra throughput. Both ceilings count requests. How much mail goes out in a day is a separate limit, counted per recipient over a rolling 24 hours, and a send over it waits and goes out by itself instead of failing. Whichever ceiling you cross returns a 429, and knowing both up front is what lets you size a sync job correctly the first time. Every response carries X-RateLimit headers naming the limit that applies, what remains of it, and when the window resets; a 429 carries Retry-After; and GET /usage reports the same ceilings alongside the monthly send pool and the day's sending position, so a job can read its budget before it starts.
Writes are built for scripts that run more than once. The contact upsert matches on email, so a nightly sync can run twice, or be re-run after a failure, without creating a second copy of anybody.
# This key holds analytics:read and nothing else.
curl https://api.sendheron.com/api/v1/contacts \
-H "Authorization: Bearer $SENDHERON_REPORTING_KEY"
# 403. GET /contacts requires contacts:read, and a key
# that cannot read contacts certainly cannot send to them.- Scoped bearer tokens across 12 permissions
- Documented rate limits, applied per window
- Idempotent upsert on email, so a sync job can run twice safely
- Standard status codes, including 403 when a key lacks a scope
Related: driving the API from an agent or a cron job, transactional and marketing sending
What makes it different, honestly
Nothing here is a second surface bolted on after the dashboard shipped. The same endpoints the interface calls are the endpoints you call, which is why the reference can be exhaustive rather than a curated subset.
The documentation is machine-readable on purpose. Every endpoint page has a markdown twin at the same address with .md appended, the entire reference is available as one markdown document, and the site publishes an llms.txt index. A tool that reads the docs does not have to parse our HTML, and neither does a person: there is a button on the reference that copies the whole thing in a form you can paste into a model.
What the reference does not include is a way for SendHeron to call you back. There are no outbound webhooks documented today: you can drive it, but it will not notify your application when something happens.
Emails your backend starts
Questions
REST API, in detail
Free trial
REST API, live on every plan
Everything on this page ships today, on every tier. Start a trial and use it on real sending.
7-day free trial. Pick a plan, add a card, cancel before the trial ends and you won't be charged. 1,000 contacts and 5,000 sends during the trial.