API reference
Emails
Send and read email.
/v1/emails/received/addressYour managed inbound address
emails:rNode.js SDKhonkio.emails.received.address()Requires emails:r.
Responses
200The account's managed inbound address (anything@… reaches it), minted on first call and stable after. enabled is the managed-address switch: mail sent to it while off is discarded, uncharged.
Field Type Description domainrequiredstring examplerequiredstring livemoderequiredboolean enabledrequiredboolean - 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403ACCOUNT_NOT_VERIFIED: the live managed address needs a verified owner mobile number. A test key is never refused; it always mints and returns the test address. Also FORBIDDEN when the key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
Example
const { data: address, error } = await honkio.emails.received.address()
if (error) throw new Error(error.message)
console.log(address.example)curl https://api.honkio.ca/v1/emails/received/address \
-H "Authorization: Bearer mk_live_YOUR_KEY"/v1/emails/received/addressTurn your managed inbound address on or off (live keys only)
emails:mNode.js SDKhonkio.emails.received.setAddressEnabled()Requires emails:m.
Request body
Turns the account's live managed inbound address on or off.
| Field | Type | Description |
|---|---|---|
enabledrequired | boolean | False stops accepting mail at the managed address; true accepts it again. Your own receiving domains are not affected. |
Responses
200The same address object GET returns, with enabled set to the requested value. The flag is account-wide: turning it off stops the live managed address receiving, so only a live key may change it.
Field Type Description domainrequiredstring examplerequiredstring livemoderequiredboolean enabledrequiredboolean - 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403LIVE_KEY_REQUIRED: the switch is account-wide and turns the live address off, so a test key cannot change it (GET still reports it). Also ACCOUNT_NOT_VERIFIED (needs a verified owner mobile number) or FORBIDDEN when the key lacks emails:m.The standard error body.
- 422VALIDATION_ERROR: the request failed validation; details names the fields.The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
Example
const { data, error } = await honkio.emails.received.setAddressEnabled(false)
if (error) throw new Error(error.message)
console.log(data.enabled)curl -X PATCH https://api.honkio.ca/v1/emails/received/address \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"enabled": false
}'/v1/emails/receivedList received emails
emails:rNode.js SDKhonkio.emails.received.list()Requires emails:r.
Responses
200A page of received emails, newest first.
Field Type Description data[]requiredobject[] idrequiredstring fromrequiredstring from_namerequiredstring - Can be null
torequiredstring[] ccrequiredstring[] subjectrequiredstring message_idrequiredstring - Can be null
in_reply_torequiredstring - Can be null
received_atrequiredstring - Format: date-time
statusrequiredstring - One of: received | rejected
reject_reasonrequiredstring Why a rejected message was stored headers only and uncharged: virus, daily_cap (the daily message cap), daily_mb_cap (the daily cap on billable MB), or insufficient_balance (the balance could not cover its charge). Null for a received message.
- Can be null
verdictsrequiredobject spfrequiredstring dkimrequiredstring dmarcrequiredstring spamrequiredstring virusrequiredstring attachments_countrequiredinteger size_bytesrequiredinteger charge_millicentsrequiredinteger domain_idrequiredstring - Can be null
livemoderequiredboolean has_morerequiredboolean next_cursorrequiredstring - Can be null
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403The API key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 422VALIDATION_ERROR: the request failed validation; details names the fields.The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
Example
const { data, error } = await honkio.emails.received.list({ limit: 10 })
if (error) throw new Error(error.message)
for (const email of data.data) console.log(email.id, email.from, email.subject)curl https://api.honkio.ca/v1/emails/received \
-H "Authorization: Bearer mk_live_YOUR_KEY"/v1/emails/received/simulateSimulate a received email (test keys only)
emails:wNode.js SDKhonkio.emails.received.simulate()Requires emails:w.
Request body
A message to receive as if it had arrived by email, run through the same processing, record and email.received webhook as real mail.
| Field | Type | Description |
|---|---|---|
fromrequired | string | The sender's address.
|
torequired | string[] | Up to 10 recipients, each your test managed address or an address at one of your test mode domains. |
cc | string[] | Up to 10 more recipients, with the same rule as to. |
subject | string | Up to 998 characters.
|
text | string | The plain text body.
|
html | string | The HTML body.
|
attachments[] | object[] | Up to 10 files, 10 MB in total. |
filenamerequired | string | The file name.
|
content_typerequired | string | The MIME type, such as application/pdf.
|
contentrequired | string | The file, base64 encoded. |
content_id | string | A Content-ID, so html can reference the file as cid:.
|
inline | boolean | Mark the file inline rather than attached. |
verdicts | object | The spam, virus and authentication verdicts to record. virus FAIL stores the message as rejected, as real mail would be. |
spf | string | The verdict to record. Left out, it is PASS.
|
dkim | string | The verdict to record. Left out, it is PASS.
|
dmarc | string | The verdict to record. Left out, it is PASS.
|
spam | string | The verdict to record. Left out, it is PASS.
|
virus | string | The verdict to record. Left out, it is PASS.
|
in_reply_to | string | The Message-ID this message replies to, for threading.
|
headers[] | object[] | Up to 20 extra headers. |
namerequired | string | The header name. |
valuerequired | string | The header value. |
Responses
201The simulated message, in the same shape GET /v1/emails/received/:id answers with. livemode is always false.
Field Type Description idrequiredstring fromrequiredstring from_namerequiredstring - Can be null
torequiredstring[] ccrequiredstring[] subjectrequiredstring message_idrequiredstring - Can be null
in_reply_torequiredstring - Can be null
received_atrequiredstring - Format: date-time
statusrequiredstring - One of: received | rejected
reject_reasonrequiredstring Why a rejected message was stored headers only and uncharged: virus, daily_cap (the daily message cap), daily_mb_cap (the daily cap on billable MB), or insufficient_balance (the balance could not cover its charge). Null for a received message.
- Can be null
verdictsrequiredobject spfrequiredstring dkimrequiredstring dmarcrequiredstring spamrequiredstring virusrequiredstring attachments_countrequiredinteger size_bytesrequiredinteger charge_millicentsrequiredinteger domain_idrequiredstring - Can be null
livemoderequiredboolean textrequiredstring - Can be null
htmlrequiredstring - Can be null
html_formatrequiredstring - One of: cid | links | sanitized
remote_imagesrequiredinteger Remote images parked in data-remote-src by html_format=sanitized; null for the other formats.
- Can be null
headers[]requiredobject[] namerequiredstring valuerequiredstring referencesrequiredstring[] reply_torequiredstring[] envelope_recipientsrequiredstring[] body_purgedrequiredboolean body_truncatedrequiredboolean text or html was cut at 2 MB (UTF-8 bytes) when stored; the raw message keeps it whole.
raw_availablerequiredboolean parse_failedrequiredboolean attachments_bytesrequiredinteger Total size of the attachments, in bytes.
attachments[]requiredobject[] idrequiredstring filenamerequiredstring content_typerequiredstring content_idrequiredstring - Can be null
inlinerequiredboolean size_bytesrequiredinteger expires_atrequiredstring - Format: date-time
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403TEST_KEY_REQUIRED: this endpoint only accepts test keys.The standard error body.
- 422VALIDATION_ERROR (bad input, or attachments over 10 MB total) or SIMULATE_RECIPIENT_NOT_OWNED (a to/cc address is neither the account's test managed address nor one of its own test-mode domains).The standard error body.
- 429TEST_EMAIL_QUOTA_EXCEEDED: the account has simulated 200 received emails in the last 24 hours, counted apart from test sends (details carry direction inbound, limit, used, requested and window_hours). Or RATE_LIMITED at 100 requests per second.The standard error body.
- 500Unexpected server error.The standard error body.
Example
// Test keys only: no real sender involved.
const { data, error } = await honkio.emails.received.simulate({
from: 'sam@example.com',
to: ['support@yourdomain.ca'],
subject: 'Where is my order?',
text: 'Hi, it has been a week.',
})
if (error) throw new Error(error.message)
console.log(data.id)curl -X POST https://api.honkio.ca/v1/emails/received/simulate \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "sam@example.com",
"to": [
"support@yourdomain.ca"
],
"subject": "Where is my order?",
"text": "Hi, it has been a week."
}'/v1/emails/received/{id}Get a received email
emails:rNode.js SDKhonkio.emails.received.get()Requires emails:r.
Parameters
| Parameter | Type | Description |
|---|---|---|
idrequiredpath | string |
Responses
200The received email. html is rewritten to point cid: images at the attachment route unless html_format=cid asks for the original; html_format=sanitized also strips scripts and unsafe markup and parks remote images in data-remote-src, counted in remote_images.
Field Type Description idrequiredstring fromrequiredstring from_namerequiredstring - Can be null
torequiredstring[] ccrequiredstring[] subjectrequiredstring message_idrequiredstring - Can be null
in_reply_torequiredstring - Can be null
received_atrequiredstring - Format: date-time
statusrequiredstring - One of: received | rejected
reject_reasonrequiredstring Why a rejected message was stored headers only and uncharged: virus, daily_cap (the daily message cap), daily_mb_cap (the daily cap on billable MB), or insufficient_balance (the balance could not cover its charge). Null for a received message.
- Can be null
verdictsrequiredobject spfrequiredstring dkimrequiredstring dmarcrequiredstring spamrequiredstring virusrequiredstring attachments_countrequiredinteger size_bytesrequiredinteger charge_millicentsrequiredinteger domain_idrequiredstring - Can be null
livemoderequiredboolean textrequiredstring - Can be null
htmlrequiredstring - Can be null
html_formatrequiredstring - One of: cid | links | sanitized
remote_imagesrequiredinteger Remote images parked in data-remote-src by html_format=sanitized; null for the other formats.
- Can be null
headers[]requiredobject[] namerequiredstring valuerequiredstring referencesrequiredstring[] reply_torequiredstring[] envelope_recipientsrequiredstring[] body_purgedrequiredboolean body_truncatedrequiredboolean text or html was cut at 2 MB (UTF-8 bytes) when stored; the raw message keeps it whole.
raw_availablerequiredboolean parse_failedrequiredboolean attachments_bytesrequiredinteger Total size of the attachments, in bytes.
attachments[]requiredobject[] idrequiredstring filenamerequiredstring content_typerequiredstring content_idrequiredstring - Can be null
inlinerequiredboolean size_bytesrequiredinteger expires_atrequiredstring - Format: date-time
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403The API key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 404RECEIVED_EMAIL_NOT_FOUND: no received email with that id on this account. A test key finds only messages received on the test managed address.The standard error body.
- 422VALIDATION_ERROR: html_format is not cid, links or sanitized.The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
Example
const { data: email, error } = await honkio.emails.received.get('RECEIVED_EMAIL_ID')
if (error) throw new Error(error.message)
console.log(email.from, email.subject, email.text)curl https://api.honkio.ca/v1/emails/received/ID \
-H "Authorization: Bearer mk_live_YOUR_KEY"/v1/emails/received/{id}/rawDownload the raw MIME of a received email
emails:rNode.js SDKhonkio.emails.received.raw()Requires emails:r.
Parameters
| Parameter | Type | Description |
|---|---|---|
idrequiredpath | string |
Responses
- 200The raw MIME message, exactly as received.
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403The API key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 404RECEIVED_EMAIL_NOT_FOUND: no received email with that id on this account. A test key finds only messages received on the test managed address.The standard error body.
- 410ATTACHMENT_EXPIRED: the raw message or attachment is no longer stored (40-day retention).The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
Example
const { data: mime, error } = await honkio.emails.received.raw('RECEIVED_EMAIL_ID')
if (error) throw new Error(error.message)
console.log(await mime.text())curl https://api.honkio.ca/v1/emails/received/ID/raw \
-H "Authorization: Bearer mk_live_YOUR_KEY"/v1/emails/received/{id}/attachments/{attachmentId}Download a received attachment
emails:rNode.js SDKhonkio.emails.received.attachment()Requires emails:r.
Parameters
| Parameter | Type | Description |
|---|---|---|
idrequiredpath | string | |
attachmentIdrequiredpath | string |
Responses
- 200The attachment bytes, with Content-Disposition set to the original filename.
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403The API key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 404RECEIVED_EMAIL_NOT_FOUND: no received email with that id on this account. A test key finds only messages received on the test managed address.The standard error body.
- 410ATTACHMENT_EXPIRED: the raw message or attachment is no longer stored (40-day retention).The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
Example
const { data: file, error } = await honkio.emails.received.attachment('RECEIVED_EMAIL_ID', 'ATTACHMENT_ID')
if (error) throw new Error(error.message)
const bytes = new Uint8Array(await file.arrayBuffer())
console.log(bytes.length)curl https://api.honkio.ca/v1/emails/received/ID/attachments/ATTACHMENT_ID \
-H "Authorization: Bearer mk_live_YOUR_KEY"/v1/emailsList emails
emails:rNode.js SDKhonkio.emails.list()Requires emails:r.
Parameters
| Parameter | Type | Description |
|---|---|---|
limitquery | string | 1 to 100. Default 50. |
cursorquery | string | next_cursor from the previous page. |
statusquery | string | One of queued, scheduled, sending, sent, delivered, bounced, complained, rejected, failed, cancelled. |
tagquery | string | string[] | name:value. Repeat to require several; all must match. |
toquery | string | A full address in the email's to list (not cc or bcc), matched exactly whatever its case. |
fromquery | string | The full sender address, matched exactly whatever its case. |
sincequery | string | ISO 8601 date-time with an offset: created_at at or after this moment. |
untilquery | string | ISO 8601 date-time with an offset: created_at at or before this moment. |
domain_idquery | string | The sending domain's id (GET /v1/email-domains). |
Responses
200A page of sent emails in the calling key's mode (a live key never lists a test send, nor a test key a live one), newest first.
Field Type Description data[]requiredobject[] idrequiredstring fromrequiredstring torequiredstring[] subjectrequiredstring body_purged_atrequiredstring Set once retention purged the subject and body.
- Format: date-time
- Can be null
statusrequiredstring - One of: queued | scheduled | sending | sent | delivered | bounced | complained | rejected | failed | cancelled
ses_message_idrequiredstring - Can be null
is_commercialrequiredboolean attachments_countrequiredinteger livemoderequiredboolean tags[]requiredobject[] namerequiredstring valuerequiredstring created_atrequiredstring - Format: date-time
has_morerequiredboolean next_cursorrequiredstring - Can be null
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403The API key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 422VALIDATION_ERROR: the request failed validation; details names the fields.The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
Example
const { data, error } = await honkio.emails.list({ status: 'bounced', limit: 20 })
if (error) throw new Error(error.message)
for (const email of data.data) console.log(email.id, email.to)curl https://api.honkio.ca/v1/emails \
-H "Authorization: Bearer mk_live_YOUR_KEY"/v1/emailsSend an email
emails:wNode.js SDKhonkio.emails.send()Requires emails:w.
Request body
One email: a subject with html, text or both, or a template.
| Field | Type | Description |
|---|---|---|
from | string | Sender, optionally with a name. Its domain must be a verified sending domain on your account. Optional when the template sets one.
|
torequired | string | string[] | A string or an array; at most 50 recipients across to, cc and bcc. |
cc | string | string[] | A string or an array. |
bcc | string | string[] | A string or an array. |
reply_to | string | string[] | A string or an array. |
subject | string | Up to 998 characters on one line. Surrounding whitespace is trimmed, and a line break or other control character, whether sent or put in by a variable, becomes a space. Leave out subject, html and text when you send a template.
|
html | string | The HTML body: at most 2 MB, before and after variables are substituted. Give html, text or both, unless you send a template. |
text | string | The plain text body: at most 2 MB, before and after variables are substituted. Give html, text or both, unless you send a template. |
template | object | Send a stored template instead of subject, html and text: its id or alias, and values for its variables. |
idrequired | string | The template's id or alias. A live key sends its published version; a test key sends its draft.
|
variables | object | Values for the template's variables, by key.
|
language | string | en or fr: the template's language version to send. When that language has no email part, the default language's is sent. Only with template; left out, the default language.
|
variables | object | Values to substitute into placeholders in subject, html and text. Ignored when template is set; a template's own variables go in template.variables instead.
|
headers | object | Extra email headers, sent as given. Headers HonkIO sets itself (To, From, Subject, Content-Type, List-Unsubscribe and the like) and any name starting with ARC- or X-SES- are refused with EMAIL_HEADER_INVALID.
|
attachments[] | object[] | Up to 10 files and 25 MB in total. The first 2 MB per recipient are included; each started MB above that is charged per recipient (GET /v1/pricing). Executable and script types are refused.
|
filenamerequired | string | The file name the recipient sees. Surrounding whitespace is trimmed, and a line break or other control character becomes a space.
|
content | string | The file, base64 encoded. Give exactly one of content, content_base64 or path. |
content_base64 | string | The file, base64 encoded (the same as content). |
path | string | An HTTPS URL HonkIO fetches the file from.
|
content_type | string | The MIME type, such as application/pdf. Inferred when left out.
|
content_id | string | Embeds the file inline: reference it from html as cid: followed by this id. |
tags[] | object[] | Up to 10 name and value pairs, each part 1 to 256 letters, digits, underscores or hyphens. Names starting with honkio_ are reserved. Tags are kept after the subject and body are purged, so keep personal information out of them.
|
namerequired | string | |
valuerequired | string | |
is_commercial | boolean | False by default. True marks a commercial message under CASL: it goes to exactly one recipient, needs consent on file for that address, and carries an unsubscribe footer and header.
|
scheduled_at | string | Send later: an ISO 8601 date-time with an offset, 1 minute to 30 days ahead.
|
tracking | object | Open and click tracking for this email, overriding the sending domain's setting.
|
opens | boolean | Track opens with a pixel. |
clicks | boolean | Track clicks by rewriting links. |
disable_unsubscribe_footer | boolean | Leave out the unsubscribe footer HonkIO adds to a commercial email. The one click unsubscribe header is still sent. A commercial email still carries an unsubscribe link in every body: your own (in html a link marked with the data-unsubscribe attribute, in text a line saying unsubscribe with its URL on it or on the next line), or, where a body has none, the footer is added anyway.
|
Responses
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403FORBIDDEN (the key lacks emails:w), EMAIL_DOMAIN_NOT_ALLOWED (this key may not send from that domain) or SENDING_PAUSED (live email is paused for this account after a high bounce or complaint rate; details carry paused_until, reason and channel: "email"). Test keys are never paused.The standard error body.
- 409IDEMPOTENCY_KEY_REUSED (the Idempotency-Key was already used for a request with a different body) or EMAIL_IDEMPOTENCY_IN_PROGRESS (the first request with this key is still being processed).The standard error body.
- 422VALIDATION_ERROR (details names the fields), IDEMPOTENCY_KEY_RESERVED (the Idempotency-Key starts with notify:, a prefix HonkIO reserves), or a send-specific code such as EMAIL_DOMAIN_NOT_VERIFIED or EMAIL_COMMERCIAL_MULTI_RECIPIENT.The standard error body.
- 429EMAIL_DAILY_LIMIT_REACHED: a live key, in the account's email probation (its first 14 days from its first live email, unless staff set a limit), would email more than 500 recipients in 24 hours (details carry limit, sent, requested, window_hours, probation_ends_at and channel: "email"). Or TEST_EMAIL_QUOTA_EXCEEDED: the account's test keys have created 200 emails in the last 24 hours (details carry limit, used, requested and window_hours); live keys have no such quota. Or RATE_LIMITED at 100 requests per second.The standard error body.
- 500Unexpected server error.The standard error body.
Example
const { data, error } = await honkio.emails.send({
from: 'Acme <hello@yourdomain.ca>',
to: 'sam@example.com',
subject: 'Your receipt',
html: '<p>Thanks for your order, Sam.</p>',
})
if (error) throw new Error(`${error.name}: ${error.message}`)
console.log(data.id, data.status)curl -X POST https://api.honkio.ca/v1/emails \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "Acme <hello@yourdomain.ca>",
"to": "sam@example.com",
"subject": "Your receipt",
"html": "<p>Thanks for your order, Sam.</p>"
}'/v1/emails/{id}Get an email by id
emails:rNode.js SDKhonkio.emails.get()Requires emails:r.
Parameters
| Parameter | Type | Description |
|---|---|---|
idrequiredpath | string |
Responses
200The sent email, with its event timeline.
Field Type Description idrequiredstring fromrequiredstring torequiredstring[] subjectrequiredstring body_purged_atrequiredstring Set once retention purged the subject and body.
- Format: date-time
- Can be null
statusrequiredstring - One of: queued | scheduled | sending | sent | delivered | bounced | complained | rejected | failed | cancelled
ses_message_idrequiredstring - Can be null
is_commercialrequiredboolean attachments_countrequiredinteger livemoderequiredboolean tags[]requiredobject[] namerequiredstring valuerequiredstring created_atrequiredstring - Format: date-time
from_namerequiredstring - Can be null
ccrequiredstring[] bccrequiredstring[] htmlrequiredstring - Can be null
textrequiredstring - Can be null
templaterequiredany | object attachments[]requiredobject[] filenamerequiredstring content_typerequiredstring content_idrequiredstring - Can be null
size_bytesrequiredinteger cost_centsrequiredinteger Whole cents this send debited from the balance; often 0 for one sub-cent email.
charge_millicentsrequiredinteger The exact price the send consumed, in CAD millicents.
attachment_bytesrequiredinteger Total attachment bytes the charge was computed on.
scheduled_atrequiredstring - Format: date-time
- Can be null
updated_atrequiredstring - Format: date-time
events[]requiredobject[] typerequiredstring occurred_atrequiredstring - Format: date-time
payloadrequiredany - 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403The API key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 404NOT_FOUND (details.resource "email"): no email with that id on this account in the calling key's mode. A test key finds only test sends, a live key only live ones.The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
Example
const { data, error } = await honkio.emails.get('EMAIL_ID')
if (error) throw new Error(error.message)
console.log(data.status, data.events)curl https://api.honkio.ca/v1/emails/ID \
-H "Authorization: Bearer mk_live_YOUR_KEY"/v1/emails/{id}Reschedule a scheduled email
emails:mNode.js SDKhonkio.emails.update()Requires emails:m.
Parameters
| Parameter | Type | Description |
|---|---|---|
idrequiredpath | string |
Request body
The new send time of a scheduled email.
| Field | Type | Description |
|---|---|---|
scheduled_atrequired | string | An ISO 8601 date-time with an offset, 1 minute to 30 days ahead.
|
Responses
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403The API key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
Example
const { data, error } = await honkio.emails.update('EMAIL_ID', { scheduledAt: '2026-10-01T14:00:00Z' })
if (error) throw new Error(error.message)
console.log(data.scheduled_at)curl -X PATCH https://api.honkio.ca/v1/emails/ID \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"scheduled_at": "2026-10-01T14:00:00Z"
}'/v1/emails/{id}Cancel a scheduled email
emails:dNode.js SDKhonkio.emails.cancel()Requires emails:d.
Parameters
| Parameter | Type | Description |
|---|---|---|
idrequiredpath | string |
Responses
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403The API key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
Example
const { error } = await honkio.emails.cancel('EMAIL_ID')
if (error) throw new Error(error.message)curl -X DELETE https://api.honkio.ca/v1/emails/ID \
-H "Authorization: Bearer mk_live_YOUR_KEY"/v1/emails/batchSend a batch of emails
emails:wNode.js SDKhonkio.batch.send()Requires emails:w.
Request body
A JSON array of up to 100 independent emails, or one message for up to 500 recipients as an object with a recipients list. Attachments are not available in a batch, and scheduling only in the object form. The request body may be at most 10 MB; send a larger email on its own.
An array of up to 100 emails, each sent on its own. Every item is checked before any is sent.
| Field | Type | Description |
|---|---|---|
from | string | Sender, optionally with a name. Its domain must be a verified sending domain on your account. Optional when the template sets one.
|
torequired | string | string[] | A string or an array; at most 50 recipients across to, cc and bcc. |
cc | string | string[] | A string or an array. |
bcc | string | string[] | A string or an array. |
reply_to | string | string[] | A string or an array. |
subject | string | Up to 998 characters on one line. Surrounding whitespace is trimmed, and a line break or other control character, whether sent or put in by a variable, becomes a space. Leave out subject, html and text when you send a template.
|
html | string | The HTML body: at most 2 MB, before and after variables are substituted. Give html, text or both, unless you send a template. |
text | string | The plain text body: at most 2 MB, before and after variables are substituted. Give html, text or both, unless you send a template. |
template | object | Send a stored template instead of subject, html and text: its id or alias, and values for its variables. |
idrequired | string | The template's id or alias. A live key sends its published version; a test key sends its draft.
|
variables | object | Values for the template's variables, by key.
|
language | string | en or fr: the template's language version to send. When that language has no email part, the default language's is sent. Only with template; left out, the default language.
|
variables | object | Values to substitute into placeholders in subject, html and text. Ignored when template is set; a template's own variables go in template.variables instead.
|
headers | object | Extra email headers, sent as given. Headers HonkIO sets itself (To, From, Subject, Content-Type, List-Unsubscribe and the like) and any name starting with ARC- or X-SES- are refused with EMAIL_HEADER_INVALID.
|
tags[] | object[] | Up to 10 name and value pairs, each part 1 to 256 letters, digits, underscores or hyphens. Names starting with honkio_ are reserved. Tags are kept after the subject and body are purged, so keep personal information out of them.
|
namerequired | string | |
valuerequired | string | |
is_commercial | boolean | False by default. True marks a commercial message under CASL: it goes to exactly one recipient, needs consent on file for that address, and carries an unsubscribe footer and header.
|
tracking | object | Open and click tracking for this email, overriding the sending domain's setting.
|
opens | boolean | Track opens with a pixel. |
clicks | boolean | Track clicks by rewriting links. |
disable_unsubscribe_footer | boolean | Leave out the unsubscribe footer HonkIO adds to a commercial email. The one click unsubscribe header is still sent. A commercial email still carries an unsubscribe link in every body: your own (in html a link marked with the data-unsubscribe attribute, in text a line saying unsubscribe with its URL on it or on the next line), or, where a body has none, the footer is added anyway.
|
One message for up to 500 recipients, each with its own variables.
| Field | Type | Description |
|---|---|---|
from | string | Sender, optionally with a name. Its domain must be a verified sending domain on your account. Optional when the template sets one.
|
subject | string | Up to 998 characters on one line. Surrounding whitespace is trimmed, and a line break or other control character, whether sent or put in by a variable, becomes a space. Leave out subject, html and text when you send a template.
|
html | string | The HTML body: at most 2 MB, before and after variables are substituted. Give html, text or both, unless you send a template. |
text | string | The plain text body: at most 2 MB, before and after variables are substituted. Give html, text or both, unless you send a template. |
template | object | Send a stored template instead of subject, html and text: its id or alias, and values for its variables. |
idrequired | string | The template's id or alias. A live key sends its published version; a test key sends its draft.
|
variables | object | Values for the template's variables, by key.
|
language | string | en or fr: the template's language version to send. When that language has no email part, the default language's is sent. Only with template; left out, the default language.
|
headers | object | Extra email headers, sent as given. Headers HonkIO sets itself (To, From, Subject, Content-Type, List-Unsubscribe and the like) and any name starting with ARC- or X-SES- are refused with EMAIL_HEADER_INVALID.
|
tags[] | object[] | Up to 10 name and value pairs, each part 1 to 256 letters, digits, underscores or hyphens. Names starting with honkio_ are reserved. Tags are kept after the subject and body are purged, so keep personal information out of them.
|
namerequired | string | |
valuerequired | string | |
is_commercial | boolean | False by default. True marks a commercial message under CASL: it goes to exactly one recipient, needs consent on file for that address, and carries an unsubscribe footer and header.
|
scheduled_at | string | Send later: an ISO 8601 date-time, 1 minute to 30 days ahead.
|
tracking | object | Open and click tracking for this email, overriding the sending domain's setting.
|
opens | boolean | Track opens with a pixel. |
clicks | boolean | Track clicks by rewriting links. |
disable_unsubscribe_footer | boolean | Leave out the unsubscribe footer HonkIO adds to a commercial email. The one click unsubscribe header is still sent. A commercial email still carries an unsubscribe link in every body: your own (in html a link marked with the data-unsubscribe attribute, in text a line saying unsubscribe with its URL on it or on the next line), or, where a body has none, the footer is added anyway.
|
recipients[]required | object[] | Up to 500 recipients, each sent their own email. |
torequired | string | The recipient's address.
|
variables | object | Values for this recipient's placeholders or template variables.
|
Responses
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403FORBIDDEN, EMAIL_DOMAIN_NOT_ALLOWED or SENDING_PAUSED (live email is paused; details carry paused_until, reason and channel: "email"). Refused before any item is sent.The standard error body.
- 409IDEMPOTENCY_KEY_REUSED (the Idempotency-Key was already used for a batch with a different body) or CONFLICT (a batch with this key is still being processed).The standard error body.
- 422VALIDATION_ERROR (details names the fields), IDEMPOTENCY_KEY_RESERVED (the Idempotency-Key starts with notify:, a prefix HonkIO reserves), or a send-specific code such as EMAIL_DOMAIN_NOT_VERIFIED.The standard error body.
- 429EMAIL_DAILY_LIMIT_REACHED: with a live key in the account's email probation, the batch would take the account past its daily recipient limit; it is refused whole, before any email is created (details as for POST /v1/emails). A recipient of the object form that a concurrent send pushed past the limit is reported in rejected with that reason. Or TEST_EMAIL_QUOTA_EXCEEDED: with a test key, the batch would take the account past 200 test emails in 24 hours, counting one per recipient of the object form and one per email of the array form. It is refused whole, before any email is created (details carry limit, used, requested and window_hours). Or RATE_LIMITED at 100 requests per second.The standard error body.
- 500Unexpected server error.The standard error body.
Example
const { data, error } = await honkio.batch.send([
{ from: 'Acme <hello@yourdomain.ca>', to: 'sam@example.com', subject: 'Your receipt', html: '<p>Thanks, Sam.</p>' },
{ from: 'Acme <hello@yourdomain.ca>', to: 'alex@example.com', subject: 'Your receipt', html: '<p>Thanks, Alex.</p>' },
])
if (error) throw new Error(error.message)
console.log(data.batch_id, data.data.length)curl -X POST https://api.honkio.ca/v1/emails/batch \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '[
{
"from": "Acme <hello@yourdomain.ca>",
"to": "sam@example.com",
"subject": "Your receipt",
"html": "<p>Thanks, Sam.</p>"
},
{
"from": "Acme <hello@yourdomain.ca>",
"to": "alex@example.com",
"subject": "Your receipt",
"html": "<p>Thanks, Alex.</p>"
}
]'
HonkIO