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

# Criar template

> Cria o template e envia para aprovação da Meta. `providerStatus` nasce
`PENDING`; o resultado chega pelo webhook `template.updated`.

- O nome é único por conta WhatsApp Business. Repetido: `409 CONFLICT`.
- Em `AUTHENTICATION` o conteúdo é fixo: a Arara envia à Meta o texto
  `{{1}} é o seu código de verificação` com um botão de copiar código, em
  `pt_BR`. `body`, `buttons` e `language` enviados não mudam o template
  aprovado. No envio, passe o código como única variável.
- Exige conta ativa (`403 ACCOUNT_NOT_ACTIVATED`).
- Os planos atuais não têm limite de templates. Contas no plano Free legado
  têm teto de 3 templates aprovados e recebem `403 PLAN_LIMIT_REACHED`.

Permissão: `TEMPLATES_WRITE`.




## OpenAPI

````yaml /openapi.yaml post /v1/templates
openapi: 3.0.3
info:
  title: API da Arara
  description: >
    API REST da Arara para WhatsApp Business: mensagens, templates, campanhas,

    contatos, conversas, formulários, automações, smart links e carteira.


    Esta especificação cobre só os endpoints que aceitam **chave de API**

    (`Authorization: Bearer ara_live_...`). Rotas usadas apenas pelo painel

    (gestão de chaves, configuração do webhook, pagamentos e perfil pessoal)

    ficam de fora.


    ## Autenticação


    Header `Authorization: Bearer ara_live_...`. Crie a chave em

    https://app.ararahq.com/dashboard/apikeys. As chaves são sempre LIVE:

    mensagens são entregues de verdade e o custo sai da carteira.


    ## Permissões da chave


    Chave criada sem permissões explícitas tem acesso total (`ADMIN`). Chave

    com permissões restritas só alcança:


    - `READ`: `GET` em `/v1/messages`, `/v1/campaigns`, `/v1/templates`,
      `/v1/flows`, `/v1/automations` e `/v1/organizations/me/numbers`.
    - `MESSAGES_SEND`: escrita em `/v1/messages/**`, `POST /v1/media/upload` e
      `POST /v1/flows/{id}/test`.
    - `TEMPLATES_WRITE`: escrita em `/v1/templates/**` e `/v1/flows/**`.

    - `CAMPAIGNS_SEND`: escrita em `/v1/campaigns/**`.

    - `CONTACTS_WRITE`: escrita em `/v1/contacts/**`.

    - `AUTOMATIONS_MANAGE`: escrita em `/v1/automations/**`.

    - `WEBHOOKS_MANAGE`: escrita em `/webhook/**`.


    Qualquer outra rota exige `ADMIN`. Fora do escopo, a resposta é `403`.


    ## Rate limit


    Por usuário da chave: 1.200 leituras (`GET`) por minuto e 3.000 escritas por

    minuto. Toda resposta traz `X-RateLimit-Remaining`. Acima do limite: `429`

    com `Retry-After` e `error.code = RATE_LIMIT_EXCEEDED`. O envio tem limites

    próprios (`SEND_RATE_LIMITED`, `BATCH_BUSY`,
    `MARKETING_FREQUENCY_EXCEEDED`).


    ## Formato de erro


    ```json

    { "error": { "code": "ERROR_CODE", "message": "Descrição", "details": {} } }

    ```


    Exceções: falha de autenticação (`401`, `403` e `503` do filtro de chave)

    volta no formato padrão do Spring (`timestamp`, `status`, `error`, `path`,

    sem `code`), e alguns `404` e `403` voltam sem corpo.
  version: 2.1.0
  contact:
    name: AraraHQ
    url: https://ararahq.com
    email: oi@ararahq.com
servers:
  - url: https://api.ararahq.com
    description: Produção
security:
  - bearerAuth: []
tags:
  - name: Mensagens
    description: Envio, consulta e histórico de mensagens de WhatsApp, e upload de mídia.
  - name: Conversas
    description: >-
      Conversas com cada telefone, resposta dentro da janela de 24h e situação
      da janela.
  - name: Templates
    description: Criação, listagem, status de aprovação e métricas de templates.
  - name: Campanhas
    description: >-
      Envio do mesmo template para muitos contatos, com estimativa, agendamento,
      cancelamento e teste A/B.
  - name: Contatos
    description: Base de contatos da organização e direitos do titular (LGPD).
  - name: Opt-out
    description: Registro e consulta de quem pediu para não receber mensagens.
  - name: Formulários
    description: >-
      Formulários nativos do WhatsApp (Flows) e as respostas recebidas.
      Disponíveis do plano Voo para cima.
  - name: Automações
    description: >-
      Sequências de passos que rodam sozinhas para cada contato que entra por um
      gatilho. Exigem plano com recuperação de receita.
  - name: Smart Links
    description: Links wa.me rastreáveis, com QR code.
  - name: Números
    description: >-
      Números de WhatsApp da organização e o perfil comercial exibido no
      WhatsApp.
  - name: Carteira
    description: Saldo, extrato, recarga automática e preços.
  - name: Consulta de telefone
    description: Consulta de tipo de linha e de WhatsApp de um número (cobrada).
  - name: Recuperação
    description: Endpoint de recuperação de receita (carrinho abandonado, Pix, boleto).
  - name: Conta
    description: Identidade da chave, plano da organização e status da API.
