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

# Create template

> Creates a template in the linked number's scope. The body field accepts three shapes: (1) a structured OBJECT { header?, body, footer?, buttons? } — recommended; (2) that same JSON as a STRING; or (3) PLAIN TEXT, auto-wrapped into { "body": { "text": ... } }. Structure: optional header NONE (default) | TEXT (0–1 variable, up to 60 chars) | IMAGE | VIDEO | DOCUMENT — media supplied via header.url (http/https) OR header.base64 (data URI data:<mime>;base64,…, re-hosted server-side); body.text up to 1024 chars, with named-style variables {{nome}} (must not start or end with a variable); footer.text up to 60 chars, no variables; buttons (up to 10 total) of types QUICK_REPLY (≤ 10), URL (≤ 2; static or dynamic with a trailing {{1}} in the URL + a resolved example), PHONE_NUMBER (≤ 1) and COPY_CODE (≤ 1; the code goes in button.example) — mixing quick-reply with CTA buttons is allowed. Buttons may accompany a video or document (PDF) header. The examples field is REQUIRED whenever the body/header (or the dynamic URL) uses variables: an object mapping each variable to a sample value; missing → 400 { code: "TEMPLATE_EXAMPLES_REQUIRED", details: { missing: [...] } }. For Meta numbers the template is submitted to Meta for approval (metaStatus PENDING); 400 META_TEMPLATE_SUBMIT_FAILED if Meta rejects it. 409 if a template with that name already exists. Requires a number-scoped key.

**Requires a number-scoped key.**



## OpenAPI

````yaml openapi.json POST /v1/templates
openapi: 3.1.0
info:
  title: Pilot Status API
  version: 1.0.0
  license:
    name: Pilot Status Terms of Service
    url: https://pilotstatus.com.br/terms
  description: >-
    Public REST API for Pilot Status. Authenticate with the `x-api-key: ps_...`
    header (or `x-api-key-id`). Base URL: https://pilotstatus.com.br
servers:
  - url: https://pilotstatus.com.br
security:
  - apiKey: []
  - apiKeyId: []
paths:
  /v1/templates:
    post:
      tags:
        - Templates
      summary: Create template
      description: >-
        Creates a template in the linked number's scope. The body field accepts
        three shapes: (1) a structured OBJECT { header?, body, footer?, buttons?
        } — recommended; (2) that same JSON as a STRING; or (3) PLAIN TEXT,
        auto-wrapped into { "body": { "text": ... } }. Structure: optional
        header NONE (default) | TEXT (0–1 variable, up to 60 chars) | IMAGE |
        VIDEO | DOCUMENT — media supplied via header.url (http/https) OR
        header.base64 (data URI data:<mime>;base64,…, re-hosted server-side);
        body.text up to 1024 chars, with named-style variables {{nome}} (must
        not start or end with a variable); footer.text up to 60 chars, no
        variables; buttons (up to 10 total) of types QUICK_REPLY (≤ 10), URL (≤
        2; static or dynamic with a trailing {{1}} in the URL + a resolved
        example), PHONE_NUMBER (≤ 1) and COPY_CODE (≤ 1; the code goes in
        button.example) — mixing quick-reply with CTA buttons is allowed.
        Buttons may accompany a video or document (PDF) header. The examples
        field is REQUIRED whenever the body/header (or the dynamic URL) uses
        variables: an object mapping each variable to a sample value; missing →
        400 { code: "TEMPLATE_EXAMPLES_REQUIRED", details: { missing: [...] } }.
        For Meta numbers the template is submitted to Meta for approval
        (metaStatus PENDING); 400 META_TEMPLATE_SUBMIT_FAILED if Meta rejects
        it. 409 if a template with that name already exists. Requires a
        number-scoped key.


        **Requires a number-scoped key.**
      operationId: post_templates
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: Template name (letters/numbers only; separators become _).
                  example: promo_cupom
                body:
                  type: string
                  description: >-
                    Template content: object { header?, body, footer?, buttons?
                    } (recommended), the same JSON as a string, or plain text
                    (auto-wrapped).
                  example: '{ "body": { "text": "Oi {{nome}}!" } }'
                body.header:
                  type: string
                  description: >-
                    Optional header. TEXT: text with 0–1 variable (up to 60
                    chars). IMAGE/VIDEO/DOCUMENT: provide url (http/https) OR
                    base64 (data URI); base64 is re-hosted server-side. No
                    location header.
                  example: '{ "type": "IMAGE", "base64": "data:image/png;base64,..." }'
                body.footer:
                  type: string
                  description: Optional footer, up to 60 chars, no variables.
                  example: '{ "text": "Promoção por tempo limitado" }'
                body.buttons:
                  type: string
                  description: >-
                    Up to 10 buttons: QUICK_REPLY (≤ 10; text), URL (≤ 2; text +
                    static url or dynamic with trailing {{1}}), PHONE_NUMBER (≤
                    1; text + phone_number E.164), COPY_CODE (≤ 1; code in
                    example). Quick-reply and CTA can coexist.
                  example: >-
                    [{ "type": "URL", "text": "Comprar", "url":
                    "https://loja.com/promo/{{link}}" }, { "type": "COPY_CODE",
                    "example": ["PROMO10"] }]
                examples:
                  type: string
                  description: >-
                    Required when variables exist: maps each variable used in
                    body/header (and the dynamic URL) to a sample value. The
                    COPY_CODE code goes in button.example, not here. Missing →
                    400 TEMPLATE_EXAMPLES_REQUIRED.
                  example: '{ "nome": "Maria", "desconto": "10%", "link": "abc123" }'
                category:
                  type: string
                  description: Template category (default UTILITY).
                  example: MARKETING
                language:
                  type: string
                  description: Template language (default pt_BR).
                  example: pt_BR
              required:
                - name
                - body
            example:
              name: promo_cupom
              category: MARKETING
              language: pt_BR
              body:
                header:
                  type: IMAGE
                  base64: data:image/png;base64,...
                body:
                  text: Oi {{nome}}! Use e ganhe {{desconto}} de desconto.
                footer:
                  text: Promoção por tempo limitado
                buttons:
                  - type: QUICK_REPLY
                    text: Quero!
                  - type: URL
                    text: Comprar
                    url: https://loja.com/promo/{{link}}
                  - type: PHONE_NUMBER
                    text: Falar
                    phone_number: '+5511999998888'
                  - type: COPY_CODE
                    example:
                      - PROMO10
              examples:
                nome: Maria
                desconto: 10%
                link: abc123
      responses:
        '201':
          description: Create full template
          content:
            application/json:
              example:
                id: tpl_01HZX...
                name: promo_cupom
                category: MARKETING
                metaStatus: PENDING
        '400':
          description: Missing examples
          content:
            application/json:
              example:
                code: TEMPLATE_EXAMPLES_REQUIRED
                details:
                  missing:
                    - nome
        '401':
          description: Missing or invalid `x-api-key` / `x-api-key-id` header
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  code:
                    type: string
              example:
                error: Unauthorized
        '403':
          description: Tenant-scoped key used on a number-scoped endpoint
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  code:
                    type: string
              example:
                error: Tenant-scoped keys cannot call number endpoints
                code: TENANT_SCOPE_NOT_ALLOWED
        '429':
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  code:
                    type: string
              example:
                error: Too many requests
components:
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: x-api-key
      description: Your ps_ API key
    apiKeyId:
      type: apiKey
      in: header
      name: x-api-key-id
      description: API key id (alternative to x-api-key)

````