Create a WhatsApp Template with OAuth 2.0

Prev Next

You can use the WhatsApp Template Management API to create a new managed WhatsApp template with OAuth 2.0. You can use this API version if you authenticate requests with an OAuth 2.0.

Field naming rule

The token generation request uses snake_case fields, such as client_id and client_secret. Template CRUD request bodies use camelCase fields, such as name, language, category, and components.

Endpoint and Headers

POST https://gw.useinsider.com/api/wa/v2/templates

Headers

Header

Sample Value

Description

Authorization: Bearer your-oauth2-token

1a2b3c4d5e6f

This key is required to authorize your request. Refer to Generate OAuth 2.0 Credentials for WhatsApp Template Management to generate your credentials.

Content-Type

application/json

This header specifies the media type of the resource.

Body Parameters

Column

Data Type

Required

Description

name

String

Yes

The template name to create.

language

String

Yes

The template locale, such as en_US.

category

String

Yes

The Meta template category.

components

Array[object]

Yes

At least one component is required.

Sample Requests

Generate a Gateway Access Token

Before calling the OAuth 2.0 template endpoints, generate a Gateway access token.

curl --location 'https://gw.useinsider.com/auth/token' \
--header 'Content-Type: application/json' \
--data '{
  "client_id": "your-client-id",
  "client_secret": "your-client-secret",
  "scopes": ["wa-temp-read", "wa-temp-manage", "wa-temp-delete"]
}'

Basic Marketing Template with Quick Reply Button

curl --location 'https://gw.useinsider.com/api/wa/v2/templates' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer your-oauth2-token' \
--data '{
  "name": "spring_campaign_template",
  "language": "en_US",
  "category": "MARKETING",
  "components": [
    {
      "type": "BODY",
      "text": "Hi {{1}}, our new spring collection is live now. Tap below to explore best sellers picked for you."
    },
    {
      "type": "BUTTONS",
      "buttons": [
        {
          "type": "QUICK_REPLY",
          "text": "Show products"
        }
      ]
    }
  ]
}'
curl --location 'https://gw.useinsider.com/api/wa/v2/templates' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer your-oauth2-token' \
--data '{
  "name": "order_delivery_update",
  "language": "en_US",
  "category": "UTILITY",
  "components": [
    {
      "type": "HEADER",
      "format": "TEXT",
      "text": "Order update"
    },
    {
      "type": "BODY",
      "text": "Hi {{1}}, your order {{2}} is on the way and will arrive on {{3}}."
    },
    {
      "type": "FOOTER",
      "text": "Thank you for shopping with us."
    },
    {
      "type": "BUTTONS",
      "buttons": [
        {
          "type": "URL",
          "text": "Track package",
          "url": "https://tracking.example.com/orders/{{2}}"
        }
      ]
    }
  ]
}'

Create an Authentication Template with Security Code

curl --location 'https://gw.useinsider.com/api/wa/v2/templates' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer your-oauth2-token' \
--data '{
  "name": "login_code_template",
  "language": "en_US",
  "category": "AUTHENTICATION",
  "components": [
    {
      "type": "BODY",
      "text": "*{{1}}* is your verification code. For your security, do not share this code."
    },
    {
      "type": "BUTTONS",
      "buttons": [
        {
          "type": "OTP",
          "otp_type": "COPY_CODE",
          "text": "Copy code"
        }
      ]
    }
  ]
}'

Upload an Image to the Header

If you want to create a media template,

  1. Upload the asset first through Gateway and reuse the returned handle in the create request.

curl --location 'https://gw.useinsider.com/api/wa/v2/templates/file-upload' \
--header 'Authorization: Bearer your-oauth2-token' \
--form 'file=@"/path/to/spring-banner.png"'
  1. You will receive the sample response below to your upload request.

{
  "id": "4::aW1hZ2UvcG5n:ARbExampleMediaHandle"
}
  1. After the upload completes, send the create request to the Gateway template endpoint with an image header component.