paths:
  /v1/templates:
    post:
      tags:
        - Templates
      summary: Criar template
      description: >
        Cria o template e envia para aprovação da Meta. `providerStatus` nasce

        `PENDING`; o resultado chega pelo webhook `template.updated`.


        - O nome é único por conta WhatsApp Business. Repetido: `409 CONFLICT`.

        - Em `AUTHENTICATION` o conteúdo é fixo: a Arara envia à Meta o texto
          `{{1}} é o seu código de verificação` com um botão de copiar código, em
          `pt_BR`. `body`, `buttons` e `language` enviados não mudam o template
          aprovado. No envio, passe o código como única variável.
        - Exige conta ativa (`403 ACCOUNT_NOT_ACTIVATED`).

        - Os planos atuais não têm limite de templates. Contas no plano Free
        legado
          têm teto de 3 templates aprovados e recebem `403 PLAN_LIMIT_REACHED`.

        Permissão: `TEMPLATES_WRITE`.
      operationId: createTemplate
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTemplateRequest'
            examples:
              simples:
                summary: Texto com variáveis
                value:
                  name: pedido_confirmado
                  category: UTILITY
                  language: pt_BR
                  body: 'Oi {{1}}, seu pedido {{2}} foi confirmado. Total: R$ {{3}}.'
                  footer: Acompanhe pelo nosso site
                  samples:
                    '1': João
                    '2': '12345'
                    '3': 147,90
              botoes:
                summary: Com botões
                value:
                  name: pedido_enviado
                  category: UTILITY
                  body: Oi {{1}}, seu pedido saiu para entrega.
                  samples:
                    '1': João
                  buttons:
                    - type: QUICK_REPLY
                      text: Confirmar
                    - type: URL
                      text: Ver pedido
                      url: https://meusite.com/p/{{1}}
              carrossel:
                summary: Carrossel
                value:
                  name: produtos_destaque
                  category: MARKETING
                  body: 'Confira nossas ofertas da semana:'
                  carouselCards:
                    - mediaUrl: https://meusite.com/produto-1.jpg
                      body: Camiseta básica por R$ 79
                      buttons:
                        - type: URL
                          text: Comprar
                          url: https://meusite.com/p/1
                    - mediaUrl: https://meusite.com/produto-2.jpg
                      body: Tênis de corrida por R$ 299
                      buttons:
                        - type: URL
                          text: Comprar
                          url: https://meusite.com/p/2
              autenticacao:
                summary: Código de verificação
                value:
                  name: otp_login
                  category: AUTHENTICATION
                  body: Código de verificação
              formulario:
                summary: Botão de formulário
                value:
                  name: captar_contato
                  category: MARKETING
                  body: Oi, conta para a gente o que você procura?
                  buttons:
                    - type: FLOW
                      text: Responder
                      flowId: 0b7e6a52-3c1d-4f7a-9a55-2f4f6f1f9c10
      responses:
        '201':
          description: Template criado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TemplateResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: |
            - Autenticação (corpo padrão do Spring): header ausente ou chave sem
              `TEMPLATES_WRITE`.
            - `ACCOUNT_NOT_ACTIVATED`: conta ainda não ativada.
            - `PLAN_LIMIT_REACHED`: só no plano Free legado, que tem teto de 3
              templates aprovados. Os planos atuais não têm limite.
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/SpringError'
              example:
                error:
                  code: PLAN_LIMIT_REACHED
                  message: Limite de templates do plano atingido.
                  details:
                    feature: TEMPLATES
                    current: 3
                    max: 3
                    currentPlan: FREE
                    upgradeTo: ESSENTIAL
        '409':
          description: >-
            `CONFLICT`: já existe um template com esse nome na mesma conta
            WhatsApp Business, ou o conteúdo foi bloqueado pela moderação da
            Arara.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: CONFLICT
                  message: Já existe um template com o nome 'pedido_confirmado'.
                  details: {}
        '422':
          description: >-
            `UNPROCESSABLE_ENTITY`: categoria inválida, variável no começo ou no
            fim do corpo, botões ou carrossel fora dos limites, exemplos
            faltando.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: UNPROCESSABLE_ENTITY
                  message: O corpo não pode começar nem terminar com uma variável.
                  details: {}
        '429':
          $ref: '#/components/responses/RateLimited'
