Skip to content
Akedly
WhatsAppNEW

OTP templates

Send WhatsApp OTPs in wording you pick from Meta's authentication library, from your own WhatsApp Business Account. Add a template once in the dashboard, wait for Meta to approve it, then pass its id — or make it a pipeline's default. With neither, nothing changes: the Built-in default keeps sending.


How it works

  1. Pick an entry in Browse library and choose English, Arabic, or both.
  2. Add it. Akedly creates it on your WABA and Meta reviews each language, usually within minutes.
  3. Wait for Approved in the OTP language. Akedly emails you when Meta decides.
  4. Use it: pass template: { id } on V1.2 or V2, or make it a pipeline's default so requests need no change.

A template changes only the wording of a WhatsApp OTP sent from your own number. It does not choose the channel: routing is unchanged, and SMS, Telegram and email keep their usual wording.

You choose

  • The library entry and its languages.
  • The security sentence, when the entry does not already include one.
  • Stored defaults for each non-fixed variable, per language.
  • Per-request variable values.
  • A default template per pipeline.

Fixed

  • Meta's wording and variable slots.
  • The Copy code button and the three-minute expiry footer.
  • The language: otpLanguage when supplied, otherwise the pipeline's OTP Language.
  • 15 characters per variable value.

Add a template

  1. Open OTP Templates under Channels setup → Setup and switch to Browse library. Use Preview: EN / AR to read each language.
  2. Select Add to my templates on an entry.
  3. Choose the languages. Entries marked English only have no Arabic version.
  4. Optionally store a default for each variable, per language. The counter shows the 15-character limit; fixed values such as validity are filled for you.
  5. Select Add to my templates. Each language starts In review.

Stored defaults decide how short your requests can be:

  • A variable with a stored default can be left out of a request; a request value overrides it.
  • A variable without one must be sent on every request, and the template cannot be a pipeline default for that language.
  • Edit defaults changes future sends without another Meta review. Adding a language starts one.

Two limits apply to adding and editing:

  • Each WhatsApp Business Account holds up to 20 templates. Removed templates don't count. At 20, adding another is refused with TEMPLATE_LIMIT_REACHED; remove one first.
  • You can't hold two identical templates: same library entry, languages, security recommendation and stored defaults. Adding one, or an edit that would make two identical, is refused with TEMPLATE_DUPLICATE, which names the template you already have. If an earlier add failed at Meta, select Retry Meta setup on that template instead of adding it again. Templates that differ only in their stored defaults are allowed.

Viewing needs whatsapp:read. Adding, editing, removing and setting a pipeline default need whatsapp:update; without it the page shows View only.

Track approval

Each card in My templates shows one badge per language, the stored defaults, the Template id to send, and a ready-made request body. While anything is in review the page refreshes the stored status every 30 seconds, and Akedly emails you when a language is approved or rejected.

BadgeMeaningWhat to do
In reviewMeta is reviewing this language.Wait. Requests in this language are refused with TEMPLATE_NOT_APPROVED.
ApprovedReady in this language.Copy the Template id.
RejectedMeta refused this language. The rejection email includes Meta's reason when Meta gives one.The wording can't be edited: remove the template and add it again.
Missing on MetaAkedly saved the template but Meta did not create this language.Select Retry Meta setup. If Meta refuses the name, remove and add it again.
Re-add after WhatsApp changeThe template belongs to a WABA you replaced. It overrides every language badge.Remove it and add it again (see Remove and re-add).

Approval is per language: an approved English variant does not make the template usable for an OTP requested in Arabic. The Meta name (akedly_auth_…) is for reference only; requests use the Template id. The read-only Built-in Default card at the top needs no id.

Send with a template

  • Name
    template
    Type
    object
    Description

    { id, variables } only. Any other key, including language, is refused with TEMPLATE_VARIABLE_INVALID. Use top-level otpLanguage to choose the OTP language. template: null means the same as leaving it out.

  • Name
    template.id
    Type
    string
    Description

    The Template id from My templates.

  • Name
    template.variables
    Type
    object
    Description

    Curated variable names mapped to values. Required only for variables with no stored default in the OTP language.

