On this page
REST API & Webhook Reference
Public developer reference for sending email, triggering automations, managing recipient consent, and receiving signed lifecycle webhooks. No sign-in is required to read these docs.
Authentication
Create API keyPublic integration requests require a live or test API key in the Authorization header.
Keys may be scoped to one domain. A scoped key can only send from that verified domain. Dashboard endpoints use the signed-in browser session and are outside this public API contract.
Base URL
Integration endpoints accept and return JSON. Email sends use /api/emails; the Resend-compatible alias /emails has the same request and response contract.
Errors
JSON errors contain an error field. Rate-limit responses may be plain text.
400 | Invalid JSON, addresses, parameters, or a suppressed recipient |
401 | Missing or invalid API key |
402 | Insufficient email credits |
403 | Domain-scoped key does not match the sender domain |
404 | Referenced template or audience not found |
409 | An idempotency key was reused with a different request |
413 | JSON request body exceeds the endpoint limit |
423 | Sending is paused for this account |
429 | Rate limit exceeded |
500 | Unexpected server error |
DNS prerequisite: verify the domain's SPF and DKIM records before using outbound lifecycle, open, or click events. To use email.received, also publish the inbound MX record shown on the domain's DNS Records tab.
Rate limits
API-key endpoints share a limit of 300 requests per minute per key. Requests above the limit return HTTP 429. Use an idempotency key when retrying sends or automation events.
OpenAPI specification
The OpenAPI 3.1 contract is public and suitable for SDK generators, API clients, and validation tools.
Download the YAML specification or use /api/docs as the stable discovery route.
Send email
/api/emailsQueue an email from a verified domain. The response contains the email ID and initial status.
| Parameter | Type | Description | Required |
|---|---|---|---|
from | string | Sender on a verified domain; display names are allowed. | Yes |
to | string[] | At least one address. Maximum 50 unique recipients total across To, CC, and BCC; duplicate mailboxes are rejected case-insensitively. | Yes |
subject | string | Required unless supplied by the selected template; at most 998 bytes. | No |
html | string | HTML body, up to 1 MiB. Required unless text or a template body is available. | No |
text | string | Plain-text body, up to 100 KiB. Required unless HTML or a template body is available. | No |
cc | string[] | CC recipients. | No |
bcc | string[] | BCC recipients. | No |
reply_to | string | Reply-To address. | No |
headers | object | Up to 20 custom X-* headers; each pair is limited to 1 KiB. | No |
attachments | object[] | Up to 10 attachments, each at most 5 MiB decoded. The complete JSON request, including base64 expansion, must remain under 10 MiB. | No |
template_id | uuid | Saved template owned by this account. | No |
variables | object | String values for exact {{key}} placeholders. HTML values are escaped. | No |
scheduled_at | date-time | Future RFC 3339 timestamp, no more than one year ahead. | No |
Attachment object
| Parameter | Type | Description | Required |
|---|---|---|---|
filename | string | File name of at most 255 UTF-8 bytes, without path separators or control characters. | Yes |
content_type | string | Optional valid MIME media type such as application/pdf. | No |
content | string | Base64-encoded file content. | Yes |
Schedule delivery
Set scheduled_at to a future RFC 3339 timestamp. Scheduled sends can be queued up to one year ahead and consume credits when accepted.
Delivery retries
Temporary SMTP failures, including 4xx replies and connection errors, are retried for up to five days from the time the message becomes eligible for delivery. The first retry is scheduled after about 30 minutes, the second after about two hours, and later attempts every two to three hours. Small timing jitter prevents a recovering provider from receiving every delayed message at once.
Permanent 5xx replies are not retried. Only a permanent RCPT TO rejection is treated as a hard bounce and suppresses that exact recipient; sender, authentication, TLS, and message-transfer failures never suppress recipients.
For direct delivery to more than one recipient domain, Hivsy records each destination that already accepted the message. A later retry sends only to the remaining recipients, preventing duplicate delivery to successful domains.
The email detail page records every attempt with its SMTP stage, reply code, enhanced status, exact provider response, recipients already accepted, next retry time, and final retry deadline. Use the Events tab or copy the diagnostic report when investigating a failure.
Idempotency
Send an Idempotency-Key header of at most 256 characters. Reusing the key returns the original email with HTTP 200 and idempotent_replay: true instead of creating a duplicate.
Test mode
Test keys use the hsl_test_ prefix. They validate the same payload, record the email with status sent, and return HTTP 202 without delivering or consuming credits.
Suppressions
Hard bounces and one-click unsubscribes populate the suppression list automatically. A send containing any suppressed recipient is rejected with HTTP 400 before credits are charged. Manage suppressions in the dashboard or call POST /api/unsubscribe from an integration.
Trigger an automation event
/api/eventsRecord an application event and trigger active automations whose configured event name matches.
Include an Idempotency-Key header (up to 256 characters) when retrying. The same key and payload reuse the original event and automation runs; a changed payload returns HTTP 409.
| Parameter | Type | Description | Required |
|---|---|---|---|
name | string | Automation trigger name, for example user.signed_up. | Yes |
contact_email | string | Recipient used by matching email automations. Without it, the event is recorded and each matching email run is marked failed with a diagnostic. | No |
data | object | Application-defined metadata. The complete event request is limited to 1 MiB. | No |
Unsubscribe a contact
/api/unsubscribeUnsubscribe matching contacts across all owned audiences, or scope the update to one audience.
| Parameter | Type | Description | Required |
|---|---|---|---|
email | string | Contact email address. | Yes |
audience_id | uuid | Optional owned audience. Omit it to update every audience. | No |
Webhook delivery
Configure webhook endpoints from a verified domain in the dashboard. Hivsy returns the signing secret when an endpoint is created or its secret is rotated. Store it immediately.
An empty event selection subscribes the endpoint to every event. Hivsy treats any 2xx response as an acknowledgement and retries connection failures or non-2xx responses up to ten times, ending after the final 24-hour retry.
Webhook event types
| Event | Status | Meaning |
|---|---|---|
email.received | Live | Inbound email received for a verified domain |
email.sent | Live | Outbound message accepted by the recipient server |
email.failed | Live | Outbound delivery permanently failed |
email.delivery_delayed | Live | A temporary delivery failure will be retried |
email.opened | Live | Tracking pixel requested by a recipient |
email.clicked | Live | Tracked link opened by a recipient |
email.suppressed | Live | Delivery stopped because every recipient was suppressed |
Verify webhook signatures
Read the Webhook-Signature header and calculate HMAC-SHA256 over the exact raw request body. The header value is sha256=<lowercase hex digest>.X-Webhook-Signature is also sent for backward compatibility.
Verify the raw bytes before parsing JSON. Re-serializing the payload changes the signature input.