# What ONPAD is Source: https://onpad.in/docs/what-is-onpad ONPAD is a WhatsApp Business platform for businesses in India. It runs on the official **WhatsApp Business Cloud API** from Meta, so every message goes out from your own verified WhatsApp Business number — not from a shared number, and not from an unofficial connection that can be shut off without warning. ## What you can do with it **Shared team inbox.** One WhatsApp number, answered by your whole team. Conversations can be assigned to a person, marked read, closed and reopened, so two people never reply to the same customer. **Contacts.** Store your customers with name, phone, email, company and tags. Import them in bulk from a CSV file. Every contact shows its own conversation history. **Templates.** WhatsApp requires pre-approved messages for anything you send first. Templates are where you write them, submit them to Meta for approval, and see whether they were approved or rejected. **Campaigns.** Send an approved template to a list of contacts, schedule it for later, and watch delivery as it happens — sent, delivered, read, failed, with the reason for each failure. **Automations.** Workflows that run on a trigger without anyone watching, so a reply or a tag can start a sequence on its own. **AI Agent.** An assistant trained on your own business information that can answer customers for you. **Analytics.** Message volume, delivery rates, replies, team workload and campaign results. **API.** A REST API for sending messages from your own software — your website, your CRM, your order system. See the [API reference](https://onpad.in/docs/api). ## What ONPAD is not ONPAD is the software. A few things belong to other people, and it matters to know which: - **WhatsApp is Meta's.** The rules about what you may send, which messages need approval, and how much Meta charges are all Meta's, not ONPAD's. ONPAD cannot approve a template or waive a charge. - **Your WhatsApp Business Account belongs to you.** It sits in your own Meta Business Manager. If you ever leave ONPAD, the account and the number stay yours. - **ONPAD does not supply phone numbers.** You bring your own. See [Before you start](https://onpad.in/docs/before-you-start). ## Who it is for Businesses that already talk to customers on WhatsApp and have outgrown a phone. The usual signs: more than one person needs to answer, you want to message a list rather than one person at a time, or you want your website or CRM to send WhatsApp messages on its own. If a single person answering from the WhatsApp Business app is working for you, you do not need this yet. ## Where to go next - New to the WhatsApp Business API? Read [WhatsApp Business API](https://onpad.in/docs/whatsapp-business-api) next — it explains how it differs from the WhatsApp you already use. - Ready to sign up? [Before you start](https://onpad.in/docs/before-you-start) lists what you need to have ready. - Want to know the costs first? [What it costs](https://onpad.in/docs/what-it-costs) separates Meta's charges from ONPAD's. --- # WhatsApp Business API Source: https://onpad.in/docs/whatsapp-business-api Most people arrive here using one of two WhatsApp apps already, and the third thing — the one ONPAD runs on — works differently enough that it is worth ten minutes before you sign up. ## The three WhatsApps **WhatsApp Messenger** is the personal app. One phone, one person, no business features. **WhatsApp Business app** is the free app for small businesses. It adds a business profile, catalogues, quick replies and labels. It still runs on one phone, and only one person can use it at a time. **WhatsApp Business Platform (the Cloud API)** is what ONPAD uses. There is no phone and no app. Your number lives on Meta's servers, and software connects to it. That is what lets a whole team answer at once, lets you message thousands of people, and lets your website send messages on its own. A number can only be in one of these at a time. Moving a number to the API means it leaves the app — see [Before you start](https://onpad.in/docs/before-you-start). ## The rules the API brings These are Meta's rules, not ONPAD's. No platform can remove them, and any platform that claims to is worth avoiding. ### You cannot message someone first in free text To start a conversation with a customer, you must use a **message template** that Meta approved in advance. You write the template, submit it, and wait for a decision — usually minutes, sometimes a day. This is why campaigns can only use approved templates, and why you cannot type a new offer and blast it out immediately. See [Your first template](https://onpad.in/docs/your-first-template). ### The 24-hour customer service window When a customer messages you, a 24-hour window opens. Inside it, you can reply with anything — free text, images, documents, voice notes. No template, no approval. When it closes, free text is no longer allowed. The only way back to that customer is an approved template, which starts a fresh conversation. Their next reply opens a new 24-hour window. ONPAD shows you when a window has closed and offers to send a template instead, so you will not write a reply that cannot be delivered. ### Template categories Every template is one of three categories, and the category decides the rules and the price: - **Marketing** — offers, announcements, anything promotional. The most likely to be rejected if it reads like spam, and customers can opt out of it. - **Utility** — about something the customer already did: an order update, a delivery notification, an appointment reminder, a payment receipt. - **Authentication** — one-time passcodes only. Meta fixes the wording tightly and allows very little variation. Meta can re-categorise a template by itself if it disagrees with your choice. Labelling a promotional message as Utility does not make it cheaper; it usually makes it rejected. ### Messaging limits and quality rating Meta gives every number a **messaging limit** — how many different customers you may start a conversation with in 24 hours — and a **quality rating** of green, amber or red based on how customers react to you. The limit rises on its own as you send messages people welcome. It falls when customers block or report you. A red rating can pause the number entirely. To protect both: - Only message people who expect to hear from you. - Keep marketing relevant and not too frequent. - Honour opt-outs immediately. Neither the limit nor the rating is something ONPAD sets, and no ONPAD plan changes them. ## What this means in practice If you are used to the WhatsApp Business app, three habits have to change: 1. **Plan your outbound messages in advance.** Templates need approval, so the offer you want to send tomorrow should be submitted today. 2. **Reply inside the window.** A customer who messaged you yesterday afternoon is reachable in free text until this afternoon, and not after. 3. **Build a list of people who want to hear from you.** Buying a contact list is the fastest way to a red quality rating and a paused number. ## Next - [Before you start](https://onpad.in/docs/before-you-start) — what you need ready before signing up - [What it costs](https://onpad.in/docs/what-it-costs) — Meta's charges and ONPAD's, which are separate --- # Before you start Source: https://onpad.in/docs/before-you-start Signing up for ONPAD takes a minute. Connecting WhatsApp is the part that needs preparation, and almost every problem people hit comes from one of the items on this page. ## A phone number you can dedicate This is the one that catches people out. **The number must not be active on any WhatsApp account.** Not WhatsApp Messenger, not the WhatsApp Business app. When a number moves to the Cloud API, it leaves whichever app it was in, and the chat history in that app does not come with it. So you have two sensible choices: - **Use a fresh number.** A new SIM, a landline, or a toll-free number. Cleanest option, and nothing is lost. - **Move your existing business number.** Works, but first export anything you need from the WhatsApp Business app, tell your team the app will stop working for that number, and then delete the WhatsApp account on that number before connecting. Other requirements for the number: - You must be able to **receive an SMS or a voice call** on it right now, for the one-time verification code. - It must be a number you control. A number belonging to a customer, a supplier or a staff member's personal phone is a problem the day they leave. - Landlines work, as long as you can answer the verification call. > If you connect a number that is still active in the WhatsApp Business app, Meta will refuse it. Delete the WhatsApp account on that number first, then wait a few minutes before trying again. ## A Facebook account and Business Manager Connecting WhatsApp goes through Meta's own flow, and that flow needs: - A **personal Facebook account** to sign in with. This is just the login — your personal profile is not shown to customers. - A **Meta Business Manager** (also called Business Portfolio). If you do not have one, Meta lets you create it during the connection flow, so you do not need to set it up in advance. You will also create a **WhatsApp Business Account (WABA)** during the flow. That account belongs to you, lives in your Business Manager, and stays yours if you ever leave ONPAD. ## Your business details Have these ready, because Meta asks for them and customers see some of them: - **Legal business name.** It should match how your business is actually registered. Meta checks this when you apply for a verified badge later. - **Business category** — retail, education, health, and so on. - **A website.** Not strictly required to connect, but Meta asks for it during business verification, and a business with no web presence is harder to verify. - **A business email and address.** The display name you choose for WhatsApp has its own rules: it must relate to your business, and Meta rejects names that are generic, misleading, or just a category like "Best Deals". ## What you do not need - **You do not need a verified badge** (the green tick) to start. It is a separate application, and messaging works without it. - **You do not need business verification** to send your first messages. Meta lets an unverified business send to a limited number of customers so you can test. Verification raises that limit. - **You do not need to buy numbers from ONPAD.** ONPAD does not sell phone numbers. You bring your own. - **You do not need a developer.** The connection flow is a series of screens, not code. ## If you are in India Meta localised billing for India on **1 January 2026**. Eligible businesses need to migrate their WhatsApp Business Account to INR billing by **31 December 2026**, or message delivery can be disrupted from **1 January 2027**. This is between you and Meta — ONPAD does not control it and cannot do it for you. Check your WhatsApp Business Account in Meta Business Manager, and see [What it costs](https://onpad.in/docs/what-it-costs). ## Ready? If you have a free number you can verify right now and a Facebook login, you have everything. Start at [Create an account](https://onpad.in/docs/create-an-account). --- # What it costs Source: https://onpad.in/docs/what-it-costs There are **two separate bills**, and confusing them is the most common billing question we get. | Who charges | For what | Paid to | |---|---|---| | ONPAD | The software — inbox, campaigns, automations, API, team seats | ONPAD, as a subscription | | Meta | The WhatsApp messages themselves | Meta, billed to your own WhatsApp Business Account | ONPAD does not collect Meta's charges, does not add a markup to them, and cannot refund them. Meta bills you directly. This also means **a payment method has to be set up on the Meta side too.** An active ONPAD plan does not keep messages flowing if Meta has no way to charge you — Meta will stop delivering. ## The ONPAD subscription Every new account starts on a **7-day free trial**, and the trial is one per person, not one per workspace — creating a second workspace does not reset it. Plans, prices and limits live in the app, because they change: open **Plans & billing** inside your workspace for the current list. Deliberately, they are not printed here, so this page cannot go stale and quote you a price that no longer exists. What differs between plans is broadly: how many contacts you can store, how many messages you can send through campaigns and the API, how many team members can sign in, and which features are switched on. ## Meta's message charges Meta charges **per message**, not per conversation. This replaced the older conversation-based model, where one price covered 24 hours of back-and-forth. Now, one reply costs one message, and five replies cost five. What you pay for depends on the category: - **Marketing templates** — always charged. - **Utility templates** — charged when sent outside an open customer service window. - **Authentication templates** — charged when sent outside an open customer service window. - **Free-form messages inside an open 24-hour window** — not charged as template messages. There is also a **free entry point window**: when a customer reaches you through a Click-to-WhatsApp ad or a Facebook Page call button, a 72-hour window opens during which messages to that customer are free. Rates differ by country and by category, and Meta changes them. **Meta's own pricing page is the only accurate source**, and it is linked at the bottom of this page. Any rate you see quoted on a third-party blog may already be out of date. Utility and authentication messages get cheaper at higher monthly volumes, through tiers Meta aggregates across all the business accounts in your portfolio. ## If you are in India Meta localised billing for India on **1 January 2026**. Eligible businesses must migrate their WhatsApp Business Account to **INR billing by 31 December 2026**. Accounts that have not migrated can see message delivery disrupted from **1 January 2027**. Check this in Meta Business Manager, under your WhatsApp Business Account's billing settings. ONPAD cannot do the migration for you and does not get told whether you have done it. ## How to keep costs down **Reply inside the 24-hour window.** A free-form reply to a customer who just messaged you costs nothing as a template. The same information sent tomorrow needs a template, which is charged. **Do not send marketing when utility would do.** An order update genuinely is a utility message, and utility rates are lower. But write it as a utility message — if it carries an offer, Meta will re-categorise it as marketing anyway. **Keep your lists clean.** Every message to a wrong or dead number is still a delivery attempt. [Import problems](https://onpad.in/docs/create-an-account) and bad data cost money as well as quality rating. **Watch your quality rating.** It is free to keep it green and expensive to lose it — a red rating can pause your number, and a paused number sends nothing at any price. ## Where to check the real numbers - **ONPAD plans** — Plans & billing inside your workspace - **Meta's rates** — [Pricing on the WhatsApp Business Platform](https://developers.facebook.com/documentation/business-messaging/whatsapp/pricing) - **Your Meta bill** — Meta Business Manager, under your WhatsApp Business Account > Meta's pricing rules have changed more than once, most recently in 2025 and 2026. If what you read here and what Meta's page says ever disagree, Meta's page is right — tell us and we will fix this page. --- # Create an account Source: https://onpad.in/docs/create-an-account Creating an account takes under a minute and does not need your WhatsApp number yet. You can look around first and connect WhatsApp when you are ready. ## Sign up Go to the ONPAD sign-in page and choose **Create account**. You have two ways in. ### With email and password You will be asked for: - **First name** and **last name** — up to 80 characters each - **Email address** — this becomes your sign-in, so use one you will keep - **Password** — at least 8 characters, including **one number** and **one symbol** - Agreement to the terms If the password does not meet all three rules, the form says so before it submits. Letters and digits alone are not enough — a symbol such as `!`, `@` or `#` is required. ### With Google **Continue with Google** signs you in with a Google account instead. ONPAD asks Google only for your name and email address. There is no password to set or remember, and nothing in your Gmail or Drive is read. If you sign up with Google, keep using Google to sign in — there is no password on the account unless you set one later. ## What happens next Your **7-day free trial** starts immediately. No card is required to begin. The trial is **one per person, not one per workspace**. Creating a second workspace does not start a second trial, so there is no benefit to signing up twice. You are the **owner** of the workspace you create. The owner can do everything, including billing and deleting the workspace. You can invite others later with narrower roles. ## Setting up the workspace After signing up you land on workspace setup, which asks three things: 1. **Organisation name** — what your business is called. Customers can see this. 2. **Category** — retail, education, health, and so on. WhatsApp shows this on your business profile. 3. **Mobile number** — yours, for account matters. This is **not** the number you will message customers from, and ONPAD never messages your customers from it. Country and timezone are detected from your browser and saved quietly. If the guess is wrong, use **Change** under the form to correct them. Timezone matters later, because scheduled campaigns run in your workspace's timezone. The next step offers to connect WhatsApp. It is **optional** — you can skip it, look around the app, and connect when your number is ready. See [Set up your workspace](https://onpad.in/docs/set-up-your-workspace). ## Signing in later Use the same email and password, or the same Google account. **Remember me** keeps you signed in for 30 days on that browser. Forgot the password? Use **Forgot password** on the sign-in page. A reset link goes to your email. For security, the page says a link has been sent whether or not an account exists for that address — so if nothing arrives, check the spelling and your spam folder. Reset links expire. If yours has, request a new one rather than reusing the old email. ## Common problems **"The email or password is incorrect."** This one message covers both a wrong email and a wrong password, on purpose — it does not tell an attacker which addresses have accounts. Check for a typo, then use Forgot password. **You signed up with Google but are typing a password.** There is no password on a Google-created account. Use **Continue with Google**. **You cannot remember which email you used.** Try your work address first, then any address you may have used for a trial. If neither works, email [support@onpad.in](mailto:support@onpad.in) from the address you think it was. ## Next [Set up your workspace](https://onpad.in/docs/set-up-your-workspace) — the business details, and what the setup checklist is asking for. --- # Set up your workspace Source: https://onpad.in/docs/set-up-your-workspace A workspace is one business on ONPAD — its number, its contacts, its templates, its team. Most people only ever need one. When you first sign in, the dashboard shows a four-step checklist. It is the shortest road from a new account to a delivered message. ## The four steps ### 1. Connect WhatsApp Links your business number to ONPAD through Meta. Nothing can be sent or received until this is done. This is the step with real prerequisites — a number not in use on any WhatsApp, and a Facebook login. Read [Before you start](https://onpad.in/docs/before-you-start) first, then [Connect WhatsApp](https://onpad.in/docs/connect-whatsapp). ### 2. Add contacts Bring your customer list in. You can add one contact at a time or import a CSV file in bulk. You do not need your whole list to continue — two or three test contacts are enough to get through the rest of the checklist. Import the real list once you have seen a message arrive. ### 3. Create a template Write a reusable message and submit it to Meta for approval. You need at least one approved template before you can message anybody who has not messaged you first. Approval usually takes minutes. Submit one early, because the next step waits on it. See [Your first template](https://onpad.in/docs/your-first-template). ### 4. Send a campaign Send that approved template to your contacts and watch it deliver. See [Your first message](https://onpad.in/docs/your-first-message). The checklist disappears once all four are done. Automations and the AI Agent are not on it — they are real features, but they are not on the road to a first message. ## Your business details The three things asked during signup can all be changed later in **Settings**: - **Organisation name** — what your business is called inside ONPAD. - **Category** — shown on your WhatsApp business profile. - **Your mobile number** — for account matters only. Customers never see it and ONPAD never messages them from it. **Country and timezone** were detected from your browser. Check the timezone is right, because scheduled campaigns run in it. A campaign scheduled for 10am runs at 10am in the workspace's timezone, not the sender's. ## Your WhatsApp business profile Separate from the above, and this one customers do see. Once WhatsApp is connected, Settings lets you edit the profile Meta shows on your number: - **About** — the short line under your business name - **Description** — a longer description of what you do - **Address**, **email**, **website** (up to two), **category** - **Profile picture** These are stored by Meta, not by ONPAD, so changes go out to Meta when you save. The dashboard has a shortcut to the same editor. ## Working with more than one workspace Each workspace is fully separate: its own number, contacts, templates, campaigns, team and billing. Nothing is shared between them, and a contact imported into one does not appear in the other. Creating a second workspace does **not** start a second free trial — the trial is one per person. ## Roles You are the **owner** of the workspace you created. When you invite people, you give each one a role that decides what they can reach — for example whether they can see billing, or only answer conversations. See the team and permissions guide for the full table of what each role can do. ## Next [Connect WhatsApp](https://onpad.in/docs/connect-whatsapp) — the step with the most moving parts, explained screen by screen. --- # Connect WhatsApp Source: https://onpad.in/docs/connect-whatsapp This is the step with real prerequisites. Read [Before you start](https://onpad.in/docs/before-you-start) first — almost every failure here comes from the number not being ready. Connecting goes through **Meta's own Embedded Signup**. ONPAD opens Meta's window; you complete it with your Facebook login. Your credentials go to Meta, never to ONPAD. ## Start Open **Connect WhatsApp** from the dashboard checklist, the banner at the top of the dashboard, or the setup page directly. You will be asked to choose how to connect. The standard option is **Cloud API number** — connect a new number, or move an existing number to the API. Choose it unless you have been told otherwise. > **Use a number that can receive the Meta verification code right now.** You will be asked for a code within a minute or two, and the window times out. ## The three screens Meta's window opens on top of ONPAD. It has three stages. ### 1. Meta login Sign in to Facebook. This is your personal login — your profile is not shown to customers and ONPAD does not see your password. If you are already signed in to Facebook in that browser, this is one click. ### 2. Select business Choose or create: - Your **Meta Business Portfolio** (Business Manager). Create one here if you do not have one. - Your **WhatsApp Business Account (WABA)** — the account that will own the number. Create one if this is your first. - The **phone number** to connect, and the **display name** customers will see. Display names have rules. Meta rejects names that are generic, misleading, or just a category. Use your actual business name. ### 3. Register and connect Meta sends a verification code to the number by SMS or voice call. Enter it. ONPAD then completes Cloud API registration, which includes securely creating a unique **two-step verification PIN** for the number. You do not need to invent or remember this PIN — it is generated and stored encrypted. When the window closes, ONPAD shows a connected card with your verified business name, the number, and the provider. That is the whole connection. ## After connecting Check the dashboard — the WhatsApp banner should be gone and the first checklist step ticked. Two things worth doing now: 1. **Fill in your WhatsApp business profile** in Settings: about, description, address, email, website, category, profile picture. This is what customers see when they open your business on WhatsApp. 2. **Send yourself a test message** before importing your real list. See [Your first message](https://onpad.in/docs/your-first-message). ## If the number shows "Pending" in Meta This happens when Meta accepted the number but Cloud API registration did not finish — usually because the window was closed early or the verification step timed out. On the setup page, open **Number still shows Pending in Meta?** and choose **Register number**. ONPAD creates the two-step verification PIN and completes registration with Meta. If it still does not complete, the number usually needs to be removed from the WABA in Meta Business Manager and connected again. ## Common problems **"This number is already registered on WhatsApp."** The number is still active on WhatsApp Messenger or the WhatsApp Business app. Delete the WhatsApp account on that number from inside the app, wait a few minutes, then try again. Exporting chats first, if you need them — they do not come across. **The verification code never arrives.** Check the number can receive SMS from international senders. Try the voice call option instead. Some business landlines and VoIP numbers block automated SMS but accept the call. **The Meta window closed by itself.** Start again from the beginning. A half-finished signup does not leave anything broken behind, though the number may show Pending — see above. **"Could not reach Meta."** A network problem between the server and Meta. Wait a minute and try again. If it persists, it is on our side, not yours — email [support@onpad.in](mailto:support@onpad.in). **You do not see your business in the list.** You are signed in to Facebook as a person without access to that Business Portfolio. Sign out and sign in as an account that is an admin of it. **The display name was rejected.** Meta requires the name to relate to the business. "Sunrise Store" works; "Best Offers Daily" usually does not. Pick a name matching your registered business and try again. ## What ONPAD stores The access token Meta issues is stored **encrypted**. ONPAD uses it to send and receive on your behalf and nothing else. Your Facebook password is never seen by ONPAD at any point. The WhatsApp Business Account stays in your own Business Manager. If you leave ONPAD, you keep it and the number. ## Next [Your first template](https://onpad.in/docs/your-first-template) — the message Meta has to approve before you can write to anybody first. --- # Your first template Source: https://onpad.in/docs/your-first-template A **template** is a message Meta approved in advance. You need one to write to anybody who has not messaged you in the last 24 hours — which includes every campaign you will ever send. This page walks through creating one. For why they exist at all, see [WhatsApp Business API](https://onpad.in/docs/whatsapp-business-api). ## Create it Open **Templates** and choose **Create template**. ### Name Lowercase letters, numbers and underscores only, at least 3 characters. `order_shipped` works; `Order Shipped` does not. The name is an identifier, not something customers see. Pick something you will recognise in a list a year from now. ### Category Pick the one that describes the message honestly: - **Marketing** — offers, announcements, anything promotional. - **Utility** — about something the customer already did: an order update, a reminder, a receipt. - **Authentication** — one-time passcodes only. Choosing Utility for a promotional message does not make it cheaper. Meta re-categorises templates it disagrees with, and often rejects them. **Authentication is a special case.** Meta writes the wording itself — the body becomes `{{1}} is your verification code.` and you cannot change it, add a header, a footer or your own buttons. That is Meta's rule, not a limitation of ONPAD. ### Language Pick the language the template is written in. Supported: English (`en`, `en_US`, `en_GB`), Hindi, Bengali, Marathi, Tamil, Telugu, Gujarati, Spanish, Portuguese (Brazil), French, German, Italian, Arabic, Indonesian, Turkish, Russian, Chinese (Simplified), Japanese and Korean. The language must match the text. A Hindi message submitted as English is a common rejection reason. ## The parts of a template ### Header — optional One of: - **Text** — up to **60 characters**. Can contain one variable. - **Image**, **Video** or **Document** — uploaded as a sample when you submit. - **Location** - **None** ### Body — required Up to **1,024 characters**. This is the message. Variables are written `{{1}}`, `{{2}}` and so on, and are filled in when the message is sent: ```text Hi {{1}}, your order {{2}} has shipped and should arrive by {{3}}. ``` For every variable you must give a **sample value** of up to 100 characters. Meta reads the samples to understand what the template does — a template whose samples are `a`, `b`, `c` is much more likely to be rejected than one with `Priya`, `#10482`, `Friday`. Variables cannot sit next to each other (`{{1}}{{2}}`) and the body cannot begin or end with one. Meta rejects both. ### Footer — optional Up to **60 characters**. Small grey text under the message. Good place for "Reply STOP to opt out". ### Buttons — optional Up to **10 buttons** in total. Every label is up to **40 characters**. - **Quick reply** — the customer taps and the label comes back to you as their reply. Up to 10 of them. - **Website** — opens a URL. Up to 2, and the URL must be `https://`. - **Phone** — dials a number. One per template. - **Copy code** — gives the customer a coupon code to copy. One per template, and Meta writes the label itself. See [Templates](https://onpad.in/docs/templates) for the full rules. ## Submit it Saving submits the template to Meta. The status then moves through: - **Pending** — with Meta, awaiting review. Usually minutes, sometimes up to 24 hours. - **Approved** — ready to use in campaigns and the API. - **Rejected** — see below. ONPAD keeps the status in sync with Meta, so the Templates list shows the current state. ## If it is rejected Rejection is normal, especially the first time. The usual causes: **It reads like spam.** Lots of capitals, several exclamation marks, "FREE!!!", urgency pressure. **Wrong category.** A promotional message submitted as Utility. **Poor sample values.** Placeholders like `xxx` or `test` give Meta nothing to review. **Language mismatch.** Text in one language, submitted as another. **A URL Meta cannot verify**, or a link shortener it does not trust. **Asking for sensitive information** — card numbers, passwords, government ID numbers. Fix the wording and submit again. There is no penalty for resubmitting, and no queue position to lose. Repeated rejections of the same kind can affect your account standing, so change something meaningful between attempts rather than resubmitting the same text. ## A good first template Keep it simple and obviously legitimate: ```text Name: welcome_message Category: Utility Language: en_US Body: Hi {{1}}, thanks for getting in touch with Sunrise Store. We have saved your number and will keep you updated. Sample: Priya Footer: Reply STOP to opt out ``` That one is approved quickly and is enough to test the whole path end to end. ## Next [Your first message](https://onpad.in/docs/your-first-message) — sending the template you just had approved. --- # Your first message Source: https://onpad.in/docs/your-first-message You have a connected number and an approved template. This is the last step of setup: getting a message onto a real phone. Send to **yourself or a colleague first.** Never point the first campaign at your customer list — a mistake there costs money and quality rating, and neither comes back. ## Add a test contact Open **Contacts** and choose **Add contact**. You need a phone number; name, email, company and tags are optional. Write the number in full international form without the `+` — `919876543210` for an Indian mobile. If you write a number without a country code, ONPAD applies the workspace default, which is +91 for India. Use a phone you can physically pick up. You want to see what arrives, not assume it. ## Send it Open **Campaigns** and choose **Create campaign**. 1. **Choose the template** you had approved. 2. **Choose the audience** — for this test, just the one contact you added. 3. **Fill in the variables.** If the template has `{{1}}` for a name, map it to the contact's name so each person gets their own. ONPAD pre-fills from the template's sample values; replace them with real mappings. 4. **Send now**, or schedule it for later. Scheduled campaigns run in your workspace's timezone. Then watch the campaign page. ## What the statuses mean | Status | What happened | |---|---| | **Queued** | Accepted by ONPAD, waiting its turn to go to Meta | | **Sent** | Meta accepted it and is delivering | | **Delivered** | It reached the customer's phone | | **Read** | The customer opened it — only if they have read receipts on | | **Failed** | It did not go. The reason is shown on the row | **Read is not reliable as a measure.** Customers who turn read receipts off never report read, no matter how carefully they read the message. A message can sit at **Sent** for a while if the phone is switched off. Meta retries, then gives up after 30 days. ## If it failed The failure reason is on the recipient row. The common ones: **Invalid phone number.** Wrong country code, a missing digit, or a landline. Check the full international form. **Number is not on WhatsApp.** Exactly what it says. The number exists but has no WhatsApp account. **Template not approved.** The template's status changed between creating and sending the campaign. Check Templates. **Outside the 24-hour window with a non-template message.** Cannot happen from a campaign, since campaigns only use templates — but it can from the inbox. See the 24-hour window in [WhatsApp Business API](https://onpad.in/docs/whatsapp-business-api). **Messaging limit reached.** Meta caps how many new conversations your number may start in 24 hours. New numbers start low and the limit rises as you send well-received messages. **Payment issue at Meta.** Meta has no valid payment method on your WhatsApp Business Account and stopped delivering. This is on Meta's side — fix it in Meta Business Manager. An active ONPAD plan does not help here. See [What it costs](https://onpad.in/docs/what-it-costs). ## When it arrives Reply to it from the phone you sent it to. The reply appears in your **Inbox**, and a 24-hour window opens in which you can answer in free text with no template. That round trip — template out, reply in, free-text answer — is the whole product working. If it did, you are set up. ## Then, carefully Before pointing anything at a real list: 1. **Import your contacts properly.** A CSV with bad numbers wastes money and quality rating on every send. 2. **Start small.** A few hundred, not everyone, on the first real campaign. 3. **Check your messaging limit.** New numbers can only start a limited number of conversations a day. 4. **Send to people who expect you.** Bought lists are the fastest route to a red quality rating and a paused number. ## Next You have finished setup. From here: - **Inbox** — answering customers as a team - **Contacts** — importing your real list - **Campaigns** — audiences, scheduling and results - **[API](https://onpad.in/docs/api)** — sending from your own software --- # Inbox Source: https://onpad.in/docs/inbox The inbox is one WhatsApp number answered by your whole team. It looks like WhatsApp Web on purpose — conversations down the left, the thread in the middle, the customer's details on the right. ## The 24-hour window Everything in the inbox depends on this one rule. When a customer messages you, a **24-hour window** opens. Inside it you can reply with anything — text, images, documents, voice notes. No template, no approval, no wait. When the window closes, free text is no longer allowed. The inbox tells you and offers to send an approved template instead. The template reaches them, and their reply opens a fresh 24 hours. > The clock runs from the customer's **last message**, not from the first. Every reply they send resets it. If you try to send free text after it closes, you get: *"The 24-hour reply window has closed. Send an approved template to reach this customer."* That is Meta's rule, and no plan or setting changes it. See [WhatsApp Business API](https://onpad.in/docs/whatsapp-business-api). ## Replying Type and send. Messages are up to **4,096 characters**. ### Sending media You can attach: - **Images** — JPEG, PNG, WebP - **Video** — MP4, 3GP - **Documents** — PDF and the usual office formats - **Audio** — AAC, MP4, MPEG, AMR, OGG Captions follow the same 4,096 character limit. Media is also only allowed inside the open window. ### Sending a template When the window is closed — or when you simply want to send an approved message — use the template option. Only **approved** templates appear, and you fill in any variables before sending. ### Reactions You can react to a customer's message with an emoji, the same as in WhatsApp. ## Working as a team ### Assignment Assign a conversation to a person so everyone knows who owns it. Unassigned conversations are everybody's and therefore nobody's — assign early. ### Open and closed A conversation is **open** or **closed**. Close it when the matter is finished; it leaves the active list without deleting anything. If the customer messages again, it comes back. Closing is not deleting. The whole history stays on the contact. ### Mark as read Marks the conversation read without opening it — useful for clearing noise after a campaign. ### Notes Notes are **internal**. The customer never sees them. Use them for context the next person needs: what was promised, what the account number is, why this one is awkward. ### Labels Labels organise conversations — `refund`, `wholesale`, `escalated`. Create them once and apply as needed. Labels sit on the conversation; tags sit on the contact. ### Canned replies Saved answers for things you type constantly — opening hours, delivery timelines, the return policy. Save one from a message you have just written, then reuse it. ## The AI agent in the inbox If the AI Agent is switched on, it can answer on its own. Each conversation has a bot status you can turn off, so a human takes over for that customer without switching the agent off for everybody. Turning the bot off for a conversation is the normal way to escalate. ## When a message fails A failed message shows in the thread with its reason, and can be retried from there. Common causes: - **The window closed** while you were typing. Send a template. - **The number is not on WhatsApp.** - **Meta payment issue** — your WhatsApp Business Account has no valid payment method. See [What it costs](https://onpad.in/docs/what-it-costs). ## Practical habits **Assign before replying.** Two people answering the same customer looks worse than a slow reply. **Close what is finished.** An inbox where everything is open tells you nothing. **Notes over memory.** The person who picks this up at 9pm is not you. **Watch the window.** If a conversation is nearly 24 hours old and still needs an answer, answer it now — after that it costs a template. ## Next - [Contacts](https://onpad.in/docs/contacts) — the customer records behind these conversations - [Campaigns](https://onpad.in/docs/campaigns) — messaging many people at once --- # Contacts Source: https://onpad.in/docs/contacts Contacts are the customers your workspace knows about. Every conversation, campaign and API message is attached to one. ## Adding a contact **Contacts → Add contact.** Only the phone number is required: | Field | Required | Notes | |---|---|---| | Phone number | Yes | Full international form. 8–15 digits after separators are stripped | | Name | No | Shown in the inbox and usable as a campaign variable | | Email | No | Stored for your reference; WhatsApp does not use it | | Company | No | Stored for your reference | | Tags | No | How you segment for campaigns | Write the number in full international form: `919876543210` for an Indian mobile. Spaces, dashes and brackets are stripped, so `+91 98765-43210` is accepted too. A number **without** a country code is incomplete. In imports you choose a default country code to apply; when adding one contact, write it in full. ## Importing a CSV **Contacts → Import contacts.** This is how you bring a real list in. ### 1. The file - **CSV**, up to **40 MB**. Larger files must be split. - The **first row must be column headings**. - Comma, semicolon or tab separated — the delimiter is detected automatically from the first line, so an Excel export that uses semicolons works without changing anything. - Download the sample CSV if you want the exact shape. ### 2. Map the columns After upload you map each CSV column to a contact field. **Phone is the only required mapping** — an import without it is rejected. Each CSV column can be mapped only once. Columns you do not need can be left unmapped and are ignored. ### 3. Default country code Numbers written without a country code get the default you choose here. India (`+91`) is pre-selected. This matters more than it looks. A list of `9876543210` style numbers with the wrong default produces thousands of valid-looking but undeliverable numbers — and every send attempt against them costs money and quality rating. ### 4. Run it **Keep the import window open until it finishes.** Large files are processed in batches, and closing the tab stops the run partway. ## What happens to duplicates Imports **update rather than duplicate**. A phone number already in the workspace has its name, email, company and tags filled in from the CSV where those fields are currently empty — existing values are not overwritten by blanks. A contact that originally came from WhatsApp keeps its WhatsApp origin; one that did not is marked as coming from CSV. Rows with an unusable phone number are **skipped**, not guessed at. The import summary says how many. ## Tags Tags are how you pick an audience for a campaign — `vip`, `mumbai`, `trial-2026`, whatever suits you. Rules: up to 60 characters, and no commas, pipes or semicolons, because those are the separators tags are stored with. A contact can have many tags. You can add tags during import by mapping a CSV column to Tags, or afterwards on a contact. Pick a small number of tags and use them consistently. Fifty tags used once each segment nothing. ## Exporting **Contacts → Export** downloads the current list as CSV, named with the date. Any filter applied to the list applies to the export, so you can export one tag rather than everything. Use it for a backup before a big import, or to work on the list in a spreadsheet. ## Common problems **"CSV file must be smaller than 40 MB."** Split the file. A 40 MB CSV is roughly a million rows — if you are near it, import in parts. **"Map a CSV column to Phone number."** No column was mapped to Phone. The import cannot run without it. **"Each CSV column can only be mapped once."** Two fields point at the same column. Pick one. **"CSV header row is missing."** The file starts with data instead of headings. Add a heading row. **Numbers imported but messages fail.** Almost always the country code. Export the list and check what the numbers actually look like now — if they are 10 digits where they should be 12, the default country code was wrong. **Fewer contacts than rows in the file.** Some rows were skipped for an unusable phone number, and duplicates updated an existing contact instead of creating a new one. Both are counted in the summary. ## Before a big import 1. **Export what you have** as a backup. 2. **Import 10 rows first** and look at the result. Mapping mistakes are obvious on 10 rows and invisible on 10,000. 3. **Check the country code** on those 10. 4. Then run the whole file. ## Next - [Campaigns](https://onpad.in/docs/campaigns) — sending to a tagged audience - [Inbox](https://onpad.in/docs/inbox) — where replies arrive --- # Templates Source: https://onpad.in/docs/templates [Your first template](https://onpad.in/docs/your-first-template) covers creating one. This page covers everything after that. ## Kinds of template ### Standard Header, body, footer, buttons. What most templates are. ### Carousel **Between 2 and 10 cards** — a carousel of one is just a message. Each card has its **own image or video**, its own text (up to 160 characters) and up to **2 buttons**. The customer swipes through them. Good for a product range or several offers in one message. Every card needs media — a carousel card without an image or a video is rejected. ### Authentication One-time passcodes only, and Meta controls them tightly. The body is fixed as: ```text {{1}} is your verification code. ``` You cannot change the wording, add a header or footer, or add your own buttons. ONPAD fills the fixed text in for you so the preview looks like the real message. Authentication templates are reviewed quickly and rarely rejected, because there is almost nothing to get wrong. ## Buttons A template can carry **up to 10 buttons in total**, and each type has its own cap on top of that: | Type | How many | Label | Value | |---|---|---|---| | **Quick reply** | up to 10 | 40 characters | — the label comes back as the customer's reply | | **Website** | up to 2 | 40 characters | an `https://` URL, up to 2,000 characters | | **Phone** | 1 | 40 characters | a number in `+` international form, 7–15 digits | | **Copy code** | 1 | fixed by Meta | a coupon code, up to 20 characters | Three rules that catch people out: - **Website button URLs must use HTTPS.** A plain `http://` URL is rejected before it even reaches Meta. - **A website button can use only one variable**, and it has to sit at the end of the URL. `https://shop.in/order/{{1}}` works; a variable in the middle does not. - **The copy code button's label is Meta's**, not yours — it always reads "Copy offer code". A quick reply button is the most reliable way to get a response: the customer taps instead of typing, and the tap arrives in your inbox as a message, opening a 24-hour window. ## Field limits | Field | Limit | |---|---| | Name | 3+ characters, lowercase letters, digits and underscores | | Header text | 60 characters | | Header example | 120 characters | | Body | 1,024 characters | | Variable sample | 100 characters each | | Footer | 60 characters | | Button label | 40 characters | | Button URL | 2,000 characters, HTTPS only | | Coupon code | 20 characters | | Buttons per template | 10 total | | Carousel cards | 2–10 | | Carousel card text | 160 characters | | Carousel card buttons | 2 | ## Statuses ONPAD keeps these in sync with Meta, so the list shows what Meta currently thinks. | Status | Meaning | |---|---| | **Draft** | Not submitted yet | | **Pending** | With Meta, under review | | **Approved** | Usable in campaigns and the API | | **Rejected** | Meta refused it. Edit and resubmit | | **Paused** | Meta paused it for poor quality. Temporary | | **Disabled** | Meta disabled or deleted it. Not coming back | ### Paused Meta pauses a template when too many recipients block or report after receiving it. It can be used again after a cooling-off period, but a template that gets paused twice usually ends up disabled. A pause is a signal about the **message**, not about your account — though repeated pauses do affect the number's quality rating. The fix is not to resubmit the same text. Ask why people reacted badly: too frequent, not expected, or sent to people who never asked. ### Disabled Meta disabled the template permanently. Write a new one; the old one will not come back. ## Template quality Approved templates carry a quality rating from Meta based on how recipients react. A falling rating is the warning that comes before a pause. Protecting it is the same work as protecting your number's rating: send to people who expect you, keep marketing relevant, and honour opt-outs immediately. ## Duplicating a template Duplicating copies the structure, text and settings into a new draft. For a carousel, the card structure and text are copied but **the media is asked for again** — Meta ties uploaded samples to the template they were submitted with, so the files cannot be reused. Useful for translating a template: duplicate, change the language, translate the text, submit. ## The template library ONPAD ships ready-made templates for common cases — order updates, appointment reminders, welcome messages. They are starting points, not finished messages. **The example business details in them are placeholders.** Replace them with your own before submitting. Meta reviews what you actually send, and a template still carrying an example company name reads as careless to a reviewer. ## Why a template was rejected In rough order of frequency: 1. **It reads like spam.** Capitals, several exclamation marks, "FREE!!!", pressure. 2. **Wrong category.** Promotional content submitted as Utility. 3. **Poor sample values.** `xxx`, `test`, `abc`. Meta reads these to understand the template. 4. **Language mismatch.** The text is in one language, submitted as another. 5. **An unverifiable URL**, or a link shortener Meta does not trust. 6. **Asking for sensitive data** — card numbers, passwords, government ID. 7. **Variables placed badly** — two touching (`{{1}}{{2}}`), or one at the very start or end of the body. There is no penalty for resubmitting, and no queue position to lose. But change something real between attempts — resubmitting identical text wastes a day and teaches you nothing. ## Keeping a template approved **Do not over-send it.** The same marketing template to the same people weekly is the usual cause of a pause. **Keep the promise the template makes.** A template that says "order update" and carries an offer gets reported. **Retire templates you no longer send.** An unused template cannot hurt you, but a list of forty makes it hard to see which ones are in trouble. ## Next - [Campaigns](https://onpad.in/docs/campaigns) — sending an approved template to a list - [API](https://onpad.in/docs/api/send-message) — sending one from your own software --- # Campaigns Source: https://onpad.in/docs/campaigns A campaign sends one approved template to many contacts and reports what happened to each one. Campaigns can only use **approved templates** — that is Meta's rule for messaging people who have not written to you recently. See [Your first template](https://onpad.in/docs/your-first-template). ## Creating one **Campaigns → Create campaign.** ### 1. Choose a template Only approved templates appear. A template pending review or rejected cannot be used. ### 2. Choose the audience Two ways: - **All contacts** — everyone in the workspace. - **By tag** — everyone carrying a particular tag. The audience count updates as you choose, so you see exactly how many people will receive it before committing. > **Contacts who opted out of marketing are never included.** They are excluded from the count and from the send automatically — you do not have to maintain that list yourself. ### 3. Fill in the variables If the template has `{{1}}`, `{{2}}` and so on, map each to either a contact field — so each person gets their own name — or a fixed value that is the same for everybody. ONPAD pre-fills from the template's sample values. Replace them; the samples were for Meta's reviewer, not for your customers. ### 4. Media header, if the template has one Templates with an image, video or document header need the actual file for this send. Upload it here. ### 5. Send or schedule Send now, or pick a time. **Scheduled campaigns run in your workspace's timezone** — check Settings if you are unsure which that is. ## Throttling and send windows Two controls worth knowing about: **Throttle per minute** limits how fast messages go out. Useful when you do not want a thousand replies landing in the inbox at once, and gentler on your quality rating than a sudden burst. **Send window** restricts sending to certain hours. A campaign that would otherwise run at 2am waits until the window opens. Messages arriving at a sensible hour get better responses and fewer blocks. ## Campaign statuses | Status | Meaning | |---|---| | `draft` | Being built, nothing sent | | `scheduled` | Waiting for its time | | `running` | Sending now | | `paused` | Stopped partway; can be resumed | | `completed` | Every recipient has a final result | | `cancelled` | Stopped and will not resume | A running campaign can be **paused**. Messages already sent cannot be recalled — WhatsApp has no such thing — but pausing stops everything not yet sent. ## Per-recipient statuses | Status | Meaning | |---|---| | `queued` | Waiting its turn | | `processing` | Being sent right now | | `accepted` | Meta accepted it | | `sent` | On its way | | `delivered` | It reached the phone | | `read` | The customer opened it | | `failed` | It did not go; the reason is on the row | The campaign page shows the totals — sent, delivered, read, replied, failed — and lets you open the recipient list filtered by any of them. **Replied** is the number that actually matters for most campaigns. Delivered means it arrived; replied means it worked. ## Reading failures The campaign page groups failures by reason, so you see the shape of the problem rather than scrolling a list. | Reason | What to do | |---|---| | Invalid phone number | Fix the data. Usually a wrong country code on import | | Not on WhatsApp | Nothing to do. That number has no WhatsApp account | | Messaging limit reached | Meta caps new conversations per 24 hours. Send in smaller batches | | Template paused or disabled | Meta paused it, usually for poor quality. Check Templates | | Payment issue | Meta has no valid payment method on your account. Fix in Meta Business Manager | Temporary failures are retried automatically. Permanent ones — an invalid number — are not, because retrying cannot help. ## Before a big send **Send to yourself first.** Create a campaign for a tag containing only your own number and run it. You see exactly what the customer will see, including how the variables filled in. **Check the variables rendered properly.** A mapping mistake that leaves `{{1}}` in the message, or puts the wrong field in it, is visible only in a real send. **Start small on a new number.** Meta's messaging limit begins low and rises as you send well-received messages. A new number cannot message everybody on day one. **Send at a sensible hour.** Use the send window. Messages at 11pm get blocked and reported, and blocks cost quality rating, which costs you the number. ## Things campaigns cannot do **Recall a sent message.** WhatsApp does not offer it. **Send an unapproved template.** No exceptions. **Skip the opt-out list.** By design — this is a protection, not a limitation. **Message people who never gave you their number.** Technically it will send; practically it is the fastest route to a red quality rating and a suspended number. ## Next - [Contacts](https://onpad.in/docs/contacts) — building the audience - [Inbox](https://onpad.in/docs/inbox) — where the replies land - [API](https://onpad.in/docs/api) — sending from your own software instead --- # Automations Source: https://onpad.in/docs/automations An automation is a flow that runs on its own when something happens — a first message arrives, or a customer says a particular word. Automations are built on a canvas: a trigger at the top, then nodes connected by lines. Each node does one thing and hands the conversation to the next. ## Triggers A flow has exactly one trigger, and it decides when the flow runs. **New conversation** — the first time a customer messages you. Use it for a welcome message, or to collect what you need before a human picks up. **Keyword** — the customer's message contains or equals a word you choose. Use it for `price`, `hours`, `STOP`, `catalogue`. ## Nodes | Node | What it does | |---|---| | **Message** | Sends free text | | **Template** | Sends an approved template — works even when the 24-hour window is closed | | **Buttons** | Sends a message with tappable reply buttons | | **List** | Sends a menu the customer picks from | | **AI reply** | Hands this turn to the AI Agent, which answers from your business information | | **Condition** | Branches on what the customer said — equals, contains | | **Delay** | Waits before continuing | | **Wait for reply** | Pauses the flow until the customer answers | | **Tag** | Adds a tag to the contact | | **Assign** | Assigns the conversation to a team member | | **Handoff** | Stops the automation and hands over to a human | | **End** | Finishes the flow | **Assign and Handoff need an active team member.** A flow pointing at someone who has left will not publish. ## Draft and published An automation keeps two versions: the **draft** you are editing and the **published** one that is actually running. Editing never affects live conversations. Changes take effect when you publish, and each publish increments the version. This is deliberate — a flow serving customers right now should not change under them because somebody dragged a node. ## Statuses | Status | Meaning | |---|---| | **Draft** | Never published. Not running | | **Active** | Published and running | | **Paused** | Published but not running. Resumes on unpause | Pause is the safe way to stop a flow that is misbehaving. Nothing is lost, and conversations part-way through stop where they are. ## Free text and the 24-hour window The same rule as everywhere else: a **Message** node sends free text, which only works inside the 24-hour window. Since automations usually trigger on a customer's own message, the window is almost always open. But a flow with a long **Delay** can wake up after it has closed — in that case use a **Template** node, which works at any time. ## Designing one that works **Start small.** A welcome message and a handoff is a complete, useful automation. Build the twenty-node version after you have seen the two-node one run. **Always leave a way to a human.** A flow a customer cannot escape is worse than no flow. Put a Handoff on the path where nothing matched. **Use buttons instead of asking people to type.** Taps are unambiguous; typed answers need a Condition node for every spelling. **Name nodes for what they do.** Six months from now "Message 4" tells you nothing. ## Watching them Each automation records how many times it ran, how many succeeded, when it last ran, and the last error if one occurred. A run count climbing with a success count that is not is the signal to open it — usually a Template node whose template was paused, or an Assign node pointing at someone who left. ## Automations and the AI Agent They work together. An **AI reply** node hands one turn to the agent and then continues the flow, which lets you keep control of the structure — collect the order number with a Wait for reply, then let the agent answer the question about it. See [AI Agent](https://onpad.in/docs/ai-agent). ## Next - [AI Agent](https://onpad.in/docs/ai-agent) — the assistant that answers customers - [Inbox](https://onpad.in/docs/inbox) — where a handoff lands --- # AI Agent Source: https://onpad.in/docs/ai-agent The AI Agent answers customers on your behalf, using information you give it about your business. It is not a general chatbot — it knows what you tell it and hands over when it does not know. ## Setting it up Open **AI Agent** and fill in what it should know. ### Who it is | Field | What it is for | |---|---| | **Agent name** | What it calls itself. Default is "Chat agent" | | **Greeting message** | The first thing a new customer sees, up to 1,000 characters | | **Business name** and **type** | So it describes you correctly | | **Currency** | For anything it says about prices | ### What it knows This is the part that decides whether it is useful: - **Business description** — what you do, in plain words - **Products and services** — what you sell, with prices if you want it quoting them - **Policies** — returns, delivery, warranty, payment - **FAQ** — the questions you answer every day - **Ground rules** — what it must never do. Never promise a delivery date, never quote a discount, never discuss a competitor Ground rules matter more than people expect. An agent that invents a refund policy costs you more than one that says "let me check with the team". ### Importing from your website Point it at your website URL and it pulls content in as a starting point. **Read what it imported before publishing** — a website says things in marketing language that make poor answers, and it will not know what is out of date. ### How it speaks | Setting | Options | |---|---| | **Tone** | Friendly, professional, concise, playful | | **Language** | Auto, English, Hindi, Hinglish | | **Reply length** | Short, medium, long | | **Maximum reply** | Characters per reply, default 1,000 | **Auto language** matches whatever the customer wrote in — a question in Hinglish gets a Hinglish answer. For most Indian businesses this is the right setting. ## Handing over to a human Three ways a conversation reaches a person: **Handoff keywords.** Words that bypass the agent entirely — "agent", "human", "complaint". These never reach the AI, so they cost nothing and are never misread. **The fallback person.** Who the conversation goes to on handoff. Set this; an unassigned handoff sits in a shared inbox waiting for someone to notice. **Turning the bot off for one conversation.** From the inbox, any team member can switch the agent off for that customer and take over. The agent stays on for everybody else. The **handoff message** is what the customer sees when this happens. Make it a promise you keep: "One of our team will reply shortly" is fine if someone actually will. ## Publishing Settings are saved as a draft and go live when published. Live conversations keep using the published version until then, so editing is safe at any time. Always use the test panel before publishing. Ask it the five questions your customers actually ask and read the answers properly. ## Automatic replies The agent only answers on its own when **automatic replies** are switched on. Off, you can still test it and use it inside an automation's AI reply node, but it will not answer customers by itself. Starting with it off, testing for a few days inside automations, then switching it on, is the sane order. ## What it costs Every reply is a request to a language model, so the agent costs money per answer. The model used is configurable; a smaller model is cheaper and usually enough for FAQ-style questions. Handoff keywords are free — they never reach the model. Putting your common escalation words there saves money and gives a better answer. ## What it cannot do **It does not know your orders.** It answers from the information you wrote, not from your database. "Where is my order" gets a generic answer unless you hand off. **It does not learn from conversations.** If it answers something wrong, fix the business information — it will not correct itself. **It cannot message first.** It replies inside the 24-hour window like any free-text message. Starting a conversation needs a template. ## Getting good answers **Write the FAQ as questions and answers**, in the customer's words — "do you deliver to Pune" rather than "serviceable pincodes". **Be specific about prices.** "Starts at ₹499" is answerable. "Competitive pricing" is not. **Test with real messages.** Take ten genuine customer messages from your inbox and run them through. Wrong answers point at missing information. **Re-read it monthly.** The commonest failure is an agent confidently quoting a policy that changed in March. ## Next - [Automations](https://onpad.in/docs/automations) — using the agent inside a flow - [Inbox](https://onpad.in/docs/inbox) — taking over from the agent --- # Analytics Source: https://onpad.in/docs/analytics Analytics shows what your workspace did over a period, with the previous period beside it so you can see direction rather than just a number. ## Choosing a period Pick the number of days. Everything on the page uses it, and the comparison is against the equally long period before it — so 30 days is compared with the 30 before that, not with last calendar month. ## Messages | Metric | What it counts | |---|---| | **Received** | Inbound messages from customers | | **Sent** | Outbound messages from you | | **Accepted** | Messages Meta accepted for delivery | | **Delivered** | Messages that reached a phone | | **Read** | Messages the recipient opened | | **Failed** | Messages that did not go | | **Pending** | Sent, no final result yet | Shown as a daily chart and as totals. ### Reading these honestly **Read is unreliable.** Customers with read receipts off never report read, however carefully they read. A low read rate may mean nothing at all. **Delivered is the real outbound number.** It is the one that says the message arrived. **Failed is the one to act on.** A failure rate that climbs is either bad data or a problem with the number — both get worse if ignored. **Received is your demand.** If it rises while your replies do not, customers are waiting. ## Team workload How the conversations were shared out. Useful for noticing that one person is carrying the queue, or that assignment is not happening at all. > Workload shows **how much** each person handled, not how well or how fast. It does not measure response time, and nothing here should be read as "fastest responder". ## Campaigns Per-campaign results over the period: audience, sent, delivered, read, replied, failed. **Replied is the number that matters.** Delivered says it arrived; replied says it worked. A campaign with 98% delivery and 0.2% replies did not work, however good the delivery looks. ## AI and automation How many replies the AI Agent sent and how many automation runs happened, with successes. Watch the gap between runs and successes. Runs climbing while successes do not means a flow is breaking — usually a paused template or an Assign node pointing at someone who left. ## Hot leads Where ONPAD marks contacts as hot leads, it is a **heuristic** — a guess from message frequency and recency, not a verified intent signal. Useful for ordering a call list, not for forecasting revenue. ## What is not here **Revenue.** ONPAD does not know what a conversation was worth. Tag contacts that convert and compare tags over time if you need this. **Per-message cost.** Meta bills you directly; its charges are in Meta Business Manager, not here. See [What it costs](https://onpad.in/docs/what-it-costs). **Response time.** Not currently measured. ## Using it weekly Four questions worth asking every week: 1. **Is failed climbing?** If yes, look at the reasons before the next campaign. 2. **Is received rising faster than sent?** If yes, customers are waiting. 3. **Which campaign got replies?** Do that again. Delivery is not the goal. 4. **Is one person carrying the inbox?** Fix it before they stop enjoying their job. ## Next - [Campaigns](https://onpad.in/docs/campaigns) — the per-campaign detail behind these totals - [Inbox](https://onpad.in/docs/inbox) — where workload comes from --- # Team and roles Source: https://onpad.in/docs/team-and-roles A workspace can be answered by your whole team, each person with their own sign-in and a role that decides what they can reach. ## The four roles | Role | Can do | |---|---| | **Owner** | Everything, including billing and admins | | **Admin** | Manage the workspace, connect WhatsApp, manage people — but not billing | | **Manager** | Inbox, contacts, templates, campaigns, automations, AI Agent | | **Agent** | Reply to customers in the inbox | ### Owner One per workspace, the person who created it. Only the owner can: - **Change the plan or billing.** No other role reaches it. - **Invite or manage another admin.** The owner's own role cannot be changed from the team screen — there is always exactly one. ### Admin Runs the workspace day to day. Can connect and reconnect WhatsApp, sync templates with Meta, and invite managers and agents. An admin **cannot** invite another admin or change an existing one — *"Only the workspace owner can invite another admin."* That keeps the top of the hierarchy with the owner. An admin also cannot see or change billing. ### Manager Everything about the work, nothing about the workspace. Creates and sends campaigns, writes templates, builds automations, configures the AI Agent, manages contacts, works in the inbox. Cannot invite people, connect WhatsApp or touch billing. ### Agent Answers customers. The inbox and the contacts behind it. Cannot create campaigns, edit templates or change automations. This is the right role for most of a support team — it removes the possibility of someone accidentally sending a campaign to everybody. ## Inviting someone **Settings → Team → Invite a teammate.** You need their work email and a role. They receive a link **valid for 7 days**. If it expires, send another. Who can invite whom: | You are | You can invite | |---|---| | Owner | Admin, Manager, Agent | | Admin | Manager, Agent | | Manager, Agent | Nobody | Until they accept, the invitation shows as pending. Pending invitations do not count as active members. ## Changing a role **Settings → Team**, then change the role on a member. Two rules: - **The owner cannot be changed here.** *"The workspace owner cannot be changed here."* - **An admin cannot manage another admin.** *"Only the owner can manage admins."* A role change takes effect immediately — the person does not need to sign out. ## Removing someone Removing a member ends their access at once. Their past messages stay in the conversations, attributed to them, because removing a person should not rewrite history. Conversations assigned to them stay assigned until somebody reassigns them. Check that after removing anyone who was carrying a queue. **Remove people the day they leave.** An account nobody is watching is the one that gets misused. ## Team size and your plan How many people can be in a workspace depends on the plan. When the limit is reached, invitations are refused until a seat frees up or the plan changes. Pending invitations may count toward the limit — cancel ones that were never accepted. ## Choosing roles well **Agent is the right default.** Start people there and raise them when they need more. **Few admins.** Admin can disconnect WhatsApp. That should be a small number of people who know what it means. **Manager for whoever sends campaigns.** The ability to message every customer at once belongs with people who understand what that costs. ## Next - [Settings](https://onpad.in/docs/settings) — the workspace details everyone shares - [Plans and billing](https://onpad.in/docs/plans-and-billing) — the owner's area --- # Settings Source: https://onpad.in/docs/settings Settings holds everything about the workspace and about you. Sections you cannot change are hidden rather than shown greyed out, so what you see depends on your role. ## Company The workspace's own details: - **Organisation name** — what your business is called inside ONPAD - **Category** — shown on your WhatsApp business profile - **Country** - **Timezone** **Timezone is the one to check.** Scheduled campaigns run in it. A campaign set for 10am goes at 10am in the workspace's timezone, whatever time it is where you are. ## My profile Your own name and personal details, separate from the workspace. Changing your name here changes how you appear to your teammates in the inbox. ## WhatsApp connection The state of your connection, and the business profile customers see. ### The profile - **About** — the short line under your business name - **Description** — a longer explanation of what you do - **Address** - **Email** - **Websites** — up to two - **Category** - **Profile picture** These are stored by **Meta**, not by ONPAD. Saving sends them to Meta, and they appear on your business in WhatsApp. Fill them in. A business profile with nothing in it looks abandoned, and it is the first thing a customer sees when they tap your name. ### Reconnecting If the connection breaks — an expired token, a number removed at Meta's end — reconnect from here. Nothing in the workspace is lost; the contacts, conversations and templates all stay. ### Syncing templates Owners and admins can sync templates with Meta on demand, which pulls the current status of every template. ONPAD keeps these in step automatically, so the button is for when you have just made a change at Meta's end and do not want to wait. ## Notifications Which alerts you receive, and where. These are **per person**, not per workspace — your choices do not change your teammates'. ## Security Your password and account access. If you signed up with Google there is no password until you set one. Setting one does not switch Google sign-in off; it adds a second way in. ## Developer API Where API keys live. See the [API overview](https://onpad.in/docs/api) for how to use them. - **Create a key** and name it for the thing that will use it. - **Copy it immediately.** Only a prefix is stored afterwards. The full key is shown once. - **Revoke** a key to kill it instantly. Below the keys is a log of recent API requests — method, path, status code, IP and which key was used. This is the first place to look when an integration stops working. **API access is a plan feature.** If your plan does not include it, this section says so, and every API request returns `401`. ## Logs Recent activity in the workspace. Useful for answering "who changed that" without guessing. ## What lives elsewhere **Plans and billing** has its own area and is **owner only**. See [Plans and billing](https://onpad.in/docs/plans-and-billing). **Team** is covered in [Team and roles](https://onpad.in/docs/team-and-roles). ## Next - [Team and roles](https://onpad.in/docs/team-and-roles) - [Plans and billing](https://onpad.in/docs/plans-and-billing) - [Data and privacy](https://onpad.in/docs/data-and-privacy) --- # Plans and billing Source: https://onpad.in/docs/plans-and-billing Plans and billing is **owner only**. No other role can see or change it. ## The trial Every new account gets a **7-day free trial**, and it is **one per person, not one per workspace** — a second workspace does not start a second trial. No card is needed to start. When the trial ends without a plan, the workspace becomes **read-only**. ## Read-only Read-only means sending stops. You can still sign in, read every conversation, export your contacts and look at your templates — nothing is deleted and nothing is hidden. What stops: - Sending messages from the inbox - Running campaigns - Sending through the API — every send returns `403 workspace_read_only` The message you will see: > Your trial has ended. This workspace is read-only. Choose a plan to resume sending and editing. Choosing a plan lifts it immediately. ## Subscription states | State | Meaning | |---|---| | **Trialing** | On the free trial | | **Active** | Paid and current | | **Authenticated** | The mandate is set up, first charge pending | | **Grace** | A payment failed; you have a few days before sending stops | | **Past due** | The grace period ran out. Read-only | | **Cancelled** | Ended | **Grace** is the one worth knowing about: a failed payment does not stop you instantly. There is a short grace period — 3 days by default — to fix the card before the workspace goes read-only. ## Choosing or changing a plan Open **Plans & billing** and pick one. Prices, limits and what each plan includes are shown there, because those change and a documentation page quoting them would eventually lie to you. What varies between plans: contacts stored, messages sendable through campaigns and the API, team seats, and which features are switched on — including **API access**, which not every plan includes. ### One checkout at a time If a checkout is already pending with the payment provider, other plans are unavailable until it completes or is abandoned. Finish or cancel the one in progress rather than starting a second — two mandates on one account is a mess to unpick. ## Meta's bill is separate Worth repeating because it causes the most confusion: - **ONPAD** charges the subscription for the software. - **Meta** charges for the WhatsApp messages, billed directly to your own WhatsApp Business Account. ONPAD does not collect Meta's charges, does not mark them up, and cannot refund them. **An active ONPAD plan does not keep messages flowing if Meta has no valid payment method.** Meta stops delivering on its own, and messages fail with a payment reason. Fix that in Meta Business Manager. See [What it costs](https://onpad.in/docs/what-it-costs), which also covers the **31 December 2026 INR migration deadline** for Indian businesses. ## Cancelling Cancel from Plans & billing. The workspace becomes read-only when the paid period ends — your data stays, sending stops. For a refund, email [support@onpad.in](mailto:support@onpad.in) with the payment reference. ## If a payment is taken but the plan does not change Usually a few minutes' delay while the provider confirms. If the money has left your account and nothing changed after that, email [support@onpad.in](mailto:support@onpad.in) with the payment reference — not a screenshot of the bank app, the reference. ## Next - [What it costs](https://onpad.in/docs/what-it-costs) — Meta's side of the bill - [Team and roles](https://onpad.in/docs/team-and-roles) — who can see this area --- # Data and privacy Source: https://onpad.in/docs/data-and-privacy ## What ONPAD stores For your workspace: contacts, conversations and their messages, templates, campaigns and their results, automations, AI Agent settings, team members, and logs of activity and API requests. Messages are stored so the inbox works — a shared inbox that forgets yesterday is not an inbox. ## Who can see it **Your team**, according to their roles. An agent sees conversations; only the owner sees billing. See [Team and roles](https://onpad.in/docs/team-and-roles). **Workspaces are separate.** Nothing is shared between them. A contact in one does not appear in another, even with the same phone number and the same owner. **ONPAD staff** can access workspace data only where support requires it, and such access is logged. ## Credentials The access token Meta issues when you connect WhatsApp is stored **encrypted**. It is used to send and receive on your behalf and for nothing else. **Your Facebook password is never seen by ONPAD.** The connection runs through Meta's own Embedded Signup — you sign in to Meta, and Meta hands ONPAD a token. API keys are stored as a **hash**, not as the key. That is why the full key is shown only once: ONPAD genuinely cannot show it again. ## What belongs to you **Your WhatsApp Business Account is yours.** It lives in your own Meta Business Manager. If you leave ONPAD, the account and the number stay with you — you disconnect ONPAD and connect something else. **Your contacts and conversations are yours.** Export contacts as CSV whenever you want. ONPAD is software you use, not a place your WhatsApp presence is locked inside. ## Meta also has the data Every message goes through Meta's WhatsApp Business Cloud API, so Meta has it too, under its own terms. That is true of every WhatsApp Business platform — it is how the official API works. Meta's data handling is Meta's, and no platform can change it. ## Getting your data out **Contacts** — export as CSV from Contacts at any time. **Everything else**, or a full copy, or deletion of an account and its data: email [support@onpad.in](mailto:support@onpad.in) **from the owner's address**. Requests from any other address are not actioned, because that is how accounts get taken. ## Deleting a workspace Deleting removes the workspace and its data. Before you do: 1. **Export your contacts.** They are not recoverable afterwards. 2. **Disconnect at Meta's end too, if you are leaving entirely** — deleting the ONPAD workspace does not delete your WhatsApp Business Account, which is correct, because that account is yours. ## Good habits **Remove people the day they leave.** An unwatched account is the one that gets misused. **One API key per integration.** Revoking one then does not break the others. **Never put an API key in browser code or a public repository.** Anyone holding it can message your customers from your number. **Do not ask customers for card numbers, passwords or ID numbers over WhatsApp.** Meta rejects templates that do, and it trains your customers to be phished. ## Next - [Settings](https://onpad.in/docs/settings) — where keys and profile details live - [Team and roles](https://onpad.in/docs/team-and-roles) — who can see what --- # A message was not delivered Source: https://onpad.in/docs/message-not-delivered Work down this page in order. The first three causes account for most failures. ## 1. Is the number right? **"Invalid phone number"** means Meta could not use it. Check the number in full international form — `919876543210`, not `9876543210`. After separators are stripped it must be 8 to 15 digits. The usual cause is a **CSV import with the wrong default country code**. Export your contacts and look at what the numbers actually became. If 10-digit numbers stayed 10 digits, the country code was never applied, and every one of them will fail. ## 2. Is the number on WhatsApp? **"Not on WhatsApp"** means exactly that. The number exists, somebody answers it, and it has no WhatsApp account. Nothing to fix. Mark the contact or remove it so you stop paying for the attempt. ## 3. Can Meta charge you? **A payment reason** means Meta has no valid payment method on your WhatsApp Business Account and has stopped delivering. This is **Meta's bill, not ONPAD's**. An active ONPAD plan does not help. Open Meta Business Manager, find your WhatsApp Business Account, and fix the payment method there. For Indian businesses there is a second version of this: accounts that have not migrated to **INR billing by 31 December 2026** can see delivery disrupted from 1 January 2027. See [What it costs](https://onpad.in/docs/what-it-costs). ## 4. Is the template still approved? **"Template not approved"**, or a campaign that worked last week and fails now. Meta can **pause** a template after it has been approved, when too many recipients block or report. Open Templates and look at its status: - **Paused** — temporary, but do not just wait it out. Something about the message made people react badly. - **Disabled** — permanent. Write a new one. See [Templates](https://onpad.in/docs/templates). ## 5. Have you hit the messaging limit? **"Messaging limit reached"** means Meta's cap on how many *different* customers your number may start a conversation with in 24 hours. New numbers start low. The limit rises on its own as you send messages people welcome. Send in smaller batches, use the campaign throttle, and spread a large list over several days. See [Messaging limits and quality](https://onpad.in/docs/messaging-limits). ## 6. Was the window open? **"The 24-hour reply window has closed"** when sending free text from the inbox or `type: "text"` through the API. Free text is only allowed within 24 hours of the customer's last message. After that, only an approved template gets through. This is Meta's rule and nothing changes it. ## 7. Is WhatsApp still connected? If **everything** fails rather than some things, check the connection in Settings. An expired Meta token fails every send with the same error. Reconnect from the setup page. Nothing is lost. --- ## Stuck at "Sent" and never delivered Not a failure. `sent` means Meta accepted it and is trying. A phone that is switched off, out of coverage or has no storage left will not receive until it comes back. Meta retries for up to 30 days. Nothing to do but wait — or reach the person another way. ## Delivered but never read Also not a failure. `read` only appears when the recipient has **read receipts switched on**, and many people do not. A low read rate across a campaign usually says more about read receipts than about your message. Judge campaigns by **replies**, not reads. ## It worked for one person and failed for another Then the problem is the specific contact, not the setup. Check that one number against causes 1, 2 and 6 above. ## Everything suddenly fails Four things fail *everything* at once: 1. **Meta payment problem** — most likely 2. **The connection broke** — expired token 3. **The number was paused by Meta** for a red quality rating 4. **The workspace went read-only** — unpaid plan, which returns `403` on the API Check in that order. The first two cover most cases. ## None of this fixed it Email [support@onpad.in](mailto:support@onpad.in) with: - The **campaign or message id** - The **recipient number** - The **exact error text** shown on the row - Roughly **when** it happened Every send is logged, so those four things let us find it. A screenshot of the whole screen is less useful than the error text. ## Related - [Messaging limits and quality](https://onpad.in/docs/messaging-limits) — the limit and the rating behind many failures - [Why a template was rejected](https://onpad.in/docs/template-rejected) - [What it costs](https://onpad.in/docs/what-it-costs) — Meta's billing, and the INR deadline --- # Why a template was rejected Source: https://onpad.in/docs/template-rejected Rejection is normal. Most businesses have one rejected before they have five approved, and there is no penalty for resubmitting. But **change something real between attempts**. Resubmitting the same text gets the same answer, a day later. ## 1. It reads like an advertisement The most common reason by far. What Meta objects to: - CAPITALS for emphasis - Multiple exclamation marks - "FREE", "LIMITED TIME", "ACT NOW", "HURRY" - Manufactured urgency - Heavy emoji **Fix:** write it as you would to one customer, not to a crowd. ```text Rejected: 🔥🔥 HUGE SALE!!! 50% OFF EVERYTHING!!! HURRY LIMITED TIME!!! 🔥🔥 Approved: Hi {{1}}, our seasonal sale starts today. Everything in store is 50% off until Sunday. Reply STOP to opt out. ``` Same offer. One is a shout, the other is a message. ## 2. Wrong category A promotional message submitted as **Utility**. Utility means something the customer **already did** — an order update, a reminder, a receipt. If the message carries an offer, or tells them about something they did not ask for, it is **Marketing**. Choosing Utility does not make it cheaper. Meta re-categorises templates it disagrees with, and often rejects them instead. ## 3. Sample values that say nothing Every variable needs a sample value, and Meta reads them to understand what the template does. ```text Rejected: {{1}} = "xxx", {{2}} = "test", {{3}} = "abc" Approved: {{1}} = "Priya", {{2}} = "#10482", {{3}} = "Friday" ``` Real samples also catch your own mistakes — a template whose samples read sensibly usually reads sensibly to the customer too. ## 4. The language does not match Hindi text submitted as `en_US`, or Hinglish submitted as `hi`. Set the language to what the text actually is. For Hinglish, `en` is usually closer than `hi`. ## 5. A URL Meta cannot verify - Link shorteners (`bit.ly` and similar) are frequently refused - A domain with no visible connection to your business - A URL that does not resolve **Fix:** use your own domain, and make sure the page exists before submitting. ## 6. Asking for sensitive information Card numbers, CVVs, passwords, OTPs the customer sends *to* you, government ID numbers. Meta rejects these outright, and it is right to — it is exactly what a phishing message looks like. **Fix:** send a link to a secure page instead of asking for the data in chat. ## 7. Variables placed badly Three rules: - Variables cannot touch: `{{1}}{{2}}` is rejected - The body cannot **start** with a variable - The body cannot **end** with a variable ```text Rejected: {{1}}, your order is ready Approved: Hi {{1}}, your order is ready ``` ## 8. Empty or near-empty content A body that is almost entirely variables gives Meta nothing to review. There must be enough fixed text to show what the message is. ## 9. It looks like a different business The template mentions a brand, a company name or a service that is not yours. Meta checks this against your verified business name. This also catches **ready-made templates used as-is** — the example business details in the template library are placeholders. Replace them before submitting. ## Authentication templates These are rejected much less often, because Meta writes the body itself: ```text {{1}} is your verification code. ``` You cannot change the wording, add a header or footer, or add your own buttons. If an authentication template is rejected, it is almost always because the content should not have been authentication at all — this category is for one-time passcodes only. ## After the fix Edit and resubmit. Usually a decision within minutes. There is no queue position to lose and no limit on attempts. But repeated rejections of the same kind do affect your account standing with Meta, so treat the third rejection as a sign to change approach, not wording. ## A template that was approved and is now paused Different problem. Meta **paused** it after approval because recipients blocked or reported it. Do not resubmit the same text. Ask why people reacted badly: - Sent too often? - Sent to people who never asked to hear from you? - Did the message deliver what its opening line promised? A template paused twice usually ends up disabled. See [Templates](https://onpad.in/docs/templates). ## Related - [Your first template](https://onpad.in/docs/your-first-template) — creating one - [Templates](https://onpad.in/docs/templates) — kinds, limits and statuses - [Messaging limits and quality](https://onpad.in/docs/messaging-limits) — what pauses are warning you about --- # Messaging limits and quality Source: https://onpad.in/docs/messaging-limits Two Meta controls decide how much you can send and whether you keep sending at all. Neither is set by ONPAD, and no plan changes them. ## The messaging limit How many **different customers** your number may start a conversation with in a rolling 24 hours. It counts conversations you start — templates and campaigns. **Replying inside an open 24-hour window does not count against it**, which is one more reason to answer people while the window is open. New numbers start at the lowest tier and rise automatically as they send messages people welcome. Business verification with Meta raises the ceiling further. When you hit it, sends fail with "messaging limit reached". Nothing is broken — the remaining messages simply have to wait. ### Working within it **Split large campaigns across days.** A list bigger than your limit was always going to take more than one day. **Use the campaign throttle.** Spreading a send over an hour is gentler than a burst, and leaves your inbox able to cope with the replies. **Check the limit before a big send**, not after a thousand failures. ## The quality rating Green, amber or red, based on how recipients react to you. Blocks and reports push it down; being ignored does not. | Rating | What it means | |---|---| | **Green** | Healthy | | **Amber** | Customers are reacting badly. A warning | | **Red** | Serious. The number can be paused | A red rating can **pause your number**, and a paused number sends nothing at any price. This is the single worst thing that can happen to a WhatsApp Business account, and it is entirely preventable. ### What damages it 1. **Messaging people who never gave you their number.** Bought lists are the fastest route to red. 2. **Sending too often.** The same marketing template weekly to the same people. 3. **Ignoring opt-outs.** Someone who said STOP and hears from you again reports you. 4. **Messages that do not match their opening line.** An "order update" carrying an offer gets reported. 5. **Sending at bad hours.** A marketing message at 11pm gets blocked far more than the same message at 11am. ### What protects it **Only message people who expect you.** This one rule prevents most problems. **Make opting out easy and honour it immediately.** A footer saying "Reply STOP to opt out" costs you nothing — ONPAD excludes opted-out contacts from every campaign automatically. **Send at sensible hours.** Use the campaign send window. **Prefer utility over marketing.** Order updates get welcomed. Offers get tolerated at best. **Watch amber.** Amber is the warning before red. React to it rather than hoping. ## Template pauses are the early signal Meta pauses individual templates before it touches your number. A paused template is telling you which message people disliked, while the rest of your account is still fine. Treat a pause as information, not an obstacle. Resubmitting the same text and getting it paused again is how numbers end up red. ## If your number is paused 1. **Stop sending.** Everything, including campaigns scheduled for later. 2. **Find out what caused it.** Look at what you sent in the days before — a particular campaign, a particular list, a particular template. 3. **Fix the cause before resuming.** A pause that is waited out rather than understood comes back. 4. **Restart small.** Utility messages to engaged customers, not the whole list. Recovery takes time, and the rating rises only as you send messages people welcome. There is no way to buy it back. ## Business verification Verifying your business with Meta raises your ceiling and is worth doing once you are sending regularly. It happens in Meta Business Manager, not in ONPAD, and Meta asks for documents showing the business is real and that the name matches. The **display name must match your registered business name** — a mismatch is the usual reason verification fails. ## Related - [A message was not delivered](https://onpad.in/docs/message-not-delivered) - [Why a template was rejected](https://onpad.in/docs/template-rejected) - [Campaigns](https://onpad.in/docs/campaigns) — throttle and send window --- # Connection problems Source: https://onpad.in/docs/connection-problems ## It will not connect in the first place ### "This number is already registered on WhatsApp" The number is still active on WhatsApp Messenger or the WhatsApp Business app. A number can only live in one place at a time. 1. Open WhatsApp on the phone holding that number. 2. **Export anything you need first** — chats do not come across. 3. Delete the WhatsApp account on that number (Settings → Account → Delete my account). 4. Wait a few minutes. 5. Try connecting again. ### The verification code never arrives - Check the number can receive **SMS from international senders**. Some prepaid plans block them. - Try the **voice call** option instead. Landlines and some VoIP numbers reject automated SMS but answer calls. - Make sure the number is **active and in coverage** right now. - Check you entered the number with the right country code. ### Your business is not in the list You are signed in to Facebook as a person who is not an admin of that Business Portfolio. Sign out of Facebook, sign in as an account that is, and start again. ### The display name was rejected Meta requires the name to relate to the business. Generic names, category names and promotional phrases are refused. "Sunrise Store" works. "Best Offers Daily" does not. Use your registered business name. ### The Meta window closed by itself Start again from the beginning. A half-finished signup leaves nothing broken behind, though the number may show Pending — see below. ### "Could not reach Meta" A network problem between our server and Meta. Wait a minute and try again. If it persists it is on our side, not yours. Email [support@onpad.in](mailto:support@onpad.in). ## The number shows "Pending" in Meta Meta accepted the number but Cloud API registration did not finish — usually because the window was closed early or verification timed out. On the setup page, open **"Number still shows Pending in Meta?"** and choose **Register number**. ONPAD creates the two-step verification PIN and completes registration. If it still will not complete, the number needs to be removed from the WhatsApp Business Account in Meta Business Manager and connected again. ## It was connected and stopped working ### "The Meta access token has expired. Reconnect WhatsApp and try again." Meta's token is no longer valid. Reconnect from Settings → WhatsApp connection. **Nothing is lost.** Contacts, conversations, templates and campaigns all stay. The connection is the only thing being replaced. ### "Connect WhatsApp before syncing message templates." The workspace has no connected number at all — either it was never connected, or the connection was removed at Meta's end. Connect from the setup page. See [Connect WhatsApp](https://onpad.in/docs/connect-whatsapp). ### Everything fails but the connection looks fine Check these in order: 1. **Meta payment method.** The most common cause. An ONPAD plan does not cover Meta's bill. 2. **The number's status at Meta.** A red quality rating can pause it. See [Messaging limits and quality](https://onpad.in/docs/messaging-limits). 3. **Your ONPAD plan.** A read-only workspace blocks sending and returns `403` on the API. ### Templates are not syncing Owners and admins can sync templates with Meta on demand from Settings. If the sync errors, the message says why — usually the token again. ## The stored credential is invalid > The stored WhatsApp credential is invalid. Reconnect the number. Rare. The encrypted token could not be read back, so sending cannot continue. Reconnecting fixes it and loses nothing. If it recurs after a successful reconnect, tell us — that is a server-side problem, not something you can fix. ## Before contacting support Have these ready: - The **phone number** being connected, with country code - **What you see** — the exact error text - **Which step** it fails at: Meta login, selecting the business, or verification - Whether the number was **previously on WhatsApp**, and whether you deleted that account That last one answers most cases before we look anything up. Email [support@onpad.in](mailto:support@onpad.in). ## Related - [Before you start](https://onpad.in/docs/before-you-start) — the prerequisites most failures come from - [Connect WhatsApp](https://onpad.in/docs/connect-whatsapp) — the flow itself --- # API overview Source: https://onpad.in/docs/api The ONPAD API lets your own software send WhatsApp messages — from your website, your CRM, your order system or a script. It is a small API on purpose. Two resources, JSON in and JSON out, bearer authentication. ## Base URL ```text https://app.onpad.in/api/v1 ``` ## Endpoints | Method | Path | What it does | |---|---|---| | `POST` | `/messages` | [Queue a message](https://onpad.in/docs/api/send-message) for delivery | | `GET` | `/messages?id=` | [Look up a message](https://onpad.in/docs/api/get-message) you sent | | `GET` | `/status` | [Check the connection](https://onpad.in/docs/api/status) and your workspace | A machine-readable [OpenAPI specification](https://onpad.in/docs/openapi.json) is available. Hand it to Codex, Claude or any API client and it will generate correct calls. ## Authentication Every request carries an API key as a bearer token: ```text Authorization: Bearer wh_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ``` Keys always start with `wh_live_`. There is no sandbox key — see [Testing](#testing) below. ### Getting a key 1. Open **Settings** in your workspace. 2. Find the **API keys** section. 3. Create a key and give it a name you will recognise later. 4. **Copy it immediately.** Only a short prefix is stored afterwards, so the full key is shown once and cannot be retrieved again. Lose it and you create a new one. Keys belong to a workspace, not to a person. A key keeps working after the person who created it leaves. ### Keeping a key safe - Keep it on your server. Never put it in browser JavaScript, a mobile app, or a public repository — anyone holding it can message your customers from your number. - Use a separate key per integration, so revoking one does not break the others. - Revoke a key the moment you suspect it leaked. Revoking is immediate. Every request is logged with its key, method, path, status code and IP address. You can see this under API keys in Settings — useful when you need to know what a key has been doing. ## The API is a plan feature API access is switched on by your plan. If your plan does not include it, every request returns `401 invalid_api_key` — the same response as a bad key, because the API does not reveal which workspaces exist. If your key is definitely correct and you still get 401, check **Plans & billing** first. ## How sending works `POST /messages` does not send the message during the request. It validates everything, stores the message, and returns **`202 Accepted`** with an id. A background worker then delivers it, usually within seconds, and retries on failure: - Up to **3 attempts**. - Backoff of **15s, 30s, 60s**, capped at 5 minutes. - A permanent error — an invalid number, an unapproved template — fails immediately without retrying, because retrying cannot help. Poll `GET /messages?id=` for the outcome, or watch the inbox. This is why validation errors come back instantly as `422` while delivery failures appear later as a `failed` status: everything knowable up front is checked up front. ## Rules that still apply The API does not bypass WhatsApp's rules. Everything in [WhatsApp Business API](https://onpad.in/docs/whatsapp-business-api) still holds: - **Free text only inside the 24-hour window.** `type: "text"` is rejected with `422` if the customer has not messaged you in the last 24 hours. - **Templates must be approved.** Sending an unapproved or non-existent template is a `422`. - **Messaging limits are Meta's.** A send that exceeds them fails at delivery, not at the API. ## Testing There is no sandbox. Keys are live, and a message sent is a message delivered and charged by Meta. To test safely: 1. Send to **your own number** first. 2. Use a template you created for testing. 3. Check the response id, then poll `GET /messages?id=` and watch the status move. ## Conventions **Everything is JSON.** Send `Content-Type: application/json`. A malformed body returns `400 invalid_json`. **Phone numbers go in full international form**, digits only, 8 to 15 of them. `919876543210` is right. `+91 98765 43210` also works — separators are stripped — but `9876543210` without a country code is not, because the API will not guess a country for you. **Timestamps are ISO 8601 with a timezone**, for example `2026-10-04T09:21:33+05:30`. **Every response has an `ok` field.** `true` on success, `false` on error with an `error` code and a human `message`. ## Next - [Send a message](https://onpad.in/docs/api/send-message) — the main endpoint, field by field - [Idempotency](https://onpad.in/docs/api/idempotency) — why every send needs a key, and what it protects you from - [Errors](https://onpad.in/docs/api/errors) — every code the API returns - [Code examples](https://onpad.in/docs/api/examples) — curl, PHP, Node.js and Python --- # Send a message Source: https://onpad.in/docs/api/send-message Queues a WhatsApp message for delivery and returns immediately with an id to track it. ```text POST https://app.onpad.in/api/v1/messages ``` ## Headers | Header | Required | Value | |---|---|---| | `Authorization` | Yes | `Bearer wh_live_...` | | `Content-Type` | Yes | `application/json` | | `Idempotency-Key` | **Yes** | A unique key for this send, 8–120 characters | `Idempotency-Key` is required, not optional. Without it the request is rejected with `422`. It is what stops a retried request from sending the same message twice — see [Idempotency](https://onpad.in/docs/api/idempotency). Allowed characters in the key: letters, digits, `.`, `_`, `:` and `-`. ## Body ### Common fields | Field | Type | Required | Description | |---|---|---|---| | `to` | string | Yes | Recipient in full international form, digits only, 8–15 digits. Separators are stripped, so `+91 98765 43210` is accepted | | `type` | string | No | `template` (default) or `text` | ### When `type` is `template` | Field | Type | Required | Description | |---|---|---|---| | `template.name` | string | Yes | The approved template's name. Lowercase letters, digits and underscores, up to 512 characters | | `template.language` | string | No | Language code, default `en_US`. Must match the approved template | | `template.parameters` | array | Yes, if the template has variables | Values for `{{1}}`, `{{2}}` … in order. Maximum 20, each 1–1024 characters, text or number | The count must match the template exactly. A template with `{{1}}` and `{{2}}` needs two parameters — one or three is a `422`. > Templates with an **image, video, document or location header** are not supported by this endpoint yet. Use a campaign for those. ### When `type` is `text` | Field | Type | Required | Description | |---|---|---|---| | `text.body` | string | Yes | The message, 1–4096 characters. `body` at the top level also works | Free text is only allowed inside the **24-hour customer service window** — that is, when the recipient has messaged you in the last 24 hours. Outside it, the request is rejected with `422` and you must send a template instead. ## Example request ```bash curl -X POST https://app.onpad.in/api/v1/messages \ -H "Authorization: Bearer wh_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: order-10482-shipped" \ -d '{ "to": "919876543210", "type": "template", "template": { "name": "order_shipped", "language": "en_US", "parameters": ["Priya", "#10482", "Friday"] } }' ``` > `919876543210` throughout these docs is a **placeholder**, not a test number. There is no reserved range in India — whoever owns a number receives whatever you send, and Meta charges you for it. Replace it with your own number before running anything. ## Response `202 Accepted` when the message is queued: ```json { "ok": true, "duplicate": false, "message": { "id": "6f1b9a2c-4d7e-4a31-9f08-2b5c7d1e3a40", "to": "+919876543210", "type": "template", "status": "queued", "meta_message_id": null, "attempts": 0, "error": null, "created_at": "2026-10-04T09:21:33+05:30", "sent_at": null, "delivered_at": null, "read_at": null, "status_url": "https://app.onpad.in/api/v1/messages/6f1b9a2c-4d7e-4a31-9f08-2b5c7d1e3a40" } } ``` `200 OK` with `"duplicate": true` when this `Idempotency-Key` was already used for an identical request. The original message is returned and **nothing is sent again**. ### Fields in the response | Field | Description | |---|---| | `id` | The ONPAD message id. Use it with [GET /messages](https://onpad.in/docs/api/get-message) | | `to` | The recipient, normalised with a leading `+` | | `status` | `queued`, `processing`, `sent`, `delivered`, `read` or `failed` | | `meta_message_id` | Meta's own id, available once sent | | `attempts` | How many delivery attempts have been made | | `error` | The failure reason, when `status` is `failed` | | `created_at`, `sent_at`, `delivered_at`, `read_at` | ISO 8601 timestamps, `null` until each happens | `202` means accepted, not delivered. Delivery happens in the background — poll for the outcome. ## Status codes | Code | Meaning | |---|---| | `202` | Queued | | `200` | Duplicate of an earlier identical request | | `400` | `invalid_json` — the body is not valid JSON | | `401` | `invalid_api_key` — missing, malformed, revoked, or the plan does not include API access | | `403` | `workspace_read_only` — the workspace is read-only, usually unpaid billing | | `405` | `method_not_allowed` — only `GET` and `POST` are accepted here | | `409` | This `Idempotency-Key` was used for a **different** request body | | `422` | `message_rejected` — a validation problem; the `message` field says which | | `500` | `internal_error` — our fault; the message was not queued | Every `422` message is specific. See [Errors](https://onpad.in/docs/api/errors) for the full list and what each one means. ## Notes **The recipient becomes a contact.** Sending to a new number creates a contact in your workspace, so the conversation appears in the inbox and replies land there. **Sending does not check opt-out.** If you maintain an opt-out list, check it before calling the API — ONPAD does not block the send for you. **One message per request.** To message many people, loop. There is no bulk endpoint; use a campaign for large sends, which is faster and gives you per-recipient reporting. --- # Look up a message Source: https://onpad.in/docs/api/get-message Returns the current state of a message you sent through the API. ```text GET https://app.onpad.in/api/v1/messages?id={id} ``` ## Parameters | Parameter | In | Required | Description | |---|---|---|---| | `id` | query | Yes | The message id returned by [POST /messages](https://onpad.in/docs/api/send-message) | ## Example ```bash curl "https://app.onpad.in/api/v1/messages?id=6f1b9a2c-4d7e-4a31-9f08-2b5c7d1e3a40" \ -H "Authorization: Bearer wh_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ``` ## Response ```json { "ok": true, "message": { "id": "6f1b9a2c-4d7e-4a31-9f08-2b5c7d1e3a40", "to": "+919876543210", "type": "template", "status": "delivered", "meta_message_id": "wamid.HBgMOTE5ODc2NTQzMjEwFQIAERgSMUY4...", "attempts": 1, "error": null, "created_at": "2026-10-04T09:21:33+05:30", "sent_at": "2026-10-04T09:21:35+05:30", "delivered_at": "2026-10-04T09:21:37+05:30", "read_at": null } } ``` ## Statuses | Status | Meaning | |---|---| | `queued` | Accepted, waiting for the worker | | `processing` | Being sent to Meta right now | | `sent` | Meta accepted it and is delivering | | `delivered` | It reached the recipient's phone | | `read` | The recipient opened it | | `failed` | It did not go. `error` says why | `read` only appears if the recipient has read receipts switched on. Plenty of people do not, so absence of `read` says nothing about whether the message was seen. ## Status codes | Code | Meaning | |---|---| | `200` | Found | | `401` | `invalid_api_key` | | `404` | `message_not_found` — no such id in this workspace | | `422` | `missing_message_id` — the `id` parameter was not provided | A message belonging to a different workspace returns `404`, not `403` — the API does not confirm that an id exists somewhere else. ## How to poll Delivery usually completes within seconds, but a switched-off phone can delay it for hours. A reasonable approach: 1. Wait 2 seconds after the `202`, then check. 2. If still `queued` or `processing`, check again after 5 seconds, then 15, then 30. 3. Once `sent`, the message is with Meta — `delivered` may follow at any time, or much later. 4. Stop polling at `delivered`, `read` or `failed`. Those are final as far as the API is concerned. Do not poll in a tight loop. Nothing changes faster than the worker runs, and every call is logged against your key. If you need delivery updates pushed to you rather than polled, say so — webhooks are planned and knowing who needs them decides the order they arrive in. --- # Check status Source: https://onpad.in/docs/api/status Confirms an API key works and reports the workspace and WhatsApp connection behind it. The cheapest way to test an integration before sending anything. ```text GET https://app.onpad.in/api/v1/status ``` ## Example ```bash curl https://app.onpad.in/api/v1/status \ -H "Authorization: Bearer wh_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ``` ## Response ```json { "ok": true, "workspace": { "id": 128, "name": "Sunrise Store", "slug": "sunrise-store", "country": "India", "timezone": "Asia/Kolkata" }, "whatsapp": { "status": "connected", "phone_number": "919876543210", "verified_name": "Sunrise Store" }, "server_time": "2026-10-04T09:21:33+05:30" } ``` ## Fields | Field | Description | |---|---| | `workspace.id` | Numeric workspace id | | `workspace.name` | The workspace name | | `workspace.slug` | URL-safe version of the name | | `workspace.country`, `workspace.timezone` | Used for scheduling and formatting | | `whatsapp.status` | `connected`, `not_started`, `pending` or `error` | | `whatsapp.phone_number` | The connected number, digits only | | `whatsapp.verified_name` | The display name Meta approved | | `server_time` | Our clock, ISO 8601 — useful for checking clock drift on your side | ## Status codes | Code | Meaning | |---|---| | `200` | The key is valid | | `401` | `invalid_api_key` — bad, revoked, or the plan does not include API access | ## Use it for **A deploy check.** Call it after deploying an integration. A `200` with `whatsapp.status: "connected"` means sending will work. **Diagnosing a 401.** If `/status` also returns `401`, the problem is the key or the plan — not the message you were trying to send. **Checking the connection before a batch.** `whatsapp.status` other than `connected` means every send will fail. Check once rather than discovering it a thousand failures later. This endpoint does not send anything and costs nothing. --- # Idempotency Source: https://onpad.in/docs/api/idempotency Every `POST /messages` request **must** carry an `Idempotency-Key` header. It is the difference between a retry that is safe and a retry that messages your customer twice. ## The problem it solves Your server posts a message. The network drops before the response arrives. Your code does not know whether the message was queued or not. Without idempotency you have two bad choices: retry and risk sending twice, or do not retry and risk not sending at all. With an idempotency key, retrying is simply safe. The second request returns the first one's result and sends nothing. ## How it works ```text Idempotency-Key: order-10482-shipped ``` Rules: 8 to 120 characters, made of letters, digits, `.`, `_`, `:` and `-`. When a request arrives, ONPAD looks for an earlier message in your workspace with the same key: - **No earlier message** → the message is queued. `202 Accepted`. - **Earlier message, identical body** → the original is returned with `"duplicate": true`. `200 OK`. Nothing new is sent. - **Earlier message, different body** → `409`, with *"This Idempotency-Key was already used for a different request."* Nothing is sent. The comparison is on the whole request body, normalised so that key order does not matter. `{"to":"91...","type":"text"}` and `{"type":"text","to":"91..."}` count as the same request. Keys are scoped to your workspace. Another workspace using the same string does not collide with yours. ## Choosing a key **Use something from your own data that identifies this exact send.** The best keys are derived, not random, because a derived key is the same on a retry: ```text order-10482-shipped invoice-2026-0931-reminder booking-77341-confirmation-2 appointment-5521-reminder-24h ``` **Do not use a fresh random string per attempt.** A new UUID on every retry defeats the whole mechanism — each attempt looks like a new message and each one sends. **Do not reuse a key for a different message.** Sending `order-10482-shipped` and later reusing it for a delivery notification gets a `409`, and the second message never goes. If one order genuinely needs several messages, put the purpose in the key: `order-10482-shipped`, `order-10482-delivered`. ## Retrying correctly ```python key = f"order-{order_id}-shipped" for attempt in range(3): try: response = post_message(key, payload) break except NetworkError: time.sleep(2 ** attempt) ``` The key is computed **once, outside the loop**. Every attempt carries the same one, so at most one message is ever sent, no matter how many attempts run. ## What it does not do **It does not retry delivery for you.** It makes your retries safe. Delivery retries happen separately inside ONPAD — 3 attempts with backoff. **It does not expire quickly.** Keys are kept with the message. Reusing a key from months ago still returns that old message rather than sending. **It does not protect against your own duplicate logic.** Two different code paths that build different keys for the same event will both send. Derive the key from the event, not from where you are in the code. ## If you get a 409 You reused a key with a different body. Two possibilities: 1. **The key is too generic** — something like `order-10482` used for several different messages about that order. Make it specific. 2. **The body changed between attempts** — a timestamp or a random value inside the payload, so the retry no longer matches. Build the payload once and reuse it, exactly like the key. --- # Errors Source: https://onpad.in/docs/api/errors Every error has the same shape: ```json { "ok": false, "error": "message_rejected", "message": "This template requires exactly 2 parameter(s)." } ``` `error` is a stable code you can branch on. `message` is written for a human and may be reworded — do not match on it in code. ## How to treat each status | Code | Retry? | What it means | |---|---|---| | `400` | No | The request body is not valid JSON | | `401` | No | The key is wrong, revoked, or your plan has no API access | | `403` | No | The workspace is read-only | | `404` | No | No such message in this workspace | | `405` | No | Wrong HTTP method for this path | | `409` | No | The `Idempotency-Key` was used for a different request | | `422` | No | Something in the request is invalid. Fix it first | | `500` | **Yes** | Our side failed. Retry with the same `Idempotency-Key` | Only `500` is worth retrying. Everything else returns the same answer however many times you send it. --- ## 400 — invalid_json > Request body must be valid JSON. The body did not parse. Usually a trailing comma, a single-quoted string, or a form-encoded body sent without `Content-Type: application/json`. --- ## 401 — invalid_api_key > Provide a valid active API key. One of four things: 1. **No `Authorization` header**, or it is not in `Bearer ` form. 2. **The key is malformed.** Keys start with `wh_live_` followed by 32–80 characters of letters, digits, `_` or `-`. A truncated copy-paste fails here. 3. **The key was revoked**, or never existed. 4. **Your plan does not include API access.** This returns the same `401` on purpose — the API never reveals which workspaces or keys exist. Check the plan first if the key is definitely right. Call [`GET /status`](https://onpad.in/docs/api/status) to test a key on its own. --- ## 403 — workspace_read_only > Your trial has ended. This workspace is read-only. Choose a plan to resume sending and editing. Sending is paused because the workspace has no active plan. Reading still works; `GET /messages` and `GET /status` keep answering. Choose a plan in **Plans & billing**. Sending resumes immediately. --- ## 404 — message_not_found > Message not found. No message with that id exists **in this workspace**. A valid id belonging to another workspace also returns `404` rather than `403`. Check the id came from this workspace's key and was copied in full — it is a 36-character UUID. --- ## 405 — method_not_allowed > Method not allowed. `/messages` accepts `GET` and `POST` only. `PUT`, `PATCH` and `DELETE` are not supported — a queued message cannot be edited or cancelled through the API. --- ## 409 — duplicate idempotency key > This Idempotency-Key was already used for a different request. The key was used before, with a different body. Nothing was sent. Either make the key specific to this exact message, or stop changing the payload between retries — a timestamp inside the body is the usual culprit. See [Idempotency](https://onpad.in/docs/api/idempotency). --- ## 422 — message_rejected The request was understood but something in it is wrong. The `message` field names the problem exactly. ### Idempotency > Provide an Idempotency-Key header between 8 and 120 safe characters. The header is missing, too short, too long, or contains characters outside letters, digits, `.`, `_`, `:` and `-`. ### Recipient > Enter a valid recipient phone number with country code. After stripping separators, `to` must be 8 to 15 digits. The most common cause is a number without its country code — `9876543210` instead of `919876543210`. ### Message type > Message type must be text or template. `type` must be `"text"` or `"template"`. It defaults to `"template"` if omitted. ### Free text > Text body must be between 1 and 4096 characters. `text.body` is empty or too long. > The 24-hour customer service window is closed. Send an approved template instead. The recipient has not messaged you in the last 24 hours, so WhatsApp does not allow free text. This is Meta's rule. Send an approved template instead — it opens a fresh window when they reply. ### Template > Enter a valid approved template name. `template.name` is empty, longer than 512 characters, or contains anything other than lowercase letters, digits and underscores. > Enter a valid template language such as en_US. The language code is malformed. Use `en`, `en_US`, `hi`, `pt_BR` and similar. > This template is not approved or is unavailable in the selected language. Three possible causes, in order of likelihood: 1. The template exists but is **not approved** — check Templates. 2. The template is approved in a **different language** than the one requested. 3. The name is misspelled. > Media-header templates are not supported by this endpoint yet. The template has an image, video, document or location header. Use a campaign for these. ### Template parameters > Template parameters must be a list with at most 20 values. `template.parameters` must be a JSON array, not an object, and at most 20 entries. > Each template parameter must be text or a number. An entry was an object, an array or `null`. Convert it to a string first. > Template parameters cannot be empty or longer than 1024 characters. An entry was an empty string or too long. An empty variable is rejected by WhatsApp, so substitute a real value or use a template without that variable. > This template requires exactly N parameter(s). The count does not match the template's variables. ONPAD counts the distinct `{{n}}` placeholders in the approved body and expects exactly that many. ### Connection > Connect WhatsApp before syncing message templates. The workspace has no connected WhatsApp number. See [Connect WhatsApp](https://onpad.in/docs/connect-whatsapp). > The Meta access token has expired. Reconnect WhatsApp and try again. Meta's token is no longer valid. Reconnect from the setup page; no data is lost. --- ## 500 — internal_error > Message could not be queued. Something failed on our side and the message was **not** queued. **This is the one error to retry.** Use the same `Idempotency-Key`, so if the message did sneak through, the retry returns it instead of sending twice. If it keeps happening, send us the time and your key's prefix at [support@onpad.in](mailto:support@onpad.in) — every request is logged, so we can find it. --- ## Failures after a 202 A `202` means queued, not delivered. A message can still fail later, and that shows up as `status: "failed"` with a reason in `error` when you [look it up](https://onpad.in/docs/api/get-message). Common delivery failures: | Reason | Meaning | |---|---| | Invalid phone number | The number is not valid for WhatsApp | | Not on WhatsApp | The number exists but has no WhatsApp account | | Messaging limit reached | Meta's cap on new conversations in 24 hours | | Payment issue | Meta has no valid payment method on your WhatsApp Business Account | | Template paused or disabled | Meta paused the template, usually for poor quality | ONPAD retries up to 3 times with backoff for temporary failures. Permanent ones — an invalid number, an unapproved template — fail at once, since retrying cannot change the answer. --- # Code examples Source: https://onpad.in/docs/api/examples Each example sends a template message, handles the errors that matter, and polls for the result. Copy one and change the key, template name and recipient. ## curl ```bash #!/usr/bin/env bash set -euo pipefail API_KEY="wh_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" BASE="https://app.onpad.in/api/v1" # Replace this. 919876543210 is a placeholder, not a test number — # whoever owns it will receive whatever you send, and Meta will charge you. RECIPIENT="919876543210" response=$(curl -sS -X POST "$BASE/messages" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: order-10482-shipped" \ -d '{ "to": "'"$RECIPIENT"'", "type": "template", "template": { "name": "order_shipped", "language": "en_US", "parameters": ["Priya", "#10482", "Friday"] } }') echo "$response" | jq . id=$(echo "$response" | jq -r '.message.id') sleep 3 curl -sS "$BASE/messages?id=$id" -H "Authorization: Bearer $API_KEY" | jq . ``` ## PHP ```php request('POST', '/messages', [ 'to' => $to, 'type' => 'template', 'template' => [ 'name' => $template, 'language' => $language, 'parameters' => $parameters, ], ], $idempotencyKey); } public function getMessage(string $id): array { return $this->request('GET', '/messages?id=' . urlencode($id)); } private function request(string $method, string $path, ?array $body = null, ?string $idempotencyKey = null): array { $headers = ['Authorization: Bearer ' . $this->apiKey]; if ($body !== null) { $headers[] = 'Content-Type: application/json'; } if ($idempotencyKey !== null) { $headers[] = 'Idempotency-Key: ' . $idempotencyKey; } $curl = curl_init($this->baseUrl . $path); curl_setopt_array($curl, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => $method, CURLOPT_HTTPHEADER => $headers, CURLOPT_TIMEOUT => 30, ]); if ($body !== null) { curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($body, JSON_UNESCAPED_UNICODE)); } $raw = curl_exec($curl); $status = (int) curl_getinfo($curl, CURLINFO_HTTP_CODE); $error = curl_error($curl); curl_close($curl); if ($raw === false) { throw new RuntimeException('Could not reach ONPAD: ' . $error); } $decoded = json_decode((string) $raw, true); if (!is_array($decoded)) { throw new RuntimeException('Unreadable response from ONPAD.'); } if (($decoded['ok'] ?? false) !== true) { throw new RuntimeException(sprintf( '[%d %s] %s', $status, $decoded['error'] ?? 'error', $decoded['message'] ?? 'Unknown error', )); } return $decoded; } } $onpad = new OnpadClient('wh_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'); // Replace this. 919876543210 is a placeholder, not a test number. $recipient = '919876543210'; $result = $onpad->sendTemplate( to: $recipient, template: 'order_shipped', parameters: ['Priya', '#10482', 'Friday'], idempotencyKey: 'order-10482-shipped', ); echo $result['message']['id'], PHP_EOL; sleep(3); echo $onpad->getMessage($result['message']['id'])['message']['status'], PHP_EOL; ``` ## Node.js Needs Node 18 or newer for the built-in `fetch`. ```javascript const API_KEY = "wh_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; const BASE = "https://app.onpad.in/api/v1"; // Replace this. 919876543210 is a placeholder, not a test number. const RECIPIENT = "919876543210"; class OnpadError extends Error { constructor(status, code, message) { super(`[${status} ${code}] ${message}`); this.status = status; this.code = code; } } async function call(path, { method = "GET", body, idempotencyKey } = {}) { const headers = { Authorization: `Bearer ${API_KEY}` }; if (body) headers["Content-Type"] = "application/json"; if (idempotencyKey) headers["Idempotency-Key"] = idempotencyKey; const response = await fetch(BASE + path, { method, headers, body: body ? JSON.stringify(body) : undefined, }); const data = await response.json(); if (!data.ok) throw new OnpadError(response.status, data.error, data.message); return data; } async function sendTemplate(to, name, parameters, idempotencyKey, language = "en_US") { return call("/messages", { method: "POST", idempotencyKey, body: { to, type: "template", template: { name, language, parameters } }, }); } async function waitForDelivery(id, attempts = 6) { const delays = [2000, 5000, 15000, 30000, 30000, 30000]; for (let i = 0; i < attempts; i++) { await new Promise(resolve => setTimeout(resolve, delays[i] ?? 30000)); const { message } = await call(`/messages?id=${encodeURIComponent(id)}`); if (["delivered", "read", "failed"].includes(message.status)) return message; } return null; } const { message } = await sendTemplate( RECIPIENT, "order_shipped", ["Priya", "#10482", "Friday"], "order-10482-shipped", ); console.log(message.id, message.status); console.log(await waitForDelivery(message.id)); ``` ## Python Needs `requests`. ```python import time import requests API_KEY = "wh_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" BASE = "https://app.onpad.in/api/v1" # Replace this. 919876543210 is a placeholder, not a test number. RECIPIENT = "919876543210" class OnpadError(Exception): def __init__(self, status, code, message): super().__init__(f"[{status} {code}] {message}") self.status = status self.code = code def call(path, method="GET", body=None, idempotency_key=None): headers = {"Authorization": f"Bearer {API_KEY}"} if idempotency_key: headers["Idempotency-Key"] = idempotency_key response = requests.request(method, BASE + path, json=body, headers=headers, timeout=30) data = response.json() if not data.get("ok"): raise OnpadError(response.status_code, data.get("error"), data.get("message")) return data def send_template(to, name, parameters, idempotency_key, language="en_US"): return call( "/messages", method="POST", idempotency_key=idempotency_key, body={ "to": to, "type": "template", "template": {"name": name, "language": language, "parameters": parameters}, }, ) def wait_for_delivery(message_id, delays=(2, 5, 15, 30, 30, 30)): for delay in delays: time.sleep(delay) message = call(f"/messages?id={message_id}")["message"] if message["status"] in ("delivered", "read", "failed"): return message return None result = send_template( to=RECIPIENT, name="order_shipped", parameters=["Priya", "#10482", "Friday"], idempotency_key="order-10482-shipped", ) message_id = result["message"]["id"] print(message_id, result["message"]["status"]) print(wait_for_delivery(message_id)) ``` ## Retrying safely All four examples would be improved by retrying `500` responses. The rule is the same in every language: **build the idempotency key once, outside the retry loop**, so every attempt carries the same key and at most one message is ever sent. ```python key = f"order-{order_id}-shipped" # once for attempt in range(3): try: return send_template(to, name, params, key) except OnpadError as error: if error.status != 500: raise # 4xx will not fix itself time.sleep(2 ** attempt) ``` Retry `500` only. A `422` returns the same answer forever, and retrying it just fills your logs. ## Generated clients The [OpenAPI specification](https://onpad.in/docs/openapi.json) describes the whole API. Point a generator at it, or hand it to a coding agent: ```text Use the OpenAPI spec at https://onpad.in/docs/openapi.json to write a client that sends a template message and polls for delivery. ```