Choose the template on your server. Never forward a template object from a browser or app. On V2 the request signature does not cover template.

Variables

  • Values are non-empty strings of 15 characters or fewer. Arabic letters count one each.
  • No line breaks, tabs, or four spaces in a row.
  • Use only the entry's curated names (Library reference).
  • Leave out fixed variables. If you send one, it must equal its fixed value: validity in verify_code is 3 minutes or ٣ دقائق.

Commercial International Bank (29 characters) and 1,250,000.00 EGP (16) are both too long; use a shorter value.

Choose the OTP language

Top-level otpLanguage picks the English or Arabic variant for one request. When absent or null, the pipeline's OTP Language (Basic Details) picks it. template.language is refused; use otpLanguage.

Set a pipeline default

When a transaction or attempt is created, Akedly uses the first of:

  1. The template in the request.
  2. The pipeline's default OTP template, with its stored defaults.
  3. The Built-in default.

A custom template, explicit or pipeline default, must be Approved in the OTP language. Otherwise creation returns HTTP 400 — TEMPLATE_NOT_APPROVED, or TEMPLATE_REJECTED if that language was rejected — never a fallback. See template errors.

To change a default's variables for one request, send that template explicitly.

In Authentication → Pipelines, open the pipeline, expand OTP Template, choose a template under Default template, and select Save changes. Only templates Approved in the pipeline's OTP Language, with a stored default for every non-fixed variable, can be chosen. Others show why, such as In review for English or Missing defaults: purpose. If the section shows Couldn't load the OTP template library, select Retry; custom templates stay unavailable until it loads.

A custom default needs WhatsApp among the pipeline's verification methods; otherwise the save is refused with TEMPLATE_PIPELINE_REQUIRES_WHATSAPP. Built-in default (akedly_otp_auth) can always be saved.

Add a missing language from a pipeline

If you switch a pipeline's OTP Language to a language its default template doesn't have yet, the OTP Template section says so and offers Add Arabic (or Add English).

  1. Select Add Arabic. The template's Edit defaults dialog opens with Add Arabic already checked. Your pipeline edits are kept but not saved.
  2. Fill in the Arabic defaults and select Save defaults. The dashboard confirms Arabic sent to Meta for review.
  3. When Meta approves Arabic (usually within minutes; Akedly emails you), select Save changes on the pipeline. Until then the section can't be saved with this template; choose the Built-in default if you need to save now.

The action appears only after the template library loads, when the target language is an available variant for that entry but has never been added, you have whatsapp:update, and the template belongs to your current WABA. A language that is In review, Rejected or Missing on Meta is fixed from OTP Templates instead.

When a template cannot be used

Refused before anything is sent

StatusCodeCauseWhat to do
400TEMPLATE_UNKNOWNThe id is malformed, not found, or does not belong to your account.Copy the Template id from My templates.
400TEMPLATE_ARCHIVEDThe template was removed.Add it again; the new copy has a new id.
400TEMPLATE_WABA_REQUIREDYour own WABA is not active, or its token cannot be read.Connect or repair the WABA.
400TEMPLATE_WABA_CHANGEDThe template was created on a previous WABA.Remove it and add it again.
400TEMPLATE_NOT_APPROVEDNo approved variant exists for the OTP language, or Meta is still reviewing it.Wait for Approved. If it is Missing on Meta, retry Meta setup or remove and re-add the template, then add the OTP language if needed.
400TEMPLATE_REJECTEDMeta rejected the variant for the OTP language.Remove it and add it again.
400TEMPLATE_VARIABLE_MISSINGA required variable has no request value and no stored default.Pass the variable or store a default.
400TEMPLATE_VARIABLE_INVALIDThe variable name or value is invalid, a fixed value changed, or the object contains language or another unsupported key.Read details and correct the request.

