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, 400 for mutations that send no mail, 200 for anything that dispatches or schedules mail, enrollment included. That second ceiling is shared across every key you hold, so minting more keys buys no extra throughput. There is no hourly and no daily quota. 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, 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. During the private beta, keys are also issued with the account rather than minted from a self-serve settings page.
Questions
REST API, in detail
Private beta
REST API, live in the private beta
We onboard a small number of teams at a time and review every account. That is how we keep deliverability high for everyone.