WhatsApp Template Management

This documentation covers details of the WhatsApp API documentation

REST API components & How to read them

REST APIs are the most prevalent and user-friendly type of APIs you will most likely encounter. As a product manager, you play a pivotal role in working with your engineering team to bring digital solutions to life, and a fundamental part of that collaboration is understanding REST APIs.

In this document, you’ll learn how to break down REST APIs into their essential components so you can confidently discuss, dissect, interact with, and debug them.

A brief intro to REST APIs

REST APIs are a set of rules and conventions that define a standardized way for requests and responses to be structured and exchanged. They are based on the principles of REST, a software architectural style for designing networked applications. You’ll also hear the term RESTful APIs in relation to REST APIs.

Here are a couple of examples of RESTful rules and conventions followed by REST APIs (not important to memorize, just to give you an idea of what these rules look like):

  1. Client-server: Separation of concerns whereby the user interface concerns (client) are separate from the data storage concerns (server).
  2. Stateless: Each request from the client to the server must contain all of the information necessary to understand and complete the request. The server cannot use previously stored context information on the server.

REST APIs make extensive use of HTTP (Hypertext Transfer Protocol) as the foundation for communication between clients (like web browsers or mobile apps) and servers (where the API is hosted). 

The majority of what you need to know about APIs are related to HTTP and it’s components. We can broadly bucket the components into the API Request and API Response:

1*J8x84KaR0akEMweLIlyKIw.pngComponents of an API Request and API Response
 

 
API Request

When you make a request to an API, you’re essentially saying, “I want to do something or get something from this endpoint.” Requests consist of the following components:

1/ API Endpoint

An endpoint is the specific location aka the access point to the API. Think of it as an address for a particular service or resource. These endpoints are usually represented as URLs (Uniform Resource Locators), making them easy to understand. The API endpoint is made up of the “ Base URL” plus the “path” of the API.

0*cYUsCUf5xOLQvOU9

2/ HTTP Methods

HTTP (Hypertext Transfer Protocol) methods are the actions you can take when interacting with an API. There are 8 request types but 4 are the most commonly used:

  • GET: This method is like asking for information. When you send a GET request to an API’s endpoint, you’re requesting data, like retrieving weather information for a specific location.
  • POST: When you send a POST request, you’re submitting data to the API which adds new data to the database. This could be creating a new user account or adding a comment on a blog post.
  • PUT: Use the PUT method to update existing data. For instance, you might change your profile picture on a social media app.
  • DELETE: As the name suggests, the DELETE method is for removing data. If you want to delete a post or an account, you’d use this method.

You’ll likely see all 4 HTTP methods being used at some point, but out of the 4, you’ll see the GET and POST method most frequently and those are the two that you should be most familiar with.

Two quick side notes:

  • The POST and PUT methods are often used interchangeably. The difference has to do with something called idempotency which is very technical and not worth diving into.
  • You’ll also see the same POST API sometimes used to both add new data and update existing data. Developers may decide to design the API this way to be more efficient as opposed to creating and managing two separate APIs in the business logic: one POST and the other PUT.

3/ Request Headers

Request headers convey additional information about the API request, such as the format in which the client expects the response (e.g., JSON or XML), authentication credentials, caching instructions, and more.

Here’s an example using APIs on Amazon:

Accept-Language: en-US
Authorization: Bearer YourAccessTokenHere
Content-Type: application/json
Host: www.amazon.com
Origin: https://www.amazon.com
Referer: https://www.amazon.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36

Information in the request header can be used for a number of reasons including:

  • Authenticating the request: There are various authentication methods, such as API keys, OAuth tokens, and username/password combinations. For example, credentials for your bank account so the API is authorized to make changes to your account.
  • Caching instructions: Temporarily storing data in a cache for improved future performance/latency.
  • Logging: All systems keep a log of events that occur in a computer system. Information stored in the headers (i.e. location of request origin, browser information, date & time of request, etc..) are logged in log files. The information in the log files can then be used for a variety of reasons: debugging, metrics, and telemetry. Accept-Language: en-US
    Authorization: Bearer YourAccessTokenHere

4/ Request Body

When you need to send data to the server, you include it in the request body. The data is typically in a structured format like JSON or XML. This is common when creating new records or updating existing ones. The request body is akin to a letter with the information you want to submit.

For example: Amazon has an internal API that adds a new product into the database.

POST https://products.amazon.com/api/2017/add
{
"product_name": "Smartphone",
"price": 499.99,
"description": "A high-quality smartphone with advanced features.",
"category": "Electronics",
"availability": true
}


 

API Response

Once you send a API request, you’ll receive an API response. This response contains the data or information you requested, as well as metadata about the response itself. It consists of the following components:

1/ Status Code

This is a three-digit number that tells you the outcome of your request. Status codes are like short, standardized messages that quickly convey whether your request was successful, encountered an issue, or faced an error. All status codes are divided into 5 categories but you’ll only really encounter 4 of them:

  • 2xx: Success — The API request was successful! e.g. 200 OK, 201 Created
  • 3xx: Redirection — The API request has more than one response. e.g. 301 Moved Permanently, 302 Found
  • 4xx: Client Error — Some information provided in the request was wrong or missing. e.g. 400 Bad Request, 401 Unauthorized
  • 5xx: Server Error — Something went wrong on the server and the request wasn’t successful. e.g. 501 Internal Server Erorr, 502 Bad Gateway

Here are some examples of common status codes:

  • 200 OK: Your request was successful, and you’ll find the data you wanted in the response.
  • 201 Created: This code typically appears after a successful POST request, indicating that the resource you requested has been created.
  • 400 Bad Request: If the API couldn’t understand your request, you might see this code.
  • 401 Unauthorized: When you lack proper authorization or credentials to access the requested data, this code appears.
  • 404 Not Found: This indicates that the endpoint or resource you’re looking for doesn’t exist.
  • 500 Internal Server Error: If something goes wrong on the other island (the API’s server), you might see this code.
1*fTqd36d2IyWnwimm0RhcTA.pngCommon API status codes

2/ Response Headers