Fallback at send time

This is rare, because approval is checked at creation. If the approved variant becomes unusable or Meta refuses it during sending, Akedly sends the Built-in default once, in the same language, on your WABA. The fallback is logged and Akedly's operations team is alerted. The API response you already received still shows the original data.template. If that send also fails, normal WhatsApp recovery continues with the Built-in default, which can use Akedly's shared number.

Shared senders always send the Built-in default

Custom wording is only sent from your own WABA's phone number. For an account with an active own WABA, if routing sends the OTP through Akedly's shared number or a send falls back to it, the selection is still checked and echoed but the message uses the Built-in default. Without an active own WABA, selecting a custom template is refused with TEMPLATE_WABA_REQUIRED (see above). On a legacy manually assigned shared phone, the Built-in default is also sent in English, whatever the OTP language.

Remove and re-add

Remove archives the template in Akedly at once: its Template id stops working (TEMPLATE_ARCHIVED), and every pipeline using it as a default goes back to the Built-in default. Akedly attempts deletion on Meta only when the template still belongs to your active WABA. If it belongs to a replaced WABA, Akedly archives it locally without calling Meta. If Meta refuses an attempted deletion, delete it in WhatsApp Business Manager. Meta blocks the name for about 30 days, so adding the same entry again creates a new Meta name and a new Template id — update your integration.

After you change WhatsApp Business Account

If you reconnect a different WABA through Embedded Signup, every template from the old one shows Re-add after WhatsApp change, and requests or pipeline defaults that use it are refused with TEMPLATE_WABA_CHANGED. Remove it and add it again. If you disconnect without reconnecting, they are refused with TEMPLATE_WABA_REQUIRED, and the pipeline section shows Custom OTP templates need your own WhatsApp Business Account. with a Use Built-in default button. A transaction created before the change sends the Built-in default in its selected language.

Library reference

Every entry below can be added from Browse library. The code slot is where Meta places the OTP; you never pass it. Types are Meta's descriptions, not format checks.

EntryCode slotVariable name and typeLanguages
delivery_code_11Noneen, ar
delivery_code_26customerName TEXT, orderInfo TEXT, estimatedDeliveryDate DATE, deliveryStartTime DATE, deliveryEndTime DATEen, ar
delivery_code_32arrivalDate DATEen, ar
delivery_code_41Noneen, ar
delivery_code_53itemCount NUMBER, orderId TEXTen, ar
delivery_code_63orderId TEXT, deliveryDate DATEen, ar
in_person_banking_user_verification1Noneen, ar
login_code1Noneen
verify_account4action TEXT, accountName TEXT, linkedService TEXT, securityContact TEXTen
verify_account_24action TEXT, accountName TEXT, linkedService TEXTen, ar
verify_code1purpose TEXT, validity TEXT, supportPhone PHONE_NUMBERen, ar
verify_code_11Noneen, ar
verify_otp_usecase1purpose TEXTen, ar
verify_password_recovery1Noneen, ar
verify_transaction_11Noneen, ar
verify_transaction_21amount AMOUNTen, ar
verify_transaction_31amount AMOUNT, cardNumber CARD_NUMBERen, ar
verify_transaction_41amount AMOUNT, accountNumber NUMBERen, ar
verify_transfer_11amount AMOUNTen, ar

validity in verify_code is fixed. verify_otp_usecase already includes its security sentence, so the security option adds nothing to it.

Localized parts

LanguageSecurity sentenceExpiry footerButton
enFor your security, do not share this code.Expires in 3 minutes.Copy code
arلأسباب تتعلق بأمانك، يرجى عدم مشاركة هذا الرمز.تنتهي صلاحيتها خلال ‏٣‏ دقائق.نسخ الرمز

For verify_otp_usecase, the Arabic sentence already in the body is للحفاظ على أمانك، لا تشارك هذا الرمز.