---
title: "Convenções e erros"
slug: conventions
group: "Primeiros passos"
source: https://linkzap.orion.moe/developers/conventions
openapi: https://linkzap.orion.moe/openapi.json
---

# Convenções e erros

As regras que valem para todas as rotas — leia uma vez e não precise reler em cada página.

## URL base e formato

Toda rota mora sob `https://linkzap.orion.moe/api/v1`. Pedido e resposta são JSON em UTF-8; as rotas que recebem corpo esperam `Content-Type: application/json`.

O que volta fica sempre dentro de `data`. É uma casca aparentemente inútil, e ela existe para que acrescentar um campo ao lado (`page`, `total`, `created`) nunca quebre quem já lê o que está dentro.

## Paginação

**Três listas são paginadas** — `GET /contacts`, `GET /conversations` e `GET /messages`. Elas aceitam `page` (a partir de 1) e `limit` (1 a 200, padrão 50), e devolvem `total` no corpo: o número de itens que casam com o filtro, não o da página.

**Duas não são**, porque não crescem: `GET /channels` e `GET /flows` devolvem tudo de uma vez, num `{ data: [...] }` seco, sem `page`, `limit` nem `total`. Uma conta tem alguns números e algumas dezenas de fluxos — paginar ali seria cerimônia sem motivo.

Exemplo — Segunda página, de 20 em 20:

```bash
curl "https://linkzap.orion.moe/api/v1/contacts?page=2&limit=20" \
  -H "Authorization: Bearer lz_SUA_CHAVE"
```

## Datas e telefones

- **Datas** saem em ISO-8601 com fuso UTC (`2026-09-21T14:03:11.000Z`). Converta para o fuso da sua operação na hora de mostrar — o painel faz isso com o fuso que está em Configurações → Geral.
- **Telefones** entram como DDI + DDD + número, só dígitos: `5592999990000`. Aceitamos com `+`, espaço, parêntese e traço e normalizamos; o que não vira um número brasileiro válido responde 422. Nas respostas o telefone volta sempre normalizado.
- **Identificadores** são strings opacas. Não tente derivar nada delas nem presuma tamanho.

## Erros

Todo erro é um JSON com `error` — uma frase em português, escrita para aparecer no seu log ou para a sua equipe ler. Quando o problema é de validação, vem junto `issues`, apontando campo por campo.

Exemplo — 422 com o campo apontado:

```json
{
  "error": "Dados inválidos.",
  "issues": [
    { "path": "phone", "message": "String must contain at least 8 character(s)" }
  ]
}
```

**Os status que você vai encontrar**

| Status | Significado | Quando acontece |
| --- | --- | --- |
| `200` | Deu certo | O corpo traz `data`, e nas listas também `page`, `limit` e `total`. |
| `201` | Criou | Algo passou a existir: um contato novo, uma mensagem, um fluxo iniciado. |
| `400` | O corpo não é JSON | Só em `POST`: o texto enviado não foi lido como JSON. Confira a vírgula sobrando e o `Content-Type`. Campo faltando ou fora do formato **não** é 400, é 422. |
| `401` | Chave ausente, inválida ou revogada | Não tente de novo com a mesma chave — ela não vai passar a valer. |
| `403` | Fora do escopo | Uma chave de canal pedindo outro canal. É 403 e não 404 de propósito: não dizemos se o outro canal existe. |
| `404` | Não existe | Canal, conversa, contato, fluxo ou arquivo que não é desta organização. |
| `409` | Existe, mas não dá agora | O caso comum é o número não estar pronto para enviar; o motivo vem em palavras. |
| `422` | Os dados não passam | Telefone fora do formato, campo faltando, valor longo demais. Vem com `issues[]` apontando o campo. |
| `429` | Rápido demais | Espere o que o `Retry-After` disser. |
| `500` | Foi culpa nossa | Tente de novo com recuo. Se persistir, fale com o suporte com o horário da chamada. |

## Limite de chamadas

Cada chave pode fazer **120 chamadas por minuto**, e a organização inteira, **600** somando todas as chaves. Passando disso, a resposta é `429` com `Retry-After` em segundos — espere o que ele disser em vez de tentar em laço.

> [!NOTE]
> **Precisa de mais?**
>
> Os limites são generosos para integração de verdade e apertados para laço acidental. Se a sua operação passa disso de forma legítima, fale com o suporte antes de espalhar chaves para contornar — o teto da organização soma todas elas.

## Repetir sem estragar

`POST /contacts` é idempotente pelo telefone: chamar duas vezes atualiza, não duplica (o `created` da resposta diz qual dos dois aconteceu). `POST /messages` **não é** — cada chamada manda uma mensagem. Se o seu código tem retentativa automática, guarde o `messageId` que voltou antes de tentar de novo.
