Utilities
Send one-way transactional messages — order confirmations, shipping updates, appointment reminders — from your backend. Utilities run on your own connections: WhatsApp goes out over your own WhatsApp Business Account, and SMS over your own BYO SMS provider.
Managed Vodafone integrations differ
BYO SMS here describes an integration you build and own. If Akedly operates a managed Vodafone integration for your account, several of the capabilities described below are fixed by Akedly and are not yours to set — see Managed Vodafone.
Server-to-server only
Utilities are a machine-to-machine API. Sends are triggered from your code — your backend picks a pipeline and template, fills the variables, and calls /utilities/send. There is no captcha or end-user ceremony; security comes from your API key and per-pipeline request signing.
Get set up
Utilities is configured once in the dashboard, then driven by a single API call. Five one-time steps — connect at least one channel — then you send.
1. Connect your WhatsApp Business Account
Utility WhatsApp messages go out from your own WABA — never a shared Akedly number — so recipients see your brand. Connecting uses Meta's Embedded Signup and takes about two minutes; the full guide is under Channels.
Skip this only if you will send over SMS exclusively.
View in dashboardChannels → Setup → WhatsApp SetupConnect your WhatsApp Business Account.
2. Connect your own SMS provider (BYO SMS)
Utility SMS dispatches exclusively through your own SMS provider. If you are building the integration yourself, add and test one under Channels → Setup → BYO SMS Setup, then set the per-country routing that decides which destinations SMS can reach — per-country chains, or an ALL catch-all. If Akedly operates a managed Vodafone integration for you, the request chain is built for you and its coverage is fixed to Egypt — there is no routing for you to set, but three setup steps are still yours — its credentials, its approved sender name, and acknowledging that Vodafone has whitelisted Akedly's outbound IPs — and it must then pass its activation test before it sends. See BYO SMS for how an integration is built, tested and routed.
Skip this only if you will send over WhatsApp exclusively. Without an active, tested BYO integration, SMS cannot be enabled on a template or a pipeline and no number is reachable over SMS.
View in dashboardChannels → Setup → BYO SMS SetupConnect your SMS provider and set its per-country routing. Not on a managed Vodafone integration — its provider and Egypt-only routing are fixed and cannot be edited.
3. Create a utility pipeline
A pipeline is your sending policy — channels, allowed destination countries, rate limits, and a spend cap. Create one under Utilities → Pipelines. Its pipelineID is what every API call references. Utility pipelines are separate from OTP pipelines.
Once created, configure the pipeline's Basic details, Request signing, Sending config and Webhooks sections.
Sending config is where channels, their order, the WhatsApp→SMS fallback, the Allowed countries (WhatsApp) list and your daily spend cap live. SMS stays disabled until BYO SMS routing resolves on for that pipeline — a connected and tested integration is necessary but not sufficient. Enabling SMS without it returns UTILITY_SMS_REQUIRES_BYO. See Enable on pipelines & cloning.
Webhooks is where you set the callback URL and reveal the whsec_ signing secret.
4. Create and approve a template
Write your message once as a template with {{variable}} placeholders, then submit it. Every template needs Akedly approval; WhatsApp additionally needs Meta approval. A template you can send with right now is a sendable template — see Templates and dual approval.
5. Reveal your request-signing secret
Reveal the request-signing secret once from the pipeline's settings and store it like a password. Your backend uses it to sign every API call; see Request Signing.
6. Send your first message
With a sendable template, send a single signed POST to /utilities/send.
Utilities vs OTP
A utility message is one-way: Akedly sends it and reports as much of the outcome as the channel gives us — WhatsApp reports the whole post-send stream (sent, delivered, read and failed — a failure carries a reason when Meta supplies one, and null when it does not); a BYO SMS send is final once your provider accepts it. There is no verify step.
| Aspect | Utilities | OTP |
|---|---|---|
| Purpose | Notify — confirmations, updates, reminders | Verify — the user proves possession of the number |
| Flow | One call: send | Create, send, verify |
| Channels | WhatsApp (your own WABA), SMS (your own BYO provider) | WhatsApp, Telegram, SMS, Email with fallback |
| Who can receive | Any valid number, subject to channel and suppression checks | Any number the user submits |
| Content | Approved templates (free text on SMS) | OTP codes |
| Billing | Per message; WhatsApp billed on delivery | Per message, or PPSA on V2.0 |
Utility pipelines and OTP pipelines are separate. A utility send must reference a utility pipeline — calls against an OTP pipeline are rejected with NOT_A_UTILITY_PIPELINE.
How a send works
Every send is a single POST to https://api.akedly.io/api/v1/utilities/send, authenticated by your API key and pipeline ID in the body and signed with your pipeline's request-signing secret. Akedly then:
- Verifies the request signature and applies your pipeline's rate limits.
- Resolves the channel — the first feasible channel in the pipeline's channel order (WhatsApp first by default): WhatsApp over your own WABA when the template and destination allow it, SMS over your own BYO integration when its routing resolves for the destination.
- Sends, records the message, and bills it. WhatsApp delivery and billing settle asynchronously when Meta reports the delivery outcome.
The response carries a transactionID you can track in the dashboard's Send History.
Opt-out and suppression
Every utility WhatsApp template automatically carries a "Stop receiving these" quick-reply button — you do not add it, and you cannot remove it.
When a recipient taps it, that number is suppressed account-wide: across every pipeline and both channels, not just the pipeline that sent the message.
Opt-out blocks both channels
Suppression is checked independently of channel configuration, so a suppressed number stays unreachable on both WhatsApp and SMS. The only thing that lifts a suppression is an explicit opt-in (POST /utilities/suppressions/opt-in, or the suppressions view in the dashboard — it needs the utilities:update permission).
Reversing an opt-out is deliberately a separate, audited action: every opt-out and opt-in is appended to an event log. Only opt a recipient back in when you have genuine renewed consent from them — never to work around a suppression.
Channels
Both channels run on connections you own. Setting them up is documented under Channels — your WhatsApp Business Account and your own SMS provider. This section is what a utility send needs from each of them.
WhatsApp — primary
Sent over your own WhatsApp Business Account, nationally and internationally. A WhatsApp send requires:
- WhatsApp enabled on the pipeline
- A Meta-approved, WhatsApp-usable template
- An active connected WABA
- The destination country in the pipeline's allowed-countries list
Delivery is confirmed asynchronously by Meta, and billing settles on the delivery outcome.
SMS — your own provider
Utility SMS dispatches exclusively through your own BYO SMS integration (Channels → Setup → BYO SMS Setup); the send response reports provider: "own-sms". An SMS send requires:
- SMS enabled on the pipeline and the template
- An active, tested BYO SMS integration
- The destination covered by your BYO country routing — a per-country chain, or an
ALLcatch-all
For an integration you build yourself there is no Egypt restriction and no Akedly-operated SMS route: coverage is whatever your own routing covers. (A managed Vodafone integration is fixed to Egypt.) This is also the only channel that accepts free-text sends (a text body instead of a template).
Note the two channels gate geography differently. WhatsApp is checked against the pipeline's allowed-countries list (default-deny); SMS is not — its reach is decided purely by your BYO country routing. Adding a country to the allowlist therefore does nothing for SMS, and a country absent from it can still be reachable over SMS.
The two routing failures you will hit most return 409: no usable BYO integration at all gives UTILITY_SMS_REQUIRES_BYO, while an integration that exists but has no chain for the destination gives UTILITY_SMS_COUNTRY_NOT_ROUTED. The second is the one to expect when you expand into a new market — on an integration you built, add a country chain or an ALL catch-all to clear it; a managed Vodafone integration is fixed to Egypt and cannot be widened. These are not the only ways an SMS send can be refused: SMS must also be enabled on both the pipeline and the template, and a managed provider that is selected but not ready returns UTILITY_SMS_PROVIDER_NOT_READY rather than silently falling through to another provider. The channel errors table lists the codes you are most likely to hit.
The channel is resolved before sending, and by default a send goes out on exactly one channel with no cross-channel retry. A pipeline can opt in to a WhatsApp → SMS fallback (utilityConfig.smsFallback, off by default): with it on, an eligible failed WhatsApp delivery is re-rendered as SMS and dispatched over your BYO chain. Eligibility is narrower than “any failure”: the first error Meta reports on the failed delivery must be one of the two fallback codes — 131026 (the recipient cannot receive it) or 131042 (a business eligibility or payment-method problem) — and a fallback code in a later position is not checked. Nothing else falls back: a template that is not approved or unavailable (131045), a spam rate limit (131048) and a WABA on hold (131057) are all terminal. The send must also be a live (non-test) one to a recipient you have not suppressed, and your BYO routing must resolve for the destination — a country chain that covers it is necessary but not sufficient, and a managed Vodafone integration whose readiness no longer holds refuses to route even inside Egypt; and even then the fallback is abandoned if the SMS fee cannot be reserved against your utility budget, if the template fails to re-render as SMS, or if your provider does not accept the dispatch. It is billed as an SMS only once your provider has accepted it. When both channels are feasible up front, the pipeline's channel order decides; the default is WhatsApp first.
Each channel needs its own connection
Neither channel works out of the box. WhatsApp needs your WhatsApp Business Account; SMS needs your own BYO SMS integration — enabling SMS on a template or pipeline hard-requires an active one. Without a BYO integration, no number is reachable over SMS, not even an Egyptian one. An approved template and a configured pipeline are not enough on their own.
Templates and dual approval
Templates are the message content: a body with {{variable}} placeholders your send call fills in. A template can also carry a text header (up to 60 characters, at most one variable), a footer (up to 60 characters, no variables), and buttons — up to two URL buttons, one phone-number button, and quick replies, of which up to three may carry a stable action label. Build these in the template editor.
What a template is made of
The editor walks five sections, and shows a live WhatsApp preview as you type:
- Basics — the template name and its language.
- Message — an optional header (bold title, ≤60 characters, may carry one variable), the body (required, where your
{{1}},{{2}}placeholders go), and an optional footer (≤60 characters, no variables). - Variables — positional placeholders. The send call fills them in order.
- Buttons — up to two URL buttons, one phone-number button, and quick replies.
- Channels — whether this template is usable on WhatsApp, SMS, or both.
The opt-out button is added for you
Every WhatsApp template carries a "Stop receiving these" quick reply automatically — visible in the preview above. You do not add it, and you cannot remove it. Tapping it suppresses that recipient account-wide; see Opt-out and suppression.
If no WhatsApp Business Account is connected, the editor says so at the top: the template can still be written and saved, but WhatsApp sends are blocked until you connect one.
The editor checks your template as you type
A counter in the header shows how many must-fix problems the template currently has. It is a pre-flight check that runs against the same rules Meta applies, so a template that would be rejected is caught before you spend a review cycle on it. Findings come in two kinds:
- Name
Must-fix- Type
- blocking
- Description
A mechanical rule Meta enforces — a header over 60 characters, a footer containing a variable, too many buttons, a variable with no example value, an unsupported language, a duplicate template name. These are shown against the section that owns them.
- Name
Advisory- Type
- report only
- Description
Judgement calls that live in the report drawer rather than blocking submit — an unused variable, very dense variable use, wording that reads as prohibited or sensitive, and the category prediction below.
The most useful advisory is "this will probably be re-classed as Marketing" — the linter reads your wording and warns before Meta re-prices the template. See Keeping the template classed as Utility.
The linter advises; the backend decides
Submission is never blocked by the linter being unavailable — if the check cannot run, submit stays enabled and the backend remains the real gate. Treat a clean report as "nothing obvious is wrong", not as a guarantee of Meta approval.
Test it before you go live
The editor has a Test & go live panel. Save the template to give it an ID, then send a real message to your own number — or to another valid number — before submitting for review.
A test is a real message, and SMS tests are billed
A test is a real message on a real channel, and the phone number must be valid. It is not a sandbox. Billing differs by channel: an SMS test bills immediately, exactly like a normal send. A WhatsApp test is flagged as a test send and its deferred billing is skipped when Meta reports delivery, so it does not appear on your bill.
Keeping the template classed as Utility
Meta categorises every template. Utility templates are cheaper than Marketing ones and are the only category appropriate for transactional messages — but the category is inferred from your wording, and a single promotional-sounding line flips the whole template.
What gets a template re-classed as Marketing
These are the patterns that have caused re-classification in practice:
- Avoid any promotional tone — even subtle words like "great", "best", "exciting".
- Keep it strictly transactional — trigger-based only: a confirmation, an update, a reminder.
- No optional engagement — drop CTAs like "check this out" or "explore".
- Tie the message to a user action — something they did, not proactive outreach.
- Avoid mixed intent — one marketing-like line is enough to flip the category.
A re-classed template is not rejected, it just costs more and stops being appropriate for utility sends. Rewrite and resubmit rather than arguing the category.
Every template carries two independent approval tracks:
- Name
Akedly status- Type
- required for any send
- Description
Every template is reviewed by Akedly before it can be sent — on any channel, no exceptions.
- Name
Meta status- Type
- required for WhatsApp
- Description
WhatsApp-usable templates are additionally submitted to Meta for approval. A template that is Akedly-approved but not Meta-approved can still send on SMS.
A sendable template is Akedly-approved and, for WhatsApp sends, Meta-approved. Sending with a template that lacks Akedly approval returns TEMPLATE_NOT_APPROVED; a template without Meta approval simply cannot resolve to WhatsApp.
A brand-new template can't send on WhatsApp until Meta approves it
Akedly approval clears a template for SMS right away, but WhatsApp additionally needs Meta's review, which is asynchronous. Until then, a template resolves to SMS only (or fails, if WhatsApp is the only feasible path for that recipient).
Billing
Utilities are billed per message sent — there is no per-verification pricing.
You are not charged for WhatsApp messages that never deliver
WhatsApp billing is deferred: a send is accepted immediately and charged only once Meta confirms delivery, so a message that never delivers is never billed. The reverse does not follow — delivery is what triggers billing, not proof it succeeded: if the deferred charge then fails terminally the transaction is marked Failed and stays unbilled. SMS, by contrast, bills at send time, at a flat fee per message.
- WhatsApp — billing is deferred: the send is accepted immediately but billed only when Meta reports the delivery outcome. Messages that never deliver are not billed.
- SMS — billed at send time as a flat BYO fee per message, not per segment. The rate resolves most-specific-first: a per-integration override, then your per-account rate, then the global default. Akedly sets every override level. The send response still reports
segmentsandencoding, but they are informational — a multi-segment message costs the same as a single-segment one. They describe how the text was encoded: GSM-7 fits 160 characters per segment (153 once a message spans segments), while Arabic or emoji content switches to UCS-2 at 70 per segment (67 multi-segment). That is why an Arabic message splits at roughly half the length of an English one.
Each pipeline can set a daily spend cap (a BYO-SMS message priced at exactly 0 is exempt from it; WhatsApp is floored at 0.25 EGP and cannot be), and it gates both channels in two stages: a send is rejected with SPEND_CAP_EXCEEDED once the day's spend has already reached the cap, and again — after the message is priced — if reserving its own fee would carry the day past it. WhatsApp is not exempt and is not a special case: it prices the message before dispatch and reserves that exact amount against the cap, even though the message is only billed when Meta reports the delivery outcome.