Similar to request headers, response headers provide additional information about the response, such as the type of data you’re receiving (e.g., JSON or XML), the server’s version, and more.

Here’s an example:

Access-Control-Allow-Origin: www.amazon.com
Content-Length: 22
Content-Type: application/json
Date: Mon, 30 Oct 2023 16:32:01 GMT

3/ Response Body

This is where you’ll find the actual data or information you requested. Like the request body, the response body is often in JSON format for easy readability and parsing.

Using the same API example as the one in the request body, here’s what a successful response where the product was successfully added to the database might look like. Notice the API response returned a newly created product_id uniquely assigned to the added product.

200 OK POST https://products.amazon.com/api/2017/add
{
"product_id": 12345,
"message": "Product 'Smartphone' has been successfully added."
}


Conclusion

We’ve covered the crucial parts of the API and you now have all the information you need to confidently discuss, dissect, interact with, and debug APIs.

1*mo5UFEREModhtJ48UfPUAg.pngREST API Model

WhatsApp Templates - things to know

image.png

Templates

Templates are used in template messages to open marketing and utility conversations with customers. Unlike free-form messages, template messages are the only type of message that can be sent to customers who have yet to message you, or who have not sent you a message in the last 24 hours.

Templates must be approved before they can be sent in template messages. In addition, templates may be disabled automatically based on customer feedback and engagement. Once disabled, a template cannot be sent in a template message until its quality rating has improved or it no longer violates our business or commerce policies.

Creation

Use the template creation API to create templates. 

Approval Process

Once you have created your template you can submit it for approval. It can take up to 24 hours for an approval decision to be made. Once a decision has been made, a notification will appear in your Broadcast Templates Manager.

If your message template is approved, its status will be set to ✅Approved and you can begin sending it to customers. If it is rejected, its status will be set to ❌Rejected. The template has to be deleted and wait for 24 hours to reapply again with the same template name. 

Multiple templates of the same name can be created by changing the template language

Samples

If your template uses variables you must include sample variable values (media assets, text strings, etc.) with your submission. This makes it easier for us to visualize how your template will appear to customers.

To include a sample with your submission in the WhatsApp Manager, first create your template, add any variables that it requires, and then click the Add Sample button. The preview pane will render any sample media assets or sample text values you provide.

image.png



If using our APIs to create templates, include the examples property for each template component object in your request that uses a variable.

Common Rejection Reasons

Submissions are commonly rejected for the following reasons, so make sure you avoid these mistakes.

  • Variable parameters are missing or have mismatched curly braces. The correct format is {{1}}.
  • Variable parameters contain special characters such as a #$, or %.
  • Variable parameters are not sequential. For example, {{1}}{{2}}{{4}}{{5}} are defined but {{3}} does not exist.
  • Template contains too many variable parameters relative to the message length. You need to decrease the number of variable parameters or increase the message length.
  • The message template cannot end with a parameter.
  • The message template contains content that violates WhatsApp’s Commerce Policy: When you offer goods or services for sale, we consider all messages and media related to your goods or services, including any descriptions, prices, fees, taxes and/or any required legal disclosures, to constitute transactions. Transactions must comply with the WhatsApp Commerce Policy.
  • The message template contains content that violates the WhatsApps Business Policy: Do not request sensitive identifiers from users. For example, do not ask people to share full length individual payment card numbers, financial account numbers, National Identification numbers, or other sensitive identifiers. This also includes not requesting documents from users that might contain sensitive identifiers. Requesting partial identifiers (ex: last 4 digits of their Social Security number) is OK.
  • The content contains potentially abusive or threatening content, such as threatening a customer with legal action or threatening to publicly shame them.
  • The message template is a duplicate of an existing template. If a template is submitted with the same wording in the body and footer of an existing template, the duplicate template will be rejected.

WhatsApp Templates API Management

The template APIs allow you to create, delete, and fetch templates

The templates API supports the following methods and are client specific

Get all templates
curl --location 'https://api.versal.one/<client-id>/templates' \
--header 'Authorization: Bearer <client-token>'
Get a template by name
curl --location 'https://api.versal.one/<client-id>/templates?name=order_delivery_1' \
--header 'Authorization: Bearer <client-token>'
Create a template

To create a template - the following components are required

for more details check the official documentation on the META website

curl --location 'https://api.versal.one/<client-id>/templates' \
--header 'Authorization: Bearer <client-token>' \
--data '{
    "name": "order_delivery_1",
    "language": "en_US",
    "category": "Marketing",
    "components": [
        {
            "type": "HEADER",
            "format": "Text",
            "text": "header text"
        },
        {
            "type": "BODY",
            "text": "This is a {{1}}",
            "example": {
                "body_text": [
                    [
                        "random text"
                    ]
                ]
            }
        },
        {
            "type": "FOOTER",
            "text": "lasadoasi"
        },
        {
            "type": "BUTTONS",
            "buttons": [
                {
                    "type": "PHONE_NUMBER",
                    "text": "Call",
                    "phone_number": "+918897229166"
                }
            ]
        }
    ]
}'
{
    "message": "Template created successfully",
    "response_text": "{\"id\":\"1179134613392693\",\"status\":\"APPROVED\",\"category\":\"MARKETING\"}",
    "status": "200"
}

Template Components

Templates are made up of four primary components which you define when you create a template: header, body, footer, and buttons. The components you choose for each of your templates should be based on your business needs. The only required component is the body component.

Some components support variables, whose values you can supply when using the Cloud API or On-Premises API to send the template in a template message. If your templates use variables, you must include sample variable values upon template creation.

Headers

Headers are optional components that appear at the top of template messages. Headers support text, media (images, videos, documents), and locations.

All templates are limited to one header component

Text Headers

You can choose to add header text to your message template. The message text in the header component accepts parameters for programmatic configuration.

Text parameters can be configured in one of two formats:

  • Positional — Pass in an array of parameters that correspond to numeric positions in the body text with examples
    • For example: “Hello John, your account balance is {{1}}” | [ “$1,000” ]
  • Named — Pass in JSON objects that contain a parameter name and examples
    • For example: { "param_name": "account_balance", "example": "$1,000" }

