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

> ## Agent Instructions
> Documentação das APIs da DeliveryVip, em português. Regras que mais quebram integrações: (1) Merchant API: faça polling em GET /merchant/v3/events:polling no máximo a cada 30 s por token; confirme todo evento recebido com POST /merchant/v3/events/acknowledgment e corpo [{"id": "<eventId>"}] (o campo lido é id, não eventId), inclusive eventos repetidos ou que o sistema não trata; deduplique por eventId; o evento é só um aviso, busque o pedido na orderURL. (2) Tokens client_credentials valem 24 h e não têm refresh_token: peça outro ao receber 401. (3) Webhooks: valide a assinatura HMAC sobre o corpo bruto e responda 2xx rápido; o polling é a reconciliação. (4) Open Delivery: host od.deliveryvip.com.br, um client_secret por loja, datas em UTC. (5) Fidelidade: o operador implementa 5 rotas assinadas com HMAC e chama o config push; o estorno precisa ser idempotente. (6) Partner API: scope dv.partner. Não invente endpoints: use a referência gerada das specs OpenAPI.

# Erros

> O formato do corpo de erro das APIs da DeliveryVip e o que fazer com cada status HTTP.

Quando uma chamada falha, a API responde com um status HTTP de erro e, na maioria dos casos, um corpo JSON curto com o status e a mensagem. Trate os erros **pelo status HTTP**: a mensagem serve para log e depuração, não para lógica.

## Formato da resposta

```json 422 Unprocessable Content theme={null}
{
  "status": "422",
  "title": "Subscription must be activated"
}
```

**status** `string`

O código HTTP, **como string** (`"404"`, `"422"`).

**title** `string`

A mensagem do erro, em inglês. Quando há mais de uma, elas vêm juntas na mesma string, separadas por `|`.

O formato vale para a Merchant API V3, a Partner API V2 e o Open Delivery.

> [!WARNING]
>
> **Exceções ao formato.** Não assuma que todo erro tem corpo:
>
> * `401` vem com `status` **numérico**: `{ "title": "Unauthorized", "status": 401 }`.
> * `403` por falta de scope vem **sem corpo**.
> * O endpoint de token (`/authentication/v1/oauth/token`) usa o padrão OAuth2, com `error` e `error_description`. Veja [Autenticação](/docs/inicio/conceitos/autenticacao.md#erros-de-autenticação).
> * `429` pode vir sem o corpo padrão. Veja [Rate limiting](/docs/inicio/conceitos/rate-limiting.md).

## Códigos HTTP

| Código | Significado | Quando acontece | O que fazer |
| - | - | - | - |
| `400` | Bad Request | Parâmetros incompatíveis, como enviar os cursores `next` e `previous` juntos. | Corrija a requisição; repetir não resolve. |
| `401` | Unauthorized | Token ausente, expirado ou revogado. | Obtenha um novo token e repita uma vez. |
| `403` | Forbidden | Token sem o scope da rota, JSON malformado no corpo, filtro inválido no polling ou loja sem acesso em `x-polling-merchants` / `x-partners`. | Confira scope, corpo e headers. Não repita sem corrigir. |
| `404` | Not Found | O recurso não existe ou não pertence às lojas que instalaram o seu app (`"title": "Record not found"`). | Confira o ID e se a loja instalou o app. |
| `406` | Not Acceptable | Parâmetros inválidos em listagens e no acknowledgment, como datas fora do formato em `GET /merchant/v3/{merchantId}/orders`. | Corrija os parâmetros. |
| `422` | Unprocessable Content | Dados inválidos para a regra de negócio, ou campo obrigatório ausente (`"param is missing: ..."`). | Leia o `title`, corrija os dados. |
| `429` | Too Many Requests | Limite de requisições excedido. | Espere e repita com backoff. |
| `500` | Internal Server Error | Erro inesperado na DeliveryVip (`"title": "Internal server error"`). | Repita com backoff; se persistir, confira o [status da plataforma](https://status.deliveryvip.com.br) e avise no Discord. |

> [!NOTE]
>
> **Sucesso sem corpo.** `204 No Content` não é erro: o polling sem eventos novos e as listagens sem resultados respondem `204`, sem corpo. Não tente fazer parse do JSON nesses casos.

## Tratando erros no código

```js Node.js theme={null}
async function call(url, options = {}) {
  const response = await fetch(url, {
    ...options,
    headers: { Authorization: `Bearer ${token}`, ...options.headers },
  })
  if (response.status === 204) return null
  if (response.ok) return response.json()

  const body = await response.text()
  const error = body ? JSON.parse(body) : {}
  throw new Error(`HTTP ${response.status}: ${error.title ?? error.error ?? 'sem corpo'}`)
}
```

```python Python theme={null}
def call(method, url, **kwargs):
    response = requests.request(
        method, url, headers={"Authorization": f"Bearer {token}"}, **kwargs
    )
    if response.status_code == 204:
        return None
    if response.ok:
        return response.json()

    error = response.json() if response.content else {}
    raise RuntimeError(
        f"HTTP {response.status_code}: {error.get('title') or error.get('error') or 'sem corpo'}"
    )
```

> [!TIP]
>
> **Repita só o que pode dar certo na segunda vez.** `401` (com token novo), `429` e `5xx` merecem nova tentativa com backoff. `400`, `403`, `404`, `406` e `422` precisam de correção antes.


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