HelloSend Public API v3 — Reference

Version: v3
Production base URL: https://api.hellosend.com


Table of Contents

  1. Overview
  2. Authentication
  3. Request & Response Conventions
  4. Errors
  5. Idempotency
  6. Endpoints - Auth - Messages - Numbers - Templates - Contacts - Webhooks (REST Hooks) - Webhook Samples
  7. Webhook Events
  8. Zapier Integration Mapping
  9. Getting an API Key
  10. Endpoint Index

Overview

Path Prefix

All routes use the prefix /api/v3/....

Example: GET https://api.hellosend.com/api/v3/auth/verify

Content Type


Authentication

Every /api/v3 request requires a long-lived API key issued from the HelloSend web app.

Header Required Description
X-HelloSend-API-Key Yes Your API key secret
Accept Recommended application/json
Content-Type For POST bodies application/json

API keys are user-scoped for hooks and sends, and account-scoped for shared resources such as contacts. Revoking a key or deactivating its owner invalidates the key and removes all hook subscriptions created with that key.


Request & Response Conventions

List Responses

List endpoints wrap results in a named array:

Endpoint Family Response Key Item Type
Numbers numbers Number object
Templates templates Template object
Contacts contacts Contact object
Hooks hooks Hook object
Webhook Samples events Webhook envelope

Dates & Times

Field Format Notes
occurredAt (webhooks) ISO 8601 UTC e.g. 2026-04-20T12:34:56.789Z
createdTime (hooks) ISO 8601
receivedAt, loggedAt (webhook data) Unix milliseconds Integer epoch ms

Phone Numbers

Use E.164 format (e.g. +14155551234).


Errors

All error responses use this envelope:

{
  "error": "snake_case_code",
  "message": "Human-readable explanation."
}

HTTP Status Codes

Status Typical error Codes Meaning
400 invalid_request, missing_field, unsupported_event, invalid_target_url Malformed or invalid input
401 invalid_api_key, authentication_failed Missing, revoked, or invalid key
404 not_found, template_not_found, hook_not_found Resource not found
409 idempotency_in_progress Duplicate in-flight request
422 send_failed, body_not_allowed_for_structured_template Business rule violation
429 — Rate limited; retry after Retry-After header (planned)
500 internal_error Server error

Error Code Reference

Code Description
authentication_failed Auth context missing
invalid_api_key Key missing, unknown, or revoked
missing_header Required header absent
invalid_request Body or parameters invalid
missing_field Required JSON field absent
missing_parameter Required query parameter absent
invalid_parameter Query parameter out of range or wrong type
template_not_found No template found for given id in this account
body_not_allowed_for_structured_template body sent with a WhatsApp/RCS template
send_failed Provider rejected the outbound message
unsupported_event Hook event not in supported set
invalid_target_url Hook targetUrl must be absolute https://
hook_not_found Hook id not found for this user
not_found Generic 404
internal_error Unexpected server failure
idempotency_in_progress Same Idempotency-Key still processing

Idempotency

POST /api/v3/messages supports optional idempotent sends via the Idempotency-Key request header. Using this header prevents duplicate sends on retries.

Header Required Description
Idempotency-Key No (recommended) A unique string per logical send (UUID recommended)

Behavior

Scenario Result
No header Normal send; no replay cache
First request with key Executes send; caches 2xx response body
Same key while first in flight 409 idempotency_in_progress, Retry-After: 2
Same key after success Replays cached 2xx body; includes X-Idempotent-Replay: true
Same key after non-2xx Claim released; caller may retry with same key

Idempotency is scoped to account + user.


Endpoints

Auth

Verify Connection

GET /api/v3/auth/verify

Confirms a valid API key and returns metadata for connection labels.

Response 200

Field Type Description
userEmail string Email of the key owner
userName string Display name of the key owner
osyncUserId string Internal user identifier
accountName string Workspace / account label
apiKeyId string Key record id
apiKeyName string Label given at key creation

Example request

GET /api/v3/auth/verify HTTP/1.1
Host: api.hellosend.com
X-HelloSend-API-Key: hs_live_xxxxxxxxxxxxxxxx
Accept: application/json

Example response

{
  "userEmail": "alex@example.com",
  "userName": "Alex Morgan",
  "osyncUserId": "usr_abc123",
  "accountName": "Acme Corp",
  "apiKeyId": "key_xyz789",
  "apiKeyName": "Zapier production"
}

Messages

Send Message

POST /api/v3/messages

Send an outbound SMS, MMS, WhatsApp, or RCS message.

Request body

Field Required Description
uniqueId Yes Sender id from Numbers list id (senderUniqueId)
toNumber Yes E.164 recipient number
body Conditional Message text. Required when no templateId. Omit for structured WhatsApp/RCS templates.
templateId No HelloSend template id
variables No Map of placeholder name → string value for template merge
module No Optional CRM module name for analytics