Component Syntax

Add this header component object into the ”components”[] object array when calling the POST <WHATSAPP_BUSINESS_ACCOUNT_ID>/message_templates endpoint. Substitute the placeholder properties below using the properties table.

{
  "type": "HEADER",
  "format": "TEXT",
  "text": "<HEADER_TEXT>",

  "example": {
    "header_text": [
       // You must provide one of the inputs below when the <HEADER_TEXT> string contains parameters
       <POSITIONAL_PARAM_EXAMPLES>
       <BODY_TEXT_NAMED_PARAMS>
    ]
  }
}

Properties


Placeholder Description Example Value

<HEADER_TEXT>

String | Required

Plain text string. Can support 1 parameter.

If this string contains parameters, you must include the example property and example parameter values as shown in <POSITIONAL_PARAM_EXAMPLES> and <HEADER_TEXT_NAMED_PARAMS> below.

60 character maximum.

“Our Holiday sale starts December 1st!”

“Our new sale starts {{1}}”

“Our new sale starts {{sale_start_date}}!”

<POSITIONAL_PARAM_EXAMPLES>

[String] | Optional

Required when using positional parameters in your header text.

Array of String in which each string is meant to illustrate the text likely to be passed in as a parameter during message send time, for example a bank account balance, or a customer name.

The number of strings must match the number of variables included in the string.

["December 1st"]

<HEADER_TEXT_NAMED_PARAMS>

[JSON Object] | Optional

Required when using named variables in your header text.

Array of JSON objects that contain param_name and example strings.

  • “param_name” — Your custom parameter name. Must be lowercase letters and underscores only.
  • “example” — The illustrative sample text for the parameter.
[{
 "param_name": "sale_start_date",
 "example": "December 1st"
}]
          

Positional Parameter Example

{
  "type": "HEADER",
  "format": "TEXT",
  "text": "Our new sale starts {{1}}!",
  "example": {
    "header_text": [
      "December 1st"
    ]
  }
}

Named Parameter Example

{
  "type": "HEADER",
  "format": "TEXT",
  "text": "Our new sale starts {{sale_start_date}}!",
  "example": {
    "header_text_named_params": [
      {
        "param_name": "sale_start_date",
        "example": "December 1st"
      }
    ]
  }
}

Media Headers

Media headers can be an image, video, or a document such as a PDF. All media must be uploaded with the Resumable Upload API. The syntax for defining a media header is the same for all media types.

Syntax

{
  "type": "HEADER",
  "format": "<FORMAT>",
  "example": {
    "header_handle": [
      "<HEADER_HANDLE>"
    ]
  }
}

Properties


Placeholder Description Example Value

<FORMAT>

Indicates media asset type. Set to IMAGEVIDEO, or DOCUMENT.

IMAGE

<HEADER_HANDLE>

Uploaded media asset handle. Use the Resumable Upload API to generate an asset handle.

4::aW...

Example

{
  "type": "HEADER",
  "format": "IMAGE",
  "example": {
    "header_handle": [
      "4::aW..."
    ]
  }
}

Body

The body component represents the core text of your message template and is a text-only template component. It is required for all templates.

The message text in the body component accepts parameters for programmatic configuration.

Text parameters can be configured in one of two formats:

  • Positional — Pass in an array of numbered positional parameters that correspond to numeric positions in the body text with examples
    • For example: “Hello {{1}}, your account balance is {{2}}” | [ “John”, “$1,000” ]
  • Named — Pass in JSON objects that contain a parameter name and examples
    • For example: { "param_name": "order_id", "example": "335628"}

All templates are limited to one body component.

Component Syntax

Add this body component object into the ”components”[] object array when calling the POST <WHATSAPP_BUSINESS_ACCOUNT_ID>/message_templates endpoint. Substitute the placeholder properties below using the properties table.

{
  "type": "body",
  "text": "<BODY_TEXT>",
  "example": {
    "body_text": [
      [
       // You must provide one of the inputs below when the <BODY_TEXT> string contains parameters
       <POSITIONAL_PARAM_EXAMPLES>
       <BODY_TEXT_NAMED_PARAMS>
      ]
    ]
  }
}

Properties

Placeholder Description Example Value

<HEADER_TEXT>

String | Required

Plain text string. Can support multiple parameters.

If this string contains parameters, you must include the example property and example parameter values as shown in <POSITIONAL_PARAM_EXAMPLES> and <BODY_TEXT_NAMED_PARAMS> below.

1024 character maximum.

“Shop our Holiday sale now!”

“Shop now through {{1}} and use code {{2}} to get {{3}} off of all merchandise.”

“Your {{order_id}}, is ready {{customer_name}}”

<POSITIONAL_PARAM_EXAMPLES>

[String] | Optional

Required when using positional parameters in your body text.

Array of string in which each string is meant to illustrate the text likely to be passed in as a parameter during message send time, for example a bank account balance, or a customer name.

The number of strings must match the number of variables included in the string.

["the end of August","25OFF","25%"]

<BODY_TEXT_NAMED_PARAMS>

[JSON Object] | Optional

Required when using named variables in your body text.

Array of JSON objects that contain param_name and example strings.

  • “param_name” — Your custom parameter name. Must be lowercase letters and underscores only.
  • “example” — The illustrative sample text for the parameter.
[{
 "param_name": "order_id",
 "example": "335628"
},
{
 "param_name": "customer_name",
 "example": "Shiva"
}]
          

Positional Parameter Example

{
  "type": "BODY",
  "text": "Shop now through {{1}} and use code {{2}} to get {{3}} off of all merchandise.",
  "example": {
    "header_text": [
      "the end of August","25OFF","25%"
    ]
  }
}

Named Parameter Example

{
  "type": "BODY",
  "text": "Your {{order_id}}, is ready {{customer_name}}.",
  "example": {
    "header_text_named_params": [
      {
        "param_name": "order_id",
        "example": "335628"
      },
      {
        "param_name": "customer_name",
        "example": "Shiva"
      }
    ]
  }
}