components:
  schemas:
    CreateTemplateRequest:
      type: object
      required:
        - name
        - category
        - body
      properties:
        name:
          type: string
          description: Nome do template. Único por conta WhatsApp Business.
          example: pedido_confirmado
        category:
          type: string
          enum:
            - MARKETING
            - UTILITY
            - AUTHENTICATION
          description: >-
            Categoria avaliada pela Meta. Em `AUTHENTICATION` o conteúdo é fixo
            (veja a descrição do endpoint).
        body:
          type: string
          description: >-
            Texto com variáveis `{{1}}`, `{{2}}`... Não pode começar nem
            terminar com variável.
        language:
          type: string
          default: pt_BR
          description: Idioma do template.
        header:
          type: string
          nullable: true
          description: 'Cabeçalho: texto simples ou URL de mídia.'
        headerType:
          type: string
          nullable: true
          enum:
            - text
            - media
            - document
          description: Tipo do cabeçalho.
        footer:
          type: string
          nullable: true
          description: Rodapé.
        buttons:
          type: array
          nullable: true
          items:
            $ref: '#/components/schemas/TemplateButton'
          description: >-
            Até 10 botões, com no máximo 2 de link (`URL` + `SMART_LINK`), 1 de
            telefone e 1 de formulário.
        samples:
          type: object
          nullable: true
          additionalProperties:
            type: string
          description: >-
            Exemplo por número da variável (`{"1": "João"}`). A Meta usa na
            revisão. Precisa ser objeto: array responde `400 INVALID_JSON`.
        variableExamples:
          type: array
          nullable: true
          items:
            type: string
          description: Legado. Prefira `samples`.
        carouselCards:
          type: array
          nullable: true
          items:
            $ref: '#/components/schemas/CarouselCard'
          description: >-
            Carrossel, de 2 a 10 cards. Todos os cards precisam ter a mesma
            estrutura de botões.
          minItems: 2
          maxItems: 10
    TemplateResponse:
      type: object
      required:
        - id
        - name
        - formattedName
        - category
        - language
        - providerName
        - providerTemplateId
        - providerStatus
        - availableForSending
        - structureJson
        - createdAt
      properties:
        id:
          type: string
          format: uuid
          description: ID do template (UUID).
        name:
          type: string
        formattedName:
          type: string
        category:
          type: string
          description: Categoria atual. A Meta pode mudar a categoria na revisão.
        originalCategory:
          type: string
          nullable: true
          description: Categoria pedida na criação.
        language:
          type: string
        providerName:
          type: string
          example: GUPSHUP
        providerTemplateId:
          type: string
        providerStatus:
          type: string
          example: APPROVED
          description: >
            Status de aprovação:


            - `PENDING`: em revisão.

            - `APPROVED`: pronto para enviar.

            - `REJECTED`: reprovado. Veja `rejectionReason`.

            - `PAUSED`: pausado pela Meta ou pela proteção automática da Arara.
            O
              envio responde `422 TEMPLATE_PAUSED`.
            - `DISABLED`: desativado. O envio responde `422
            TEMPLATE_NOT_SENDABLE`.
        rejectionReason:
          type: string
          nullable: true
        availableForSending:
          type: boolean
          description: >-
            `false` quando o template foi aprovado em um número que a
            organização não usa mais. Recrie o template no número ativo.
        unavailableReason:
          type: string
          nullable: true
        bodyPreview:
          type: string
          nullable: true
          description: Corpo do template, com os marcadores de variável.
        structureJson:
          type: object
          additionalProperties: true
        usageGuide:
          type: object
          nullable: true
          additionalProperties: true
        variablesSchema:
          type: object
          nullable: true
          additionalProperties:
            type: string
          description: Exemplos por número da variável.
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
          nullable: true
      example:
        id: a7f3c1e2-4b5d-6789-abcd-ef0123456789
        name: pedido_confirmado
        formattedName: pedido_confirmado
        category: UTILITY
        originalCategory: UTILITY
        language: pt_BR
        providerName: GUPSHUP
        providerTemplateId: 4c1f0e9a-2b3d-4e5f-8a6b-7c8d9e0f1a2b
        providerStatus: PENDING
        rejectionReason: null
        availableForSending: true
        unavailableReason: null
        bodyPreview: 'Oi {{1}}, seu pedido {{2}} foi confirmado. Total: R$ {{3}}.'
        structureJson: {}
        usageGuide:
          message: >-
            Use o objeto 'variables' no envio da mensagem para substituir os
            placeholders.
          endpoint: POST /v1/messages
        variablesSchema:
          '1': João
          '2': '12345'
          '3': 147,90
        createdAt: '2026-09-15T14:30:00Z'
        updatedAt: null
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              example: INSUFFICIENT_FUNDS
              description: >-
                Código estável do erro. Use este campo no seu tratamento, não a
                mensagem.
            message:
              type: string
              nullable: true
              description: Descrição legível, em português. Pode mudar.
            details:
              type: object
              additionalProperties: true
              description: Dados extras do erro. Vazio na maioria dos casos.
      example:
        error:
          code: INSUFFICIENT_FUNDS
          message: Saldo insuficiente.
          details: {}
    SpringError:
      type: object
      description: >-
        Corpo padrão do Spring nas falhas de autenticação (`401`, `403` e `503`
        do filtro de chave). Não tem `error.code`.
      properties:
        timestamp:
          type: string
          format: date-time
        status:
          type: integer
          example: 401
        error:
          type: string
          example: Unauthorized
        path:
          type: string
          example: /v1/messages
    TemplateButton:
      type: object
      required:
        - type
        - text
      properties:
        type:
          type: string
          enum:
            - QUICK_REPLY
            - URL
            - PHONE_NUMBER
            - SMART_LINK
            - COPY_CODE
            - FLOW
            - CHARGE
          description: >
            - `QUICK_REPLY`: resposta rápida.

            - `URL`: abre um link. Aceita variável no fim da URL.

            - `PHONE_NUMBER`: liga para o número em `phone`.

            - `SMART_LINK`: link rastreável da Arara.

            - `COPY_CODE`: copia um código.

            - `FLOW`: abre o formulário de `flowId`. Um por template.

            - `CHARGE`: botão de cobrança. A cobrança vai no campo `charge` do
            envio.
        text:
          type: string
          maxLength: 20
          description: Texto do botão, até 20 caracteres.
        url:
          type: string
          nullable: true
          description: Só em `URL` e `SMART_LINK`.
        phone:
          type: string
          nullable: true
          description: Só em `PHONE_NUMBER`.
        flowId:
          type: string
          format: uuid
          nullable: true
          description: >-
            Só em `FLOW`. O `id` do formulário, criado no mesmo número do
            template.
        extraConfig:
          type: object
          nullable: true
          additionalProperties: true
    CarouselCard:
      type: object
      required:
        - mediaUrl
        - body
      properties:
        mediaUrl:
          type: string
          description: URL da imagem ou do vídeo do card.
        body:
          type: string
          description: Texto do card.
        buttons:
          type: array
          nullable: true
          items:
            $ref: '#/components/schemas/TemplateButton'
          description: Até 2 botões por card.
  responses:
    BadRequest:
      description: >-
        Requisição inválida: `VALIDATION_ERROR` (campo obrigatório ausente ou
        regra do corpo), `INVALID_JSON` (JSON malformado ou tipo errado),
        `INVALID_PATH_PARAM` ou `INVALID_IDEMPOTENCY_KEY`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: VALIDATION_ERROR
              message: O número do recebedor é obrigatório
              details: {}
    Unauthorized:
      description: >
        Chave inexistente, revogada, expirada, com prefixo errado (`ara_` sem

        `ara_live_`) ou vinda de IP fora da allowlist. O corpo é o JSON padrão
        do

        Spring, sem `error.code`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/SpringError'
          example:
            timestamp: '2026-09-15T14:30:00.000+00:00'
            status: 401
            error: Unauthorized
            path: /v1/messages
    RateLimited:
      description: >-
        `RATE_LIMIT_EXCEEDED`: limite geral da API (1.200 leituras ou 3.000
        escritas por minuto, por usuário da chave).
      headers:
        Retry-After:
          schema:
            type: integer
          description: Segundos a aguardar antes de repetir a chamada.
        X-RateLimit-Remaining:
          schema:
            type: integer
          description: Requisições restantes na janela atual.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: RATE_LIMIT_EXCEEDED
              message: Muitas requisições. Tente de novo em instantes.
              details: {}
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: ara_live_...
      description: >-
        Chave de API da Arara (`ara_live_...`), enviada no header
        `Authorization: Bearer ara_live_...`. Crie e gerencie as chaves no
        painel: https://app.ararahq.com/dashboard/apikeys. O valor completo
        aparece uma única vez, na criação.

````

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