Template rules

Response 201

Field Type Description
id string Message id
messageId string Provider message identifier
status string "sent" on success
fromNumber string Resolved E.164 sender
toNumber string Recipient
serviceId string Resolved integration id
templateId string Present when a template was used
module string Present when supplied

Example — plain SMS

POST /api/v3/messages HTTP/1.1
Host: api.hellosend.com
X-HelloSend-API-Key: hs_live_xxxxxxxxxxxxxxxx
Content-Type: application/json
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
{
  "uniqueId": "SN_01ARZ3NDEKTSV4RRFFQ69G5FAV",
  "toNumber": "+14155551234",
  "body": "Your appointment is confirmed for tomorrow at 2pm."
}

Response

{
  "id": "SMxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "messageId": "SMxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "status": "sent",
  "fromNumber": "+14155559876",
  "toNumber": "+14155551234",
  "serviceId": "integ_abc123"
}

Example — template with variables

{
  "uniqueId": "SN_01ARZ3NDEKTSV4RRFFQ69G5FAV",
  "toNumber": "+14155551234",
  "templateId": "tmpl_welcome_001",
  "variables": {
    "firstName": "Ada",
    "orderId": "ORD-42"
  }
}

Numbers

List Numbers

GET /api/v3/numbers

Returns phone numbers the authenticated user may send from. Used to populate From Number dropdowns.

Response 200 — numbers[] item

Field Type Description
id string senderUniqueId — pass as uniqueId on send
integId string Integration id (display; resolved on send)
phoneNumber string E.164 number (display)
friendlyName string User-assigned label
provider string Messaging provider display name
crm string Connected CRM display name
channels string[] e.g. ["sms","mms","whatsapp"]
whatsappBusinessAccountId string Present for WhatsApp-enabled numbers
label string Pre-rendered dropdown label

Example response

{
  "numbers": [
    {
      "id": "SN_01ARZ3NDEKTSV4RRFFQ69G5FAV",
      "integId": "integ_abc123",
      "phoneNumber": "+14155559876",
      "friendlyName": "Main sales line",
      "provider": "Twilio",
      "crm": "HubSpot",
      "channels": ["sms", "mms"],
      "label": "+14155559876 — HubSpot via Twilio (SMS · MMS)"
    }
  ]
}

Templates

List Templates

GET /api/v3/templates

Query parameters

Param Required Description
integId No Filter to templates for this integration
module No CRM module name filter
channels No Comma-separated types: application, whatsapp, twiliorcs. Default: application

Response 200 — templates[] item

Field Type Description
id string Template id
name string Friendly name
moduleName string Module scope (general when global)
templateType string application, whatsapp, or twiliorcs
content string Template body (application templates)
integId string Integration scope when set
label string Pre-rendered dropdown label
placeholders array { name, type?, required? } entries

Get Template

GET /api/v3/templates/{id}

Returns full template detail including placeholders and, for structured templates, components.

Errors: 404 template_not_found when the id does not exist in the account.


Contacts

Find Contacts by Phone

GET /api/v3/contacts?phone={phone}

Account-scoped contact lookup. Returns an empty contacts array when no match — not an error.

Query parameters

Param Required Description
phone Yes Phone number to search (E.164 recommended)

Response 200 — contacts[] item

Field Type Description
id string HelloSend contact id
phone string Phone on the contact record
firstName string
lastName string
email string
integId string Integration id
rightServiceId string Messaging service id
remoteContactId string CRM-side contact id

Webhooks (REST Hooks)

HelloSend delivers webhook payloads to HTTPS URLs registered via these endpoints. Use these routes to subscribe and unsubscribe triggers.

List Hooks

GET /api/v3/hooks

Response 200 — hooks[] item

Field Type Description
id string Hook subscription id
event string Event key
targetUrl string Subscriber HTTPS URL
status string e.g. active
apiKeyId string Key used to create the subscription
createdTime string ISO 8601 timestamp

Subscribe

POST /api/v3/hooks

Request body

Field Required Description
event Yes Supported event name (case-insensitive)
targetUrl Yes Absolute https:// URL to receive POST payloads

Response 201 — Same shape as a single hook object above.

Multiple subscriptions for the same event are supported (each subscriber receives independent deliveries).

Example

{
  "event": "inbound_message",
  "targetUrl": "https://hooks.zapier.com/hooks/catch/123456/abcdef/"
}

Unsubscribe

DELETE /api/v3/hooks/{hookId}

Response 200

{
  "deleted": true,
  "hookId": "hook_uuid_here"
}

Errors: 404 hook_not_found when the id does not belong to the authenticated user.