curl --location 'https://gw.useinsider.com/api/wa/v2/templates' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer your-oauth2-token' \
--data '{
  "name": "spring_visual_campaign",
  "language": "en_US",
  "category": "MARKETING",
  "components": [
    {
      "type": "HEADER",
      "format": "IMAGE",
      "example": {
        "header_handle": [
          "4::aW1hZ2UvcG5n:ARbExampleMediaHandle"
        ]
      }
    },
    {
      "type": "BODY",
      "text": "Hi {{1}}, our spring collection is now live. Tap below to browse the new arrivals."
    },
    {
      "type": "BUTTONS", 
      "buttons": [
        {
          "type": "URL",
          "text": "Shop now",
          "url": "https://www.example.com/spring"
        }
      ]
    }
  ]
}'

Sample Responses

A successful request returns the following JSON response with the details of the newly created template.

{
  "id": 42,
  "name": "spring_campaign_template",
  "language": "en_US",
  "quality": "PENDING",
  "status": "IN-REVIEW"
}

Sample Error Responses

Most template endpoint failures return a JSON body with a message field. Creating validation failures can also include an error field. OAuth token and scope failures may be returned by the Gateway before the request reaches the template service.

401 Unauthorized: Invalid OAuth Client Credentials

You will receive this error if the token request contains an invalid client_id or client_secret,

{
  "message": "invalid client credentials"
}

401 Unauthorized: Missing or Invalid Bearer Token

You will receive this error if the token is missing, expired, or malformed.

{
  "message": "unauthorized"
}

403 Forbidden: Missing Required Scope

You will receive this error if the token does not include the required scope for the operation.

{
  "message": "forbidden"
}

400 Bad Request: Invalid JSON Body

You will receive this error if the request body cannot be decoded.

{
  "message": "failed to decode request"
}

400 Bad Request: Missing Required Fields

You will receive this error if a required field, such as name, language, or components is missing.

{
  "message": "failed to validate request",
  "error": "Key: 'CreateRequest.Name' Error:Field validation for 'Name' failed on the 'required' tag"
}

400 Bad Request: Empty Components Array

You will receive this error if components is provided but empty.

{
  "message": "failed to validate request",
  "error": "Key: 'CreateRequest.Components' Error:Field validation for 'Components' failed on the 'min' tag"
}

Invalid List Query Parameters

You will receive this error if the “List” endpoint validation runs before querying templates.

{ "message": "page must be a positive integer" }
{ "message": "per_page must be between 1 and 100" }
{ "message": "sort must be in column|direction format" }
{ "message": "sort column is invalid" }
{ "message": "sort direction is invalid" }

400 Bad Request: Invalid Template ID in Path

You will receive this error if the :id path parameter is not numeric.

{
  "message": "template id is invalid"
}

404 Not Found: Template Not Found

You will receive this error if the template does not exist for the authenticated partner, the detail and delete endpoints return.

{
  "message": "template not found"
}

422 Unprocessable Entity: Router Domain Missing for URL Buttons

You will receive this error if you create a template with URL buttons, but you have no active WhatsApp router domain.

{
  "message": "active whatsapp router domain not found"
}

Meta Rejects the Template Payload

You will receive this error if Meta validation errors are exposed as readable messages. Unsupported button combinations are a common example.

{
  "message": "Invalid parameter - buttons: quick reply and url combination is not supported"
}

400 Bad Request: Upload Request Without a File

You will receive this error if the multipart upload request does not contain a file field.

{
  "message": "file is required"
}

429 Too Many Requests: Upload Rate Limit Exceeded

You will receive this error if you exceed the upload quota.

{
  "message": "upload rate limit exceeded"
}

Media Upload Fails Upstream

If Meta rejects the uploaded file type or upload session, the API returns the upstream message.

{
  "message": "Unsupported post request. Object with ID 'upload-session-id' does not exist"
}

Unexpected Upstream or Local Failure

In less common cases, the API can return internal decoding or persistence errors.

{ "message": "failed to decode template creation response" }
{ "message": "template created in Meta but could not be persisted locally" }