Who can manage keys
Owners and Admins manage keys in Settings → API keys. Other roles do not see that tab. See Your account for the roles. A key cannot create, list or revoke keys. Managing keys always needs a signed-in Owner or Admin.Create a key
1
Open Settings → API keys
Start a new key from the API keys tab.
2
Name it after the integration
Up to 60 characters, for example
CRM sync. A clear name tells you which
integration stops working when you revoke the key.3
Choose the scopes
Tick only what the integration needs. See Scopes below.
4
Choose an expiry
30, 90 or 365 days, or never. Prefer an expiry: a key that expires limits the
damage if it leaks unnoticed. An expired key is refused from the moment it
expires.
5
Copy the key and store it
The key is shown once, when you create it. Copy it into your secret manager
or your platform’s secret store straight away. Heullo stores only a hashed
form of the key, so it cannot show it to you again. If you lose a key, create
a new one and revoke the old one.
hk_live_AbCd…wxyz, its scopes, who created it, when it was last used, when it
expires and its status: active, expired or revoked. Revoked and expired keys stay
in the list as a record.
IP allowlists
When IP allowlists are available for your organization, the create form shows an extra field for them. Enter one public IPv4 or IPv6 address or CIDR range per line, up to 20 entries, for example203.0.113.7 or 198.51.100.0/24. A key with an
allowlist answers 403 with API_KEY_IP_NOT_ALLOWED to requests from any other
address. A key without an allowlist accepts requests from any address.
Key format
Production keys start withhk_live_, followed by 40 letters and digits:
hk_test_. A key works only in
the environment that created it, and is refused with 401 in the other. See
Base URLs.
The fixed prefix makes a key easy to match with a secret-scanning rule in your own
repositories and logs.
Call the API with a key
Send the key as a bearer token in theAuthorization header of every request:
X-Organization-Id header is needed, because the key identifies its
organization. If you send that header anyway, it must name the key’s organization,
or the request is refused with 403 and ORGANIZATION_MISMATCH.
The key is accepted only in the Authorization header, never in a query string or
form field.
The examples below call production, https://api.heullo.com, and read the key
from an environment variable on your server, so it never appears in your source
code. Responses use the standard response envelope.
Response examples are abridged; each operation’s page lists every field.
Send a single message
Needs thesms:send scope. Operation reference.
status is SENT when the mobile network accepted the message, FAILED when it
was refused (the credits are returned), and SCHEDULED when you set a future
scheduledFor. Keep id to read the delivery status later. A balance below the
cost of the message answers 402; see Errors.
Send a bulk message
Needs thesms:send scope. Operation reference.
One bulk request sends the same message to many recipients. Prefer it to a loop of
single sends: it is one request against your rate limit, and it
creates one campaign in SMS Management.
402. The messages are then sent in the
background. recipientCount and uniqueRecipientsCount are the number of
recipients after duplicates were removed, originalRecipientsCount is the number
you sent, and duplicatesRemoved the difference. Keep managementId to follow
the campaign.
Read a message’s delivery status
Needs thesms:read scope. Operation reference.
status; see
Statuses for what each value means. An identifier that does
not belong to your organization answers 404.
For the recipients of a bulk campaign, list the campaign’s messages with the
managementId from the bulk response. Paging starts at 1, and size is at most 500:
List inbound messages
Needs theinbound:read scope. Operation reference.
inbound:read can read messages but cannot mark them as read.
Create a contact
Needs thecontacts:manage scope. Operation reference.
phoneNumber is required. name and email are stored as the contact’s name and
email. Any other field, such as company above, is stored as a custom field and
returned at the top level of the contact.
409.
Read the balance
Needs thebalance:read scope. Operation reference.
Scopes
A key can call only the operations of the scopes it was given.
The operations each scope allows:
These operations show the API key scheme and the scope they need on their page in
the API reference.
Every other operation refuses an API key with
403 and API_KEY_FORBIDDEN,
whatever scopes the key has. That includes members and invitations, billing other
than reading the balance, settings, sender IDs, keywords, Email-to-SMS, reports,
exports, CSV imports, campaign controls such as pause and cancel, and API key
management itself. Use the web application, signed in as a member with the right
role, for those.
Idempotency
Network failures leave a client unsure whether a send went through. To retry a send safely, give it anIdempotency-Key header. It is accepted on
POST /api/v1/sms/single and POST /api/v1/sms/bulk with an API key.
“The same request body” means the same bytes. Store the body you sent and retry
with it, rather than serialising the request again.
Retry advice:
- Retry timeouts, connection errors,
5xxresponses and409 IDEMPOTENCY_IN_PROGRESSwith the same Idempotency-Key and body. Wait forRetry-Afterwhere it is given, then back off exponentially. - Do not retry
400,402,403or422unchanged. Correct the request first. A corrected request is a new send and needs a new Idempotency-Key. - If retries keep answering
409 IDEMPOTENCY_IN_PROGRESSfor several minutes, check SMS Management for the message before you send it under a new Idempotency-Key. - A request with an Idempotency-Key can be at most 1 MiB; a larger one answers
413.
Rate limits
Each key has its own limit, by default 120 requests per minute. The allowance refills evenly through the minute, so a key can make a burst of up to 120 requests and then about two per second. Over the limit, the API answers429 with RATE_LIMITED and a Retry-After
header giving the seconds to wait. Wait at least that long, then retry with
exponential backoff and some random jitter, so several workers do not retry at the
same moment. Retries and idempotent replays count toward the limit like any other
request.
To stay under the limit, send to many recipients with one bulk request rather than
many single sends, and give each integration its own key. Before running sustained
high-volume traffic, contact your Primetel account manager.
Errors
Errors caused by the key itself are answered before the request reaches the operation, with this body:status and code. The message text can change.
Errors from the operation itself, such as a missing field (
400), too few credits
(402), a record that is not yours (404) or a duplicate contact (409), use the
standard envelope with success: false and no code. See
Errors.
Keep keys secure
- One key per integration. You can then revoke one integration’s access without touching the others, and the last-used time tells you which integration is active.
- Give each key the fewest scopes it needs. A key that only reads the balance cannot send messages if it leaks.
- Rotate keys. Create the new key, deploy it to the integration, confirm the integration works with it, then revoke the old key. Both keys work during the change, so nothing breaks.
- Revoke a leaked key at once. Revoking takes effect on the next request. Then create a replacement, and check SMS Management and the credit balance for use you do not recognise.
- Keep keys on your servers. Never put a key in browser JavaScript, a mobile app or any other code that runs on your customers’ devices, where anyone can extract it. Call Heullo from your own backend instead.
- Keep keys out of source code and logs. Load the key from a secret store or an
environment variable, and do not log the
Authorizationheader.
Messages sent with a key
Messages sent with an API key appear in SMS Management with theAPI channel, like
any other message from your organization. A single send is listed as
“API SMS to” followed by the recipient, and a bulk send under the name you gave
it. Filter by the API channel in SMS Management or in the Outbound report to see
your integrations’ traffic, and the credits it used, separately from messages your
team sent.