Webhook Samples

Read-only endpoints that return recent webhook-shaped payloads for integration testing. The JSON structure matches live webhook POST bodies.

Inbound SMS Samples

GET /api/v3/zapier-hook-samples/inbound-message-sms

Outbound Delivery Status Samples

GET /api/v3/zapier-hook-samples/outbound-message-sms-status

Query parameters (both endpoints)

Param Required Default Max
limit No 25 50

Response 200

{
  "events": [ /* webhook envelope objects, newest first */ ]
}

Returns { "events": [] } when the account has no recent matching history.


Webhook Events

When a subscribed event occurs, HelloSend POSTs a JSON envelope to the registered targetUrl with Content-Type: application/json.

Supported Events

Event Key When It Fires
inbound_message HelloSend receives an inbound SMS on the account
outbound_message_status An outbound SMS reaches a terminal delivery status (delivered or failed)

Envelope Shape

Field Type Description
id string Unique event id (use for deduplication)
event string Event key
occurredAt string ISO 8601 UTC timestamp
data object Event-specific payload

inbound_message — data object

Field Type Description
messageId string Provider message id
fromNumber string Sender (external party)
toNumber string Your HelloSend number
body string Message text
receivedAt integer Unix ms when received
contact object Matched contact, if any (see below)

Example payload

{
  "id": "evt_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "event": "inbound_message",
  "occurredAt": "2026-04-20T12:34:56.789Z",
  "data": {
    "messageId": "msg_inbound_123",
    "fromNumber": "+14155551234",
    "toNumber": "+14155559876",
    "body": "Hey — reply when you can.",
    "receivedAt": 1745148896789,
    "contact": {
      "phone": "+14155551234",
      "firstName": "Ada",
      "lastName": "Lovelace",
      "email": "ada@example.com",
      "remoteContactId": "crm_contact_456"
    }
  }
}

outbound_message_status — data object

Field Type Description
messageId string Outbound message id
fromNumber string Your HelloSend number
toNumber string Recipient
deliveryStatus string delivered or failed
loggedAt integer Unix ms inbox log time
errorCode string Provider error code (when failed)
errorDetail string Human-readable failure detail (when failed)
contact object Matched contact, if any

Example payload

{
  "id": "SMxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_delivered",
  "event": "outbound_message_status",
  "occurredAt": "2026-04-20T12:35:00.000Z",
  "data": {
    "messageId": "SMxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "fromNumber": "+14155559876",
    "toNumber": "+14155551234",
    "deliveryStatus": "delivered",
    "loggedAt": 1745152500000,
    "errorCode": "",
    "errorDetail": "",
    "contact": {
      "phone": "+14155551234",
      "firstName": "Ada",
      "lastName": "Lovelace",
      "email": "ada@example.com",
      "remoteContactId": "crm_contact_456"
    }
  }
}

Contact Object

Included in both event payloads when a matching contact is found.

Field Type Description
phone string Contact phone
firstName string
lastName string
email string
remoteContactId string CRM record id

Zapier Integration Mapping

Zapier Step API Calls
Connect Account (auth test) GET /api/v3/auth/verify
Trigger: New Inbound SMS Subscribe inbound_message; poll GET /api/v3/zapier-hook-samples/inbound-message-sms
Trigger: Outbound SMS Delivery Status Subscribe outbound_message_status; poll GET /api/v3/zapier-hook-samples/outbound-message-sms-status
Action: Send Message POST /api/v3/messages (+ Idempotency-Key); dropdowns via GET /api/v3/numbers, GET /api/v3/templates, GET /api/v3/templates/{id}
Search: Find Contact by Phone GET /api/v3/contacts?phone=

Getting an API Key

API keys are created in the HelloSend web app — not via the API.

  1. Sign in at https://www.hellosend.com
  2. Go to Settings → API Keys
  3. Click Generate key, name it, and copy the secret immediately (shown once)
  4. Paste the key into your integration

Revoke unused keys from the same Settings page.


Endpoint Index

Method Path Description
GET /api/v3/auth/verify Verify API key; get connection metadata
GET /api/v3/numbers List sendable phone numbers
GET /api/v3/templates List message templates
GET /api/v3/templates/{id} Get template with placeholders
POST /api/v3/messages Send outbound message
GET /api/v3/contacts?phone= Find contacts by phone number
GET /api/v3/hooks List webhook subscriptions
POST /api/v3/hooks Subscribe to a webhook event
DELETE /api/v3/hooks/{hookId} Unsubscribe from a webhook
GET /api/v3/zapier-hook-samples/inbound-message-sms Recent inbound SMS webhook samples
GET /api/v3/zapier-hook-samples/outbound-message-sms-status Recent outbound status webhook samples