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

# Endpoints de templates

> Endpoints REST para gerenciar templates do WhatsApp — listar, criar, atualizar, excluir, enviar para aprovação e semear o pacote inicial.

O Switchbord expõe um pequeno conjunto de endpoints autenticados sob `/api/templates` na aplicação control-plane (`apps/app`) para gerenciar a biblioteca de templates do WhatsApp do workspace. Todas as rotas exigem um operador autenticado com **acesso a settings** (`owner`, `admin` ou `developer`); a rota de seed exige adicionalmente `owner` ou `admin`.

As requisições são restritas ao workspace ativo do chamador — você não pode ver ou alterar templates de outro workspace. Erros de autenticação retornam `401 unauthenticated` ou `403 forbidden`.

## Resumo

| Método | Caminho                            | Finalidade                                 | Papel necessário  |
| ------ | ---------------------------------- | ------------------------------------------ | ----------------- |
| GET    | `/api/templates`                   | Lista todos os templates do workspace      | acesso a settings |
| POST   | `/api/templates`                   | Cria um rascunho de template               | acesso a settings |
| GET    | `/api/templates/{id}`              | Busca um template                          | acesso a settings |
| PUT    | `/api/templates/{id}`              | Atualiza um rascunho de template           | acesso a settings |
| DELETE | `/api/templates/{id}`              | Exclui um rascunho (apenas status `draft`) | acesso a settings |
| POST   | `/api/templates/{id}/submit`       | Envia um rascunho à Meta para aprovação    | acesso a settings |
| POST   | `/api/templates/seed-starter-pack` | Semeia o pacote inicial da GB Viaggi       | owner ou admin    |

***

## GET /api/templates

Lista todos os templates do workspace ativo, ordenados pelos atualizados mais recentemente.

**Resposta 200**

```json theme={null}
{
  "templates": [
    {
      "id": "b3d2b8f1-...",
      "name": "booking_confirmed",
      "language": "it",
      "category": "UTILITY",
      "status": "approved",
      "parameterFormat": "POSITIONAL",
      "components": [ ... ],
      "variables": ["var1", "var2"],
      "preview": "Prenotazione confermata per var1 a var2.",
      "metaTemplateId": "123456789",
      "rejectionReason": null,
      "updatedAt": "2026-04-22T10:15:00Z"
    }
  ]
}
```

**Erros** — `401 unauthenticated`, `403 forbidden`, `500 internal_error`.

***

## POST /api/templates

Cria um novo rascunho de template. O template é armazenado com `status = "draft"` e **não** é enviado à Meta. Use `POST /api/templates/{id}/submit` depois que o rascunho estiver pronto.

**Corpo da requisição**

```json theme={null}
{
  "name": "winback_30d",
  "language": "it",
  "category": "MARKETING",
  "parameterFormat": "POSITIONAL",
  "components": [
    { "type": "BODY",
      "text": "Ciao {{1}}, è passato un po' dall'ultima volta...",
      "example": { "body_text": [["Marco"]] } }
  ]
}
```

Campos:

* `name` (string, obrigatório) — letras minúsculas; caracteres não correspondentes são removidos e substituídos por `_`. Veja [name-regex](/pt-BR/whatsapp/template-rules#name-regex).
* `language` (string, padrão `"en_US"`) — código de locale da Meta, por exemplo `"it"`, `"en_US"`, `"pt_BR"`.
* `category` (`"MARKETING" | "UTILITY" | "AUTHENTICATION"`, padrão `"UTILITY"`).
* `parameterFormat` (`"POSITIONAL" | "NAMED"`, padrão `"POSITIONAL"`).
* `components` (array) — o formato de componente do schema da Meta.

**Resposta 200**

```json theme={null}
{ "template": { "id": "...", "status": "draft", ... } }
```

**Erros** — `400 create_failed` com `message` descrevendo o erro de banco de dados ou de validação, além de erros de autenticação.

***

## GET /api/templates/{id}

Busca um único template por id. Retorna `404 not_found` se o id não existir no workspace do chamador.

**Resposta 200** — mesmo formato de uma entrada de lista.

***

## PUT /api/templates/{id}

Atualiza um ou mais campos de um rascunho de template. Os campos enviados são aplicados (patched); campos não enviados permanecem inalterados.

**Corpo da requisição** (todos os campos são opcionais)

```json theme={null}
{
  "name": "winback_30d_v2",
  "language": "it",
  "category": "MARKETING",
  "parameterFormat": "POSITIONAL",
  "components": [ ... ]
}
```

**Resposta 200**

```json theme={null}
{ "template": { ... } }
```

**Erros** — `400 update_failed`, erros de autenticação.

***

## DELETE /api/templates/{id}

Exclui um rascunho de template. **Apenas templates com `status = "draft"`** podem ser excluídos — uma vez enviado, o template é retido para auditoria. Um template que não é rascunho retorna `409 conflict`.

**Resposta 200**

```json theme={null}
{ "ok": true }
```

**Erros** — `404 not_found`, `409 conflict` com `"Only draft templates can be deleted"`, erros de autenticação.

***

## POST /api/templates/{id}/submit

Envia um rascunho de template ao endpoint `POST /{waba_id}/message_templates` da Meta. O Switchbord primeiro executa o validador completo do lado do cliente (as mesmas regras documentadas em [Regras de template](/pt-BR/whatsapp/template-rules)); se alguma verificação falhar, nenhuma chamada é feita à Meta e é retornado um `400 validation_failed` com o array de problemas (issues) que falharam.

Em caso de sucesso, a linha do template é atualizada com `meta_template_id`, `status = "pending_approval"` e `rejection_reason = null`.

Em caso de rejeição pela Meta (HTTP 4xx com um corpo `error`), a linha é atualizada com `status = "rejected"` e `rejection_reason` = a mensagem legível para humanos da Meta, e um `400 meta_submit_failed` é retornado ao chamador com o payload de erro completo da Meta.

**Resposta 200**

```json theme={null}
{ "template": { "id": "...", "status": "pending_approval", "metaTemplateId": "123456789" } }
```

**Erros**

* `400 validation_failed` — o validador do lado do cliente rejeitou o rascunho. `issues` é o array de issues do Zod.
* `400 meta_submit_failed` — a Meta retornou um erro. `meta` é o objeto `error` bruto da Meta (code, subcode, `error_user_msg`, `error_data.details`).
* `400 no_waba` — nenhuma conta do WhatsApp Business configurada para o workspace.
* `400 no_access_token` — nenhum access token da Meta no vault do workspace.
* `404 not_found`, erros de autenticação.

***

## POST /api/templates/seed-starter-pack

Semeador (seeder) único, restrito a admins, que envia o pacote inicial da GB Viaggi (8 `UTILITY` + 5 `MARKETING`, italiano + inglês quando aplicável) para a Meta e faz upsert das linhas correspondentes na tabela local `templates`. Seguro para reexecutar — a chave de upsert é `(workspace_id, name, locale)`.

Papel necessário: **owner** ou **admin**.

**Corpo da requisição** — vazio.

**Resposta 200**

```json theme={null}
{
  "total": 13,
  "submitted": 11,
  "errored": 2,
  "results": [
    {
      "name": "booking_confirmed",
      "language": "it",
      "category": "UTILITY",
      "status": "submitted",
      "metaTemplateId": "987654321"
    },
    {
      "name": "flash_sale",
      "language": "it",
      "category": "MARKETING",
      "status": "error",
      "error": "Variable parameters in the body text cannot be next to each other."
    }
  ]
}
```

`status` por entrada:

* `submitted` — aceito pela Meta, linha armazenada como `pending_approval`.
* `error` — erro da Meta ou do banco de dados, linha armazenada como `rejected` com a mensagem da Meta.
* `skipped` — reservado; não é emitido atualmente.

**Erros**

* `400 no_waba` — nenhuma conta do WhatsApp Business configurada.
* `400 no_access_token` — segredo `meta-access-token` do vault ausente.
* `500 internal_error` — falha não tratada.
* `401 unauthenticated`, `403 forbidden` — o chamador não possui o papel de owner/admin.

***

## Endpoints internos relacionados

Existem duas rotas internas, não públicas, em `apps/api` para fluxos de sincronização machine-to-machine:

* `POST /internal/templates` — upsert de template do worker para a API após um evento de webhook.
* `POST /internal/templates/sync` — resincronização completa da biblioteca a partir da Meta de volta para o Switchbord.

Essas rotas não são expostas publicamente e não devem ser chamadas a partir do frontend. Veja a [Especificação da API Interna](/pt-BR/api-reference/internal-spec) para a lista oficial.

## OpenAPI

O formato legível por máquina para esses endpoints será gerado em `apps/docs/api-reference/openapi.json` por `pnpm openapi:generate`. Execute o gerador após alterar uma rota para manter a especificação sincronizada.