Footers are optional text-only components that appear immediately after the body component. Templates are limited to one footer component.

Syntax

{
  "type": "FOOTER",
  "text": "<TEXT>"
}

Properties


Placeholder Description Example Value

<TEXT>

Text to appear in template footer when sent.


60 characters maximum.

Use the buttons below to manage your marketing subscriptions

Example

{
  "type": "FOOTER",
  "text": "Use the buttons below to manage your marketing subscriptions"
}

Buttons

Buttons are optional interactive components that perform specific actions when tapped. Templates can have a mixture of up to 10 button components total, although there are limits to individual buttons of the same type as well as combination limits. These limits are described below.

Buttons are defined within a single buttons component object, packed into a single buttons array. For example, this template uses a phone number button and a URL button:

{
  "type": "BUTTONS",
  "buttons": [
    {
      "type": "PHONE_NUMBER",
      "text": "Call",
      "phone_number": "15550051310"
    },
    {
      "type": "URL",
      "text": "Shop Now",
      "url": "https://www.luckyshrub.com/shop/"
    }
  ]
}

If a template has more than three buttons, two buttons will appear in the delivered message and the remaining buttons will be replaced with a See all options button. Tapping the See all options button reveals the remaining buttons.

Copy Code Buttons

Copy code buttons copy a text string (defined when the template is sent in a template message) to the device's clipboard when tapped by the app user. Templates are limited to one copy code button.

Syntax

{
  "type": "COPY_CODE",
  "example": "<EXAMPLE>"
}

Properties


Placeholder Description Example Value

<EXAMPLE>

String to be copied to device's clipboard when tapped by the app user.


Maximum 15 characters.

250FF

Example

{
  "type": "COPY_CODE",
  "example": "250FF"
}
Delete a template
curl --location --request DELETE 'https://api.versal.one/<client-id>/templates?name=harsh45021279' \
--header 'Authorization: Bearer <client-token>'

Send Template Messages

While sending a template message, the template contents are not sent. To send a template message, its media link [public link] & variable values [if any] are sent along with the template name and language

Broadcast with caution - Do not spam. Spamming will lead to the degradation of service and WhatsApp number getting blocked

Sending Message
The template has no parameter
curl --location 'https://api.versal.one/<client-id>' \
--header 'Authorization: Bearer <client-token>' \
--header 'Content-Type: application/json' \
--data '{
    "purpose": "sendtemplate",
    "to": <recepient phone number>,
    "template": <template name>,
    "code": <language code>    
}'

sample data
--data '{
    "purpose": "sendtemplate",
    "to": "919999900000",
    "template": "conv_start_hi",
    "code": "en_US"    
}'
The template has image media

The image typically does not look like a regular parameter while creating the template. However, is a parameter

curl --location 'https://api.versal.one/<client-id>' \
--header 'Authorization: Bearer <client-token>' \
--header 'Content-Type: application/json' \
--data '{
    "purpose": "sendtemplate",
    "to": <recepient>,
    "template": "schedule",
    "code": "en",
    "components": [
        {
            "type": "header",
            "parameters": [
                {
                    "type": "image",
                    "image": {
                        "link": "https://cdn.anuhealthyfood.in/images/missyourorders.png"
                    }
                }
            ]
        }
    ]
}'
The template has body parameters
curl --location 'https://api.versal.one/<client-id>' \
--header 'Authorization: Bearer <client-token>' \
--header 'Content-Type: application/json' \
--data '{
    "purpose": "sendtemplate",
    "to": <recepient>,
    "template": "schedule",
    "code": "en",
    "components": [
        {
            "type": "body",
            "parameters": [
                {
                    "type": "TEXT",
                    "text": "Hemant Suryavanshi"
                },
                {
                    "type": "TEXT",
                    "text": "Blue USB Microphone"
                },
                {
                    "type": "TEXT",
                    "text": "12/12/2024"
                }
            ]
        }
    ]
}'

In the above example, the template has three body variables. As depicted, only parameters are passed and not the entire body

The template has body parameters and image media
curl --location 'https://api.versal.one/<client-id>' \
--header 'Authorization: Bearer <client-token>' \
--header 'Content-Type: application/json' \
--data '{
    "purpose": "sendtemplate",
    "to": <recepient>,
    "template": "schedule",
    "code": "en",
    "components": [
        {
            "type": "header",
            "parameters": [
                {
                    "type": "image",
                    "image": {
                        "link": "https://cdn.anuhealthyfood.in/images/missyourorders.png"
                    }
                }
            ]
        },
        {
            "type": "body",
            "parameters": [
                {
                    "type": "TEXT",
                    "text": "Hemant Suryavanshi"
                },
                {
                    "type": "TEXT",
                    "text": "Blue USB Microphone"
                },
                {
                    "type": "TEXT",
                    "text": "12/12/2024"
                }
            ]
        }
    ]
}'

 

In the above example, there is an image and three body parameters in the template

Response

{
    "message": "Message sent successfully",
    "response_text": "{"messaging_product":"whatsapp","contacts":[{"input":"+16312924377","wa_id":"16312924377"}],"messages":[{"id":"wamid.HBgLMTYzMTI5MjQzNzcVAgARGBIxNEExODY3MjhGMDNGNDRBNjgA","message_status":"accepted"}]}",
    "status": "200"
}

 

 

vCX WhatsApp Onboarding & Messaging

Co-existence.pngBase URL - Administration

https://backend.admin.versalence.online/api/v2

All protected endpoints require:

Authorization: Bearer <JWT_TOKEN>

1. Authenticate the customer admin

The customer’s admin user logs in with their vCX credentials. The returned JWT is used for all subsequent calls.

POST /api/v2/login
Content-Type: application/json

{
  "email": "admin@customer.com",
  "password": "CustomerAdminPassword"
}

Response:

{
  "success": true,
  "message": "Sign-in successful",
  "token": "<JWT_TOKEN>"
}

Notes:


Create a Sub-Account Under an Agency

An agency account creates a sub-account by calling the standard onboarding endpoint. The agency relationship is implicitly derived from the JWT; there is no body parameter to set the parent agency UUID.

