> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tawked.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Update a template

> For a connected app's key alone: an application's own key, full access included, answers `403 insufficient_scope`, and writes its templates in the console. Replaces a text template's content on Meta. Send the whole new content: the body of a creation without `name` and `language`, which Meta fixed at creation and which are ignored here. Meta reviews the change again. Only an `APPROVED`, `REJECTED` or `PAUSED` template can be edited; anything else answers `409 template_not_editable` with a `status`: the template's own, `META_SAMPLE` for one of Meta's samples, or `MEDIA_HEADER` for a template that opens with an image or other media, which is edited in the console. An authentication template answers `422 template_category_not_allowed`. Answers the template as it stands after the edit.

Guide: [Templates](/whatsapp/templates)


## OpenAPI

````yaml https://tawked.com/openapi.json patch /v1/whatsapp/templates/{template_id}
openapi: 3.1.0
info:
  title: Tawked API
  version: 2026-09
  summary: >-
    Tawked Verify: OTP verification for Saudi mobile numbers over SMS, in two
    calls. Tawked Notifications: WhatsApp template messages from the
    application's own number. The Partner API for platforms that run Tawked
    Verify for their merchants.
  description: >-
    The public API of Tawked, a Saudi messaging platform: Tawked Verify
    (one-time codes), Tawked Notifications (WhatsApp templates from the
    application's own number) and the Partner API. Tawked Verify is an OTP
    verification API for Saudi numbers. One call sends a one-time code by SMS to
    a Saudi mobile number, and a second call checks it. SAR 0.09 per SMS code
    sent, prepaid; a send the network refuses is refunded. Authenticate with a
    Bearer API key from the dashboard (tk_live_ for production, tk_test_ for the
    sandbox, tk_partner_ for partners, tk_partner_test_ for the partner
    sandbox). Partners (tk_partner_) provision a Verify application per merchant
    under /v1/partner/applications and name it as application on every Verify
    call. Both /v1/... and /api/v1/... answer identically. Rate limit: 120
    requests per minute per key.
  termsOfService: https://tawked.com/en/terms
  license:
    name: Proprietary (Tawked terms of service)
    url: https://tawked.com/en/terms
  contact:
    name: Tawked support
    email: support@tawked.com
    url: https://tawked.com/en/contact
servers:
  - url: https://tawked.com
    description: Production (the sandbox is a tk_test_ key on the same host)
  - url: https://tawked.com/api
    description: The same API under /api/v1/..., kept for older integrations
security:
  - bearerKey: []
  - headerKey: []
tags:
  - name: Verify
    x-group: Verify
    description: Send and check one-time codes.
  - name: WhatsApp
    x-group: Notifications
    description: >-
      Tawked Notifications: send approved WhatsApp templates through the number
      connected to an application. An application in review or approved connects
      its own number from the dashboard.
  - name: Partner
    x-group: Partner API
    description: >-
      For platforms that run Tawked Verify for their merchants: provision a
      Verify application per merchant, keep its brand and verify settings
      current, switch it off and on, and read usage and the code log. Partner
      keys (tk_partner_) only; every Verify operation then takes `application`
      with the partner's own id for the application.
  - name: Webhooks
    x-group: Webhooks
    description: >-
      The events Tawked sends to your endpoint: an application's verification
      outcomes and message statuses, and a partner account's lifecycle, balance
      and opt-in verification events. Every delivery is signed the same way and
      retried the same way.
externalDocs:
  description: Developer docs, with code samples
  url: https://docs.tawked.com
paths:
  /v1/whatsapp/templates/{template_id}:
    patch:
      tags:
        - WhatsApp
      summary: Update a template
      description: >-
        For a connected app's key alone: an application's own key, full access
        included, answers `403 insufficient_scope`, and writes its templates in
        the console. Replaces a text template's content on Meta. Send the whole
        new content: the body of a creation without `name` and `language`, which
        Meta fixed at creation and which are ignored here. Meta reviews the
        change again. Only an `APPROVED`, `REJECTED` or `PAUSED` template can be
        edited; anything else answers `409 template_not_editable` with a
        `status`: the template's own, `META_SAMPLE` for one of Meta's samples,
        or `MEDIA_HEADER` for a template that opens with an image or other
        media, which is edited in the console. An authentication template
        answers `422 template_category_not_allowed`. Answers the template as it
        stands after the edit.
      operationId: whatsapp_template_update
      parameters:
        - name: template_id
          in: path
          required: true
          schema:
            type: string
          description: >-
            The template's Meta id, as `id` in `GET /v1/whatsapp/templates`. One
            id is one language of a template.
        - name: Idempotency-Key
          in: header
          required: false
          description: >-
            A 1 to 128 printable-ASCII-character key you generate, scoped to
            your API key. Replaying it with the same request answers the
            original 2xx unchanged, with the response header
            `Idempotent-Replayed: true`, and runs nothing again; the same key
            with another request answers `409 idempotency_key_reused`, and a
            request still in flight `409 idempotency_in_progress`. A refused
            request is never stored, so a corrected retry under the same key
            runs. Keys expire after 24 hours.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                category:
                  type: string
                  description: >-
                    `UTILITY`. A connected app's key writes utility templates
                    only: `MARKETING` is refused with `422
                    template_category_not_allowed`. An authentication template
                    is created in the console.
                header:
                  type: string
                  description: >-
                    A text header: one line, up to 60 characters, no emoji and
                    no asterisk, at most one placeholder.
                body:
                  type: string
                  description: >-
                    Up to 1024 characters. Placeholders are all named
                    (`{{name}}`, lowercase) or all numbered (`{{1}}`, `{{2}}` in
                    order), never at the very start or end of the text.
                footer:
                  type: string
                  description: One line, up to 60 characters, no placeholders.
                buttons:
                  type: array
                  description: >-
                    Up to 10 objects, each with a `text` of up to 25 characters:
                    `{ "type": "QUICK_REPLY", "text" }`, `{ "type": "URL",
                    "text", "url" }` (https, optionally ending in `{{1}}`; two
                    at most) or `{ "type": "PHONE_NUMBER", "text",
                    "phone_number" }` (E.164; one at most). Quick replies sit
                    together, before or after the other buttons.
                examples:
                  type: object
                  description: >-
                    One sample value per placeholder, keyed `header:<key>`,
                    `body:<key>` and `button:<index>`. Required whenever the
                    template has placeholders: Meta reviews with them.
              required:
                - category
                - body
      responses:
        '200':
          description: The template after the edit
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  name:
                    type: string
                  language:
                    type: string
                  category:
                    type: string
                  status:
                    type: string
                  quality:
                    type:
                      - string
                      - 'null'
                  rejected_reason:
                    type:
                      - string
                      - 'null'
                  components:
                    type: array
                    items:
                      type: object
                      properties:
                        type:
                          type: string
                        format:
                          type: string
                        text:
                          type: string
                        buttons:
                          type: array
                          items:
                            type:
                              - string
                              - 'null'
                  examples:
                    type: object
                    properties:
                      header:1:
                        type: string
                      body:1:
                        type: string
                      body:2:
                        type: string
                      button:0:
                        type: string
                  placeholders:
                    type: object
                    properties:
                      kind:
                        type: string
                      header:
                        type: array
                        items:
                          type: string
                      body:
                        type: array
                        items:
                          type: string
                      buttons:
                        type: array
                        items:
                          type: object
                          properties:
                            index:
                              type: integer
                            type:
                              type: string
                  managed:
                    type: boolean
              examples:
                the_template_after_the_edit:
                  summary: The template after the edit
                  value:
                    id: '7000'
                    name: order_received_v1
                    language: ar
                    category: UTILITY
                    status: PENDING
                    quality: null
                    rejected_reason: null
                    components:
                      - type: HEADER
                        format: TEXT
                        text: طلبك {{1}}
                        buttons: []
                      - type: BODY
                        format: null
                        text: >-
                          استلمنا طلبك رقم {{1}} بقيمة {{2}} ريال، ونبلغك عند
                          شحنه.
                        buttons: []
                      - type: BUTTONS
                        format: null
                        text: null
                        buttons:
                          - type: URL
                            text: تتبع الطلب
                            url: https://flowers.example/orders/{{1}}
                            phone_number: null
                    examples:
                      header:1: '1042'
                      body:1: '1042'
                      body:2: '250'
                      button:0: '1042'
                    placeholders:
                      kind: positional
                      header:
                        - '1'
                      body:
                        - '1'
                        - '2'
                      buttons:
                        - index: 0
                          type: url
                    managed: false
        '400':
          description: >-
            `invalid_json`: The request body is not valid JSON.;
            `invalid_request`: start: `to` (and `phone`) both missing or blank.
            check: `id` or `code` missing.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - invalid_json
                          - invalid_request
        '401':
          description: >-
            `unauthorized`: Missing, unknown, revoked, or mode-mismatched key;
            or an unknown/suspended partner.; `key_expired`: The key's
            `expires_at` has passed. Checked right after the key is recognised,
            before the IP allowlist or scope.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - unauthorized
                          - key_expired
        '403':
          description: >-
            `account_not_active`: The application is not approved yet, the
            account is banned, or a partner disabled this application. All four
            causes share this one response.; `ip_not_allowed`: The caller's IP
            does not match the key's `ip_allowlist` (exact IPs and/or CIDR
            ranges, IPv4 and IPv6).; `insufficient_scope`: The key was not
            granted this call: a custom key without this product, or with a
            level below the call, such as a key that checks where the call
            sends. The response header `WWW-Authenticate` names the scope the
            call needs. Judged right after the key is recognised, before
            `account_not_active` and the request's shape. This operation needs
            `notifications:templates`. An application's own key answers this,
            full access included: only a connected app's key holds that scope.;
            `live_key_required`: A sandbox (tk_test_) key. WhatsApp has no
            sandbox yet; use the application's live key.;
            `whatsapp_not_enabled`: WhatsApp is turned off for this application.
            Message support if you think this is a mistake.;
            `template_not_managed`: A connected app's key on a template that app
            did not create for this application. Such a key edits and deletes
            only the templates it created, the ones `managed` is true on.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - account_not_active
                          - ip_not_allowed
                          - insufficient_scope
                          - live_key_required
                          - whatsapp_not_enabled
                          - template_not_managed
          headers:
            WWW-Authenticate:
              description: >-
                Sent with `insufficient_scope` only: the scope this operation
                needs, which the key was not granted.
              schema:
                type: string
              example: >-
                Bearer error="insufficient_scope",
                scope="notifications:templates"
        '404':
          description: >-
            Not on this number / `not_found`: Unknown id, or an id that belongs
            to a different account or application than the calling key's.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - not_found
              examples:
                not_on_this_number:
                  summary: Not on this number
                  value:
                    error: not_found
        '409':
          description: >-
            Not editable / `no_whatsapp_number`: No WhatsApp number is connected
            to this application yet. Connect one from the Number section of the
            application's Notifications tab in the dashboard (Getting started,
            step 1).; `template_not_editable`: The template cannot be changed
            over the API as it stands; `status` says why. On an edit: the
            template's status when it is not `APPROVED`, `REJECTED` or `PAUSED`,
            or `MEDIA_HEADER` for a template that opens with an image or other
            media, which is edited in the console. On an edit or a delete:
            `META_SAMPLE` for one of Meta's own samples.; `template_in_use`:
            Something still sends the template, so it is neither edited nor
            deleted. `used_by` lists what, from `campaign` (a campaign that has
            not finished), `automation` (an automation that is on) and
            `store_notice` (a store integration's notice that is on), in that
            order. The business stops it or gives it another template in the
            console first.; `idempotency_in_progress`: A request with this
            `Idempotency-Key` is still running. Wait for its answer, or retry in
            a moment.; `idempotency_key_reused`: This `Idempotency-Key` was
            already used for a different request. Use one key per change.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - no_whatsapp_number
                          - template_not_editable
                          - template_in_use
                          - idempotency_in_progress
                          - idempotency_key_reused
              examples:
                not_editable:
                  summary: Not editable
                  value:
                    error: template_not_editable
                    status: PENDING
        '422':
          description: >-
            `template_category_not_allowed`: An AUTHENTICATION template sent
            with a partner key. Partner keys send utility and marketing
            templates; the application's own live key sends authentication ones.
            Also an authentication template in `PATCH
            /v1/whatsapp/templates/{template_id}` (its text is Meta's), and a
            connected app's key on any category but UTILITY, in a send or in a
            template it creates or edits.; `template_refused`: Meta refused the
            template after Tawked's own checks passed; `message` is Meta's own
            sentence (a name already in use, a text it will not review). Also a
            connected app's key that already holds as many templates as it may:
            `message` says so.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - template_category_not_allowed
                          - template_refused
        '429':
          description: >-
            `too_many_requests`: Per-key rate limit exceeded (default 120
            requests/minute, fixed 60s window). Checked before authentication.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - too_many_requests
        '500':
          description: >-
            `internal_error`: An unhandled server error. Quote the X-Request-Id
            header if you report it.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - internal_error
        '503':
          description: >-
            `templates_unavailable`: Meta did not answer the read of the
            number's template list, which the template endpoints and a send need
            before anything happens, or did not answer a template write. Nothing
            was sent, changed or charged; retry shortly.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - templates_unavailable
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |-
            curl -X PATCH https://tawked.com/v1/whatsapp/templates/7000 \
              -H "Authorization: Bearer tk_live_xxxxxxxxxxxxxxxxxxxx" \
              -H "Content-Type: application/json" \
              -H "Idempotency-Key: order_received_v1-ar-2" \
              -d '{
                "category": "UTILITY",
                "header": "طلبك {{1}}",
                "body": "استلمنا طلبك رقم {{1}} بقيمة {{2}} ريال، ونبلغك عند شحنه.",
                "buttons": [
                    {
                        "type": "URL",
                        "text": "تتبع الطلب",
                        "url": "https://flowers.example/orders/{{1}}"
                    }
                ],
                "examples": {
                    "header:1": "1042",
                    "body:1": "1042",
                    "body:2": "250",
                    "button:0": "1042"
                }
            }'
        - lang: javascript
          label: Node.js
          source: >-
            const res = await
            fetch("https://tawked.com/v1/whatsapp/templates/7000", {
              method: "PATCH",
              headers: {
                Authorization: "Bearer tk_live_xxxxxxxxxxxxxxxxxxxx",
                "Content-Type": "application/json",
                "Idempotency-Key": "order_received_v1-ar-2",
              },
              body: JSON.stringify({
                  "category": "UTILITY",
                  "header": "طلبك {{1}}",
                  "body": "استلمنا طلبك رقم {{1}} بقيمة {{2}} ريال، ونبلغك عند شحنه.",
                  "buttons": [
                      {
                          "type": "URL",
                          "text": "تتبع الطلب",
                          "url": "https://flowers.example/orders/{{1}}"
                      }
                  ],
                  "examples": {
                      "header:1": "1042",
                      "body:1": "1042",
                      "body:2": "250",
                      "button:0": "1042"
                  }
              }),
            });

            const data = await res.json();
        - lang: python
          label: Python
          source: |-
            import requests

            res = requests.patch(
                "https://tawked.com/v1/whatsapp/templates/7000",
                headers={"Authorization": "Bearer tk_live_xxxxxxxxxxxxxxxxxxxx", "Idempotency-Key": "order_received_v1-ar-2"},
                json={
                    "category": "UTILITY",
                    "header": "طلبك {{1}}",
                    "body": "استلمنا طلبك رقم {{1}} بقيمة {{2}} ريال، ونبلغك عند شحنه.",
                    "buttons": [
                        {
                            "type": "URL",
                            "text": "تتبع الطلب",
                            "url": "https://flowers.example/orders/{{1}}"
                        }
                    ],
                    "examples": {
                        "header:1": "1042",
                        "body:1": "1042",
                        "body:2": "250",
                        "button:0": "1042"
                    }
                },
            )
            data = res.json()
components:
  schemas:
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          description: A stable machine-readable code; the docs list every one.
      additionalProperties: true
  securitySchemes:
    bearerKey:
      type: http
      scheme: bearer
      description: >-
        Authorization: Bearer <api key>. An application key (tk_live_, tk_test_)
        has full access, which covers every product and any product added later,
        or custom access, chosen when the key is created: one or more of the
        scopes `verify:check`, `verify:send` (includes `verify:check`),
        `notifications:read`, `notifications:send` (includes
        `notifications:read`), `notifications:templates` (includes
        `notifications:read`). No key made on the API keys page holds
        `notifications:templates`, full access included: the three template
        writes answer such a key 403 `insufficient_scope`. A connected app's key
        holds it. A call outside the key's access answers 403
        `insufficient_scope` and names the scope it needs in the
        `WWW-Authenticate` response header. A partner key (tk_partner_) always
        has full access. Whatever its access, a key is a server-side secret.
    headerKey:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        The same API key, with the same access, as a header, for clients that
        cannot set Authorization.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.