POST /api/v2/addUser Agency Account

Headers

Authorization: Bearer <agency-account-jwt>
Content-Type: application/json

How the Agency Tag Is Derived

  1. The JWT uuid claim identifies the calling account.
  2. The cust_auth.authenticate middleware validates the token and calls MiddlewareCheck to verify that the UUID belongs to a company with is_agency = 'yes'.
  3. If valid, the middleware sets req.parent_uuid to the agency UUID.
  4. The SignUpController passes that UUID as agent_uuid to the creation service, which writes it into company.parent_agency_uuid.

Request Body

{
  "name": "Sub-account Admin Name",
  "email": "admin@subaccount.com",
  "password": "securePassword",
  "company_name": "Sub Account Inc",
  "company_email": "info@subaccount.com",
  "company_type": "Agency Client",
  "phone_number": "1234567890",
  "address": "123 Main St",
  "industry": "Technology",
  "website": "https://subaccount.com"
}

Required Fields

Field Validation
name Required
company_name Required
company_type Required
email Required, valid email
company_email Required, valid email
password Required, 6–26 characters
phone_number Required, 8–15 characters
address Optional
industry Optional
website Optional

Success Response — 201

{
  "success": true,
  "message": "User created successfully."
}

What Happens on the Backend

  • A new UUID and company_id are generated.
  • Records are inserted into uuid_table, company, and company_users.
  • company.parent_agency_uuid is set to the agency UUID from the JWT.
  • The first user is created with user_role = 'admin', email_verified = 'yes', and first_admin = 'yes'.
  • Plan assignment: if the creator is not the Versalence super-account, the sub-account inherits the agency's current company_plan_id from company_subscription_current; otherwise it falls back to plan0.

Error Responses

Status Meaning Frontend Handling
400 Validation failed or duplicate user/company email Show inline field errors
403 Authorization header missing, invalid token, or account is not an agency Redirect to login or show access denied
500 Unexpected creation error Show generic error and allow retry

UI / Frontend Notes

Note: The addUser endpoint does not accept a parent agency UUID in the body. The frontend should only allow this action when the logged-in account is an agency, and it should rely on the agency's JWT to establish the relationship automatically.
Warning: Only accounts with is_agency = yes can create sub-accounts via this flow. The configured VERSALENCE_UUID super-account is the only exception and can bypass the agency check.
SuperAdminPanel
└── AgencyManagementPage
    ├── AccountSearch / AccountSelector
    ├── AccountDetailsCard
    │   ├── CurrentAgencyStatusBadge
    │   └── PromoteButton / DemoteButton
    └── ConfirmAgencyStatusModal

AgencyDashboard
└── SubAccountManagementPage
    ├── SubAccountList
    └── CreateSubAccountForm (calls POST /api/v2/addUser)

Environment Variables

Variable Purpose
SUPER_ADMIN_UUID Overrides the default super admin UUID.
VERSALENCE_UUID Bypasses the agency check for the master account.

2. Get Agency Customers

GET /api/admin/v2/getCustomers
Authorization: Bearer <agency-jwt>

Response:

{
  "success": true,
  "message": "Customers retrieved successfully.",
  "data": [
    {
      "uuid": "...",
      "company_name": "...",
      "company_email": "...",
      "company_id": "AGTSW000012026",
      "account_status": "active",
      "parent_agency_uuid": "...",
      "company_member_since": "...",
      "user_name": "...",
      "user_email": "...",
      "user_phone": "...",
      "user_role": "admin",
      "user_status": "active"
    }
  ]
}

3. Login to Sub Account using company_id

GET /api/admin/v2/clientAgentLogin?client_id=<SUB_ACCOUNT_COMPANY_ID>
Authorization: Bearer <agency-owner-jwt>

How it works

  1. The agency owner logs in via /api/admin/v2/adminLogin to get their own JWT.
  2. They call /api/admin/v2/clientAgentLogin?client_id=<company_id> with that JWT.
  3. The backend validates that the requested account is actually a sub-account under the agency.
  4. It returns a JWT for the sub-account’s first admin user.

Example

GET /api/admin/v2/clientAgentLogin?client_id=AGTSW000012026
Authorization: Bearer <agency-owner-jwt>

Response:

{
  "success": true,
  "message": "User successfully logged in.",
  "token": "<sub-account-jwt>"
}

Base URL - Backend

https://backend.versalence.online

All protected endpoints require:

Authorization: Bearer <JWT_TOKEN>

4. Check WhatsApp integration status

Use this to decide whether the customer still needs to onboard WhatsApp.

GET https://backend.versalence.online/api/v2/getWaba
Authorization: Bearer <JWT_TOKEN>

Not integrated response:

{
  "success": true,
  "message": "no whatsapp data found"
}

Already integrated response:

{
  "success": true,
  "message": "whatsapp data found",
  "data": [
    {
      "app_id": "...",
      "waba_id": "...",
      "access_token": "[hidden]",
      "phone_id": "...",
      "phone_number": "919876543210",
      "display_phone_number": "+91 98765 43210",
      "onboarding_mode": "standard",
      "is_active": true,
      "webhook_subscription_status": "subscribed"
    }
  ]
}

5. Launch Meta Embedded Signup

The mobile app never sees the Meta App ID. It asks the vCX backend for the OAuth URL, opens it in a browser, and polls for the result after Meta redirects back to vCX.

5a. Initiate WhatsApp Embedded Signup

GET https://backend.versalence.online/api/v2/whatsappSignupInit?mode=coexistence
Authorization: Bearer <vCX_JWT_TOKEN>

Query parameters:

Parameter Required Values Default Description
mode No standard, coexistence standard WhatsApp onboarding mode. Use coexistence if the customer wants to keep their existing WhatsApp Business app running alongside vCX.

Response:

{
  "success": true,
  "data": {
    "oauth_url": "https://www.facebook.com/v20.0/dialog/oauth?client_id=...&redirect_uri=...&scope=whatsapp_business_management&response_type=code&state=...",
    "state": "<STATE_TOKEN>",
    "redirect_uri": "https://backend.versalence.online/api/v2/whatsappSignupCallback",
    "scope": "whatsapp_business_management",
    "mode": "coexistence"
  }
}

Mobile app action: Open oauth_url in an in-app browser or WebView. Do not extract or store the Meta App ID.

5b. Meta OAuth callback

After the user completes Meta’s flow, Meta redirects the browser to the vCX backend. The mobile app does not call this endpoint directly.

GET https://backend.versalence.online/api/v2/whatsappSignupCallback?code=<META_AUTH_CODE>&state=<STATE_TOKEN>

What the backend does:

  1. Exchanges the code for a Meta access token.
  2. Resolves the WABA ID and phone number.
  3. Registers the phone number.
  4. Configures the vCX webhook.
  5. Persists the account.
  6. For coexistence mode, requests smb_app_state_sync and history sync from Meta.

On success, the browser is redirected to:

https://backend.versalence.online/whatsapp-signup-success

On failure:

https://backend.versalence.online/whatsapp-signup-failure?error=<ERROR_MESSAGE>

These redirect URLs are configurable via environment variables.

5c. Check WhatsApp signup status

The mobile app should poll this endpoint after the browser is redirected back.

GET /api/v2/whatsappSignupStatus
Authorization: Bearer <vCX_JWT_TOKEN>

Not connected response:

{
  "success": true,
  "message": "No WhatsApp account connected",
  "data": {
    "is_connected": false,
    "onboarding_mode": "standard"
  }
}

Connected response:

{
  "success": true,
  "message": "WhatsApp account connected",
  "data": {
    "is_connected": true,
    "onboarding_mode": "coexistence",
    "is_active": true,
    "waba_id": "...",
    "phone_id": "...",
    "phone_number": "919876543210",
    "display_phone_number": "+91 98765 43210",
    "webhook_subscription_status": "subscribed",
    "expires_in": "...",
    "last_message_at": null,
    "last_smb_message_echo_at": null,
    "last_history_at": null,
    "last_smb_app_state_sync_at": null
  }
}

This endpoint can be queried at any time in the future to check whether WhatsApp is still connected.


6. Get messaging API configuration

GET /api/v2/whatsappApiConfig
Authorization: Bearer <vCX_JWT_TOKEN>

Response:

{
  "success": true,
  "data": {
    "send_messages_url": "https://api.versal.one",
    "create_templates_url": "https://api.versal.one",
    "message_status_url": "https://apiproxy.versal.one"
  }
}

Use these endpoints (documented separately) to send messages, create templates, and check message delivery status.


7. Existing account lookup (backward-compatible)

GET /api/v2/getWaba
Authorization: Bearer <vCX_JWT_TOKEN>>

This existing endpoint continues to work and returns the connected WhatsApp account data. The mobile app may use either /getWaba or /whatsappSignupStatus.

Onboarding modes

Standard mode

GET /api/v2/whatsappSignupInit?mode=standard
GET /api/v2/whatsappSignupInit?mode=coexistence

Environment variables

Add these to the vCX backend .env:

# Backend-driven OAuth signup flow for external mobile apps.
# WHATSAPP_OAUTH_REDIRECT_URI must be registered in the Meta app settings.
WHATSAPP_OAUTH_REDIRECT_URI=https://backend.versalence.online/api/v2/whatsappSignupCallback
WHATSAPP_OAUTH_SUCCESS_REDIRECT=https://backend.versalence.online/whatsapp-signup-success
WHATSAPP_OAUTH_FAILURE_REDIRECT=https://backend.versalence.online/whatsapp-signup-failure

# External WhatsApp messaging API endpoints exposed to mobile apps.
WHATSAPP_SEND_MESSAGES_URL=https://api.versal.one
WHATSAPP_CREATE_TEMPLATES_URL=https://api.versal.one
WHATSAPP_MESSAGE_STATUS_URL=https://apiproxy.versal.one

The following existing variables are also used:

APP_ID=
APP_SECRET=
META_API_VERSION=

Prerequisites

  1. The customer account must already exist in vCX (created as a sub-account under the partner’s master account).
  2. The customer must have an admin user with verified email and active account status.
  3. The WHATSAPP_OAUTH_REDIRECT_URI must be registered in the Meta app settings.
  4. Migration 009_add_whatsapp_coexistence_support.sql must be applied to production. It creates the onboarding_sessions and whatsapp_accounts tables required by the new flow.

Coexistence with the existing web dashboard flow

The existing web dashboard flow is unchanged and continues to work:

The new mobile-app flow is additive:

The removed /v2/whatsapp-coexistence/enable and /v2/whatsapp-coexistence/disable endpoints are no longer needed because the mode is passed directly at signup time.

Error handling

Step Typical failure How the mobile app should handle
Login Invalid credentials Show error and ask user to retry.
Initiate signup Missing APP_ID / redirect URI Backend misconfiguration. Contact vCX support.
Meta OAuth User cancels Browser redirects to failure page. Poll /whatsappSignupStatus to confirm not connected.
Callback Invalid/expired state Browser redirects to failure page with error=Invalid or expired onboarding session.
Callback Missing WABA or phone number Browser redirects to failure page. User must retry signup.
Status polling is_connected: false Continue polling or restart signup.

Summary of API endpoints

Endpoint Method Auth Purpose
/api/v2/login POST Public Authenticate and get JWT.
/api/admin/v2/adminLogin POST Public Agency owner login.
/api/admin/v2/getCustomers GET Agency JWT List sub-accounts.
/api/admin/v2/clientAgentLogin GET Agency JWT Get sub-account JWT.
/api/v2/getWaba GET Any JWT Check WhatsApp account.
/api/v2/whatsappSignupInit GET Admin JWT Get Meta OAuth URL.
/api/v2/whatsappSignupCallback GET None (Meta calls this) Complete signup after Meta OAuth.
/api/v2/whatsappSignupStatus GET Any JWT Check if WhatsApp is connected.
/api/v2/whatsappApiConfig GET Any JWT Get messaging API URLs.

Appendix: Web dashboard 3-step flow

The following endpoints are used by the existing vCX web dashboard. They remain available but are not used by the mobile-app OAuth flow described above.

A1. Exchange code for access token

POST /api/v2/whatsappSign
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json

{
  "code": "<META_AUTH_CODE>",
  "mode": "coexistence"
}

Response:

{
  "success": true,
  "message": "Access token updated successfully",
  "session_id": "<SESSION_ID>",
  "mode": "coexistence",
  "data": "<ACCESS_TOKEN>"
}

Save session_id and discard data (legacy field).

A2. Resolve WABA ID

POST /api/v2/whatsappWaba
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json

{
  "session_id": "<SESSION_ID>"
}

Response:

{
  "success": true,
  "message": "WABA ID updated successfully",
  "data": {
    "waba_id": "<WABA_ID>"
  },
  "session_id": "<SESSION_ID>"
}

A3. Resolve phone number and complete signup

POST /api/v2/whatsappPhone
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json

{
  "session_id": "<SESSION_ID>"
}

Response:

{
  "success": true,
  "message": "Whatsapp embedded signup complete with co-existence mode",
  "mode": "coexistence",
  "phone_number": "919876543210",
  "phone_id": "<PHONE_ID>",
  "webhook_config": "Webhook configured successfully"
}

Role requirement: Admin only for all three steps.

Send messages via vCX

Once onboarding is complete, use the separately documented messaging API to send WhatsApp messages through the vCX platform.

The backend stores the access token and phone ID, so the send-message API only needs the vCX customer JWT (and the recipient/message payload).

Important notes

WhatsApp Coexistence - FAQs


WhatsApp Coexistence allows a business to continue using its existing WhatsApp Business App while connecting the same phone number to the WhatsApp Business Platform Cloud API.

Previously, businesses generally had to choose between using the WhatsApp Business App or moving their number to the WhatsApp Business Platform.

With Coexistence, both can work together using the same business phone number.

This means your team can continue using the familiar WhatsApp Business App while your connected business platform can also send and receive supported WhatsApp messages through the API.


Coexistence is useful when a business already has an active WhatsApp Business number and does not want to stop using the WhatsApp Business App.


No.

The main purpose of Coexistence is to allow your existing WhatsApp Business App number to also connect to the WhatsApp Business Platform.

You should be a WhatsApp Business App user and should use the same business phone number during the Coexistence onboarding process.


No.

After successful Coexistence onboarding, the WhatsApp Business App remains available.

You can continue using the app while the connected business platform also communicates through the same WhatsApp number.

This is one of the main differences between Coexistence and a traditional migration to the WhatsApp Business Platform.


No.

Your existing conversations remain available in your WhatsApp Business App.


Yes.

Coexistence should not be considered a complete replication of every WhatsApp Business App feature inside an API based platform.

Important points include:

  1. Only supported conversations and message events are synchronized through the Cloud API.
  2. Some functionality available inside the WhatsApp Business App may not be available through the API.
  3. Historical message synchronization can be limited.
  4. Some activity from companion devices may not generate the same API events as activity from the primary WhatsApp Business App.
  5. API initiated messaging must follow WhatsApp Business Platform messaging rules.
  6. Business initiated conversations outside the customer service window require approved message templates.
  7. Meta may change Coexistence capabilities and restrictions over time.

The WhatsApp Business App should therefore continue to be used for app specific functionality, while the connected platform can handle automation, CRM workflows, customer management and API based messaging.

Verify, then trust the connection.


During onboarding, you will normally be taken through Meta's official WhatsApp onboarding process.

You will typically:

  1. Log in using your Facebook account.
  2. Select or create the correct Meta Business Portfolio.
  3. Select or create the appropriate WhatsApp Business Account.
  4. Choose to connect your existing WhatsApp Business App number.
  5. Confirm the business phone number.
  6. Follow the instructions shown inside your WhatsApp Business App.
  7. Authorize the connection.
  8. Complete any requested conversation synchronization.

Once completed, the same phone number can operate through both the WhatsApp Business App and the WhatsApp Business Platform.


Yes.

After onboarding, complete the steps by checking your Meta Business Portfolio.

Go to:

Meta Business Settingshttps://business.facebook.com/settings/latest

OR

Security Centerhttps://business.facebook.com/latest/settings/security_center/

to verify their business, it may take some days to get your business verified — keep check for status on the same link https://business.facebook.com/settings/latest

Make sure you are viewing the same Business Portfolio that was selected during WhatsApp onboarding.

You should review:

  1. Business information
  2. Business verification status
  3. Business phone number
  4. WhatsApp Business Account
  5. WhatsApp phone number
  6. Users and permissions
  7. Billing information where applicable

Ensure billing is setup:

Billing Hubhttps://business.facebook.com/latest/billing_hub/accounts/details/ — add a credit card to activate payment (Master and Visa only)

If your Business Portfolio is not already verified and Meta makes verification available, complete the Business Verification process.

From Meta Business Settings, look for:

Security Center → Business Verification

Meta may request information such as:

  1. Legal business name
  2. Registered business address
  3. Business telephone number
  4. Business website
  5. Business email
  6. Company registration information
  7. Supporting business documents

The information submitted should match your official company records as closely as possible.


Business Verification helps Meta establish the identity of the organization operating the Business Portfolio.

Verification may also be required for certain Meta products, account capabilities, increased messaging usage or additional business features.

A business should therefore complete verification when Meta makes the process available.

If the verification option is not currently visible, that does not necessarily indicate a problem.


Yes.

After onboarding, go to:

Meta Business Settingshttps://business.facebook.com/settings/latest

Then review your Business Info.

Make sure the official company phone number is present and correct.

Also verify:

  1. Legal business name
  2. Registered address
  3. Business website
  4. Business email
  5. Business telephone number

Where possible, these details should match the information appearing on your company registration documents and website.

This is separate from the WhatsApp number itself.

The Business Portfolio should contain the company's official business information, while WhatsApp Manager contains the WhatsApp Business Platform phone number.


Open WhatsApp Manager from your Meta Business Portfolio.

Then open the section containing your WhatsApp phone numbers.

Your connected WhatsApp Business number should appear there.

Check that:

  1. The correct phone number is displayed.
  2. The correct WhatsApp Business Account owns the number.
  3. The business display name is correct.
  4. The number shows as connected or active.
  5. There are no warnings requiring action.

The WhatsApp display name is the business name customers see in association with your WhatsApp Business number.

Meta has specific requirements for WhatsApp Business display names.

Your display name should accurately represent your company, business or brand.

You can review the display name from WhatsApp Manager by selecting the relevant phone number.

If Meta requires approval of the display name, allow the review process to complete before assuming there is an account problem.


The display name can be reviewed from WhatsApp Manager by selecting the relevant phone number. Any change is subject to Meta's review process and display name requirements.

If Meta requires approval of the display name, allow the review process to complete before assuming there is an account problem.

Where a change is needed, submit the new display name from WhatsApp Manager and allow the review process to complete.

Reversible, but not without consequence.


Yes.

Connecting through Coexistence does not mean the number is permanently tied to the API connection.

The WhatsApp Business Platform connection can be disconnected later.

However, disconnecting should be done carefully because any CRM, automation, AI assistant, support platform or API workflow using the number may stop functioning.


When the API connection is disconnected:

  1. The connected CRM or customer engagement platform may no longer receive new WhatsApp conversations.
  2. API based outbound messages will stop.
  3. WhatsApp automations using the Cloud API will stop.
  4. Message templates sent through the API will stop.
  5. Integrations connected to WhatsApp may stop receiving message events.

Your WhatsApp Business App may continue to operate depending on how the disconnection was performed.

Before disconnecting, confirm which systems currently depend on the API connection.


The exact interface can change as Meta updates WhatsApp Business App and WhatsApp Manager.

Coexistence users can be managed through the WhatsApp Business App, WhatsApp Manager or the platform through which Coexistence was originally connected.

You can review your WhatsApp account from:

Meta Business Settings → Accounts → WhatsApp Accounts

and from:

WhatsApp Manager → Phone Numbers

A disconnected number can usually return.


Yes.

A WhatsApp Business App number that has been disconnected can generally be connected again through the supported Coexistence onboarding process, provided that the account and phone number remain eligible.

You should normally reconnect using the same Business Portfolio and WhatsApp Business Account that previously owned the number.


The safest approach is to start the WhatsApp Coexistence onboarding process again from the connected business platform.

You will normally:

  1. Start the WhatsApp connection process.
  2. Log in to Facebook.
  3. Select the correct Meta Business Portfolio.
  4. Select the appropriate WhatsApp Business Account.
  5. Select your existing WhatsApp Business App number.
  6. Authorize the connection.
  7. Complete any confirmation requested inside the WhatsApp Business App.
  8. Allow conversation synchronization where available.
  9. Confirm that the phone number appears correctly in WhatsApp Manager.
  10. Test sending and receiving messages from both sides.

Do not immediately remove the WhatsApp Business Account or phone number from Meta.

First complete the normal WhatsApp Business App registration process on the new or reinstalled device.

After registration, check whether your Coexistence connection is still active.

Then test:

  1. Receiving a WhatsApp message.
  2. Replying from the WhatsApp Business App.
  3. Confirming that the message reaches your connected platform.
  4. Replying from the connected platform.
  5. Confirming that the response appears correctly in WhatsApp Business App.

If the API connection has been disconnected, complete the Coexistence onboarding process again.


Usually, no.

Deleting the WhatsApp number should not be the first troubleshooting step.

First check:

  1. Whether the WhatsApp Business App is working.
  2. Whether the phone number still appears in WhatsApp Manager.
  3. Whether your connected platform shows the WhatsApp connection as active.
  4. Whether the correct Meta Business Portfolio is being used.
  5. Whether permissions are still active.
  6. Whether billing is active where required.
  7. Whether there are any restrictions or warnings in WhatsApp Manager.

Deleting a phone number can turn a relatively simple integration issue into a more complicated onboarding or migration problem.


Yes, in many cases, but moving the number to another provider should be treated differently from simply disconnecting Coexistence.

A provider change may involve:

  1. Changing the integration.
  2. Changing the application connected to the WhatsApp Business Account.
  3. Migrating platform configuration.
  4. Reconfiguring webhooks.
  5. Reconfiguring templates or system integrations.
  6. In some cases, changing WhatsApp Business Account ownership.

Do not delete the number before confirming the correct migration process with the new provider.

Speed is a function of correctness.


To ensure your API messages are delivered as quickly and reliably as possible, you need to make sure you are sending them under the correct WhatsApp messaging conditions and that your WhatsApp Business Platform account is fully set up for sending.

1. Use the correct messaging window

Messages are normally delivered immediately when you are inside the 24 hour customer service window after a customer messages you.

Outside this window, you must use an approved WhatsApp message template.

If an approved template is correctly used, it can be delivered immediately even when the 24 hour customer service window is closed.

2. Payment method and billing requirements

Meta may require a valid payment method for continued or increased usage.

Billing problems can result in:

  1. Message delivery failures
  2. Sending restrictions
  3. Account limitations
  4. Payment related API errors

A missing payment method therefore does not necessarily block every message immediately, but billing should be configured correctly to ensure reliable business messaging.

3. Ensure your billing setup is correctly configured

To avoid unnecessary sending failures:

  1. Add a valid payment method where Meta requires one.
  2. Ensure the WhatsApp Business Account is not in a restricted or unpaid billing state.
  3. Check your payment status.
  4. Check for billing warnings in Meta.
  5. Monitor any account usage or messaging limits.

If billing is not correctly configured, messages may fail or be rejected by the API.

4. Use approved templates for outbound messages

For messages sent outside the 24 hour customer service window:

  1. Use only approved WhatsApp message templates.
  2. Make sure the template is not pending approval.
  3. Make sure the template has not been rejected.
  4. Make sure you are using the correct approved template name and language.
  5. Ensure all required template variables are supplied correctly.

A payment method does not override WhatsApp messaging rules.

An unapproved or incorrectly constructed template can still fail.