Códigos de erro da API pública
Gerado automaticamente a partir do catálogo de erros do servidor — sempre em sincronia com o que as rotas realmente emitem. Versões para máquina: errors.json e errors.md. Referência dos endpoints em /api-docs.
Envelope
Todo erro é um JSON com error (código estável), opcionalmente reason (subcódigo), message legível e campos auxiliares como retry_after, max_offset e details. Use error/reason na lógica de retry: message pode mudar sem aviso.
Limites de contenção
Deslocamento máximo de paginação: 1000 registros. Mais de 12 rejeições em 10 minutos acionam cooldown de 60s, dobrando até 900s.
| Endpoint | Req/min | Linhas/hora |
|---|---|---|
| /api/public/lots | 60 | 3000 |
| /api/public/bids | 120 | 10000 |
| /api/public/index | 60 | 3000 |
| /api/public/auctions/{auction_id}/metrics | 60 | 3000 |
| /api/public/bids/leader | 120 | 6000 |
| /api/public/lots/{lot_id}/timer-resets | 60 | 20000 |
| /api/public/lots/{lot_id}/stream | 20 | 600 |
| /api/public/auctions/{auction_id}/stream | 20 | 600 |
invalid_query
Parâmetros de consulta inválidos
Quando acontece: Algum filtro, cursor ou parâmetro de paginação não passou na validação Zod da rota.
O que fazer: Corrija os campos listados em `details.fieldErrors` e repita. Não faça retry automático: o erro é determinístico.
Endpoints: /api/public/lots, /api/public/bids, /api/public/index
HTTP/1.1 400 Bad Request
content-type: application/json; charset=utf-8
access-control-allow-origin: *
access-control-expose-headers: retry-after, x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset, x-ratelimit-scope, x-api-version, x-api-supported-versions, x-correlation-id
x-api-version: 1
x-api-supported-versions: 1
x-ratelimit-limit: 60
x-ratelimit-remaining: 0
x-ratelimit-reset: 1785312060
x-ratelimit-scope: distributed
{
"error": "invalid_query",
"details": {
"formErrors": [],
"fieldErrors": {
"lot_id": [
"Invalid uuid"
]
}
},
"version": "1",
"code": "invalid_query",
"message": "Parâmetros de consulta inválidos"
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| access-control-expose-headers | Libera a leitura dos headers de cota por clientes cross-origin. |
| x-api-version | Versão do contrato usada para montar a resposta. |
| x-api-supported-versions | Versões que o servidor ainda aceita. |
| x-ratelimit-limit | Teto da janela avaliada (requisições/minuto ou linhas/hora). |
| x-ratelimit-remaining | Saldo restante; sempre 0 em respostas rejeitadas. |
| x-ratelimit-reset | Epoch em segundos do reinício da janela. |
| x-ratelimit-scope | Camada que rejeitou: `distributed`/`local` (cota por minuto), `rows` (orçamento de linhas) ou `abuse` (cooldown). |
- `details` traz apenas nomes de campos e mensagens do Zod — nunca dados de usuários.
invalid_lot_id
Identificador de lote malformado
Quando acontece: O segmento `{lot_id}` da URL não é um UUID válido.
O que fazer: Use o `id` devolvido por `/api/public/lots`.
Endpoints: /api/public/lots/{lot_id}, /api/public/lots/{lot_id}/stream
HTTP/1.1 400 Bad Request
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: no-store
x-api-version: 1
x-api-supported-versions: 1
{
"error": "invalid_lot_id",
"version": "1",
"code": "invalid_lot_id",
"message": "Identificador de lote malformado",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
| x-api-version | Versão do contrato usada para montar a resposta. |
| x-api-supported-versions | Versões que o servidor ainda aceita. |
invalid_auction_id
Identificador de leilão malformado
Quando acontece: O segmento `{auction_id}` da URL não é um UUID válido.
O que fazer: Use o `auction_id` devolvido por `/api/public/index` ou `/api/public/lots`.
Endpoints: /api/public/auctions/{auction_id}/metrics, /api/public/auctions/{auction_id}/stream
HTTP/1.1 400 Bad Request
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: no-store
x-api-version: 1
x-api-supported-versions: 1
{
"error": "invalid_auction_id",
"version": "1",
"code": "invalid_auction_id",
"message": "Identificador de leilão malformado",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
| x-api-version | Versão do contrato usada para montar a resposta. |
| x-api-supported-versions | Versões que o servidor ainda aceita. |
invalid_since
Parâmetro `since` inválido
Quando acontece: O `?since=` do feed ou de `/api/public/lots` não é uma data ISO-8601 válida.
O que fazer: Envie um timestamp ISO-8601 (ex.: `2026-08-01T00:00:00Z`).
Endpoints: /api/public/lots, /api/public/bids, /api/public/feed.json, /api/public/feed.xml, /api/public/atom.xml
HTTP/1.1 400 Bad Request
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: no-store
{
"error": "invalid_since",
"message": "Parâmetro `since` deve ser uma data ISO-8601.",
"code": "invalid_since",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
invalid_validate_amount
Parâmetro `validate_amount` inválido
Quando acontece: `?validate_amount=` não é um número não negativo ou foi enviado sem `?lot_id=`.
O que fazer: Envie um número >= 0 junto de `lot_id` para validar contra o incremento mínimo do evento.
Endpoints: /api/public/bids
HTTP/1.1 400 Bad Request
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: no-store
{
"error": "invalid_validate_amount",
"message": "Parâmetro `validate_amount` deve ser um número não negativo.",
"code": "invalid_validate_amount",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
invalid_pagination
Paginação do feed fora dos limites
Quando acontece: `?page=`, `?per_page=` ou o alias `?limit=` do feed estão fora do intervalo aceito.
O que fazer: Respeite `max_per_page` devolvido no corpo e recomece pela primeira página.
Endpoints: /api/public/feed.json, /api/public/feed.xml, /api/public/atom.xml
HTTP/1.1 400 Bad Request
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: no-store
{
"error": "invalid_pagination",
"message": "per_page deve estar entre 1 e 100.",
"max_per_page": 100,
"code": "invalid_pagination",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
invalid_include_deleted
Parâmetro `include_deleted` inválido
Quando acontece: `?include_deleted=` (ou `?include_only_deleted=`) veio com um valor fora do domínio booleano aceito.
O que fazer: Envie `1/0`, `true/false` ou `yes/no`. O erro é determinístico: não repita com o mesmo valor.
Endpoints: /api/public/bids, /api/public/bids/stream
HTTP/1.1 400 Bad Request
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: no-store
{
"error": "invalid_include_deleted",
"message": "Parâmetro `include_deleted` aceita 1/0, true/false ou yes/no.",
"code": "invalid_include_deleted",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
- Em `/api/public/bids` a rejeição conta como violação na janela anti-abuso; no stream ela acontece antes do upgrade para `text/event-stream`.
invalid_deleted_limit
Parâmetro `deleted_limit` inválido
Quando acontece: `?deleted_limit=` não é um inteiro >= 1 (valor `0`, negativo, decimal ou não numérico).
O que fazer: Envie um inteiro entre 1 e o `per_page` máximo do endpoint. Valores acima do teto são reduzidos, não rejeitados.
Endpoints: /api/public/bids
HTTP/1.1 400 Bad Request
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: no-store
{
"error": "invalid_deleted_limit",
"message": "Parâmetro `deleted_limit` deve ser um inteiro >= 1 (máximo 200).",
"code": "invalid_deleted_limit",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
- Só faz sentido junto de `include_deleted=1`; limita o tamanho do bloco `deleted[]`.
invalid_include_only_deleted
Parâmetro `include_only_deleted` inválido
Quando acontece: Valor fora do domínio booleano, uso sem `since` (modo incremental) ou combinado com `include_deleted=0`.
O que fazer: Envie `include_only_deleted=1` junto de `since` e sem desligar `include_deleted`. O corpo diz qual das três condições falhou.
Endpoints: /api/public/bids
HTTP/1.1 400 Bad Request
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: no-store
{
"error": "invalid_include_only_deleted",
"message": "Parâmetro `include_only_deleted` exige `since` (modo incremental).",
"code": "invalid_include_only_deleted",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
invalid_json
Corpo da requisição não é JSON válido
Quando acontece: O `POST` chegou com um corpo que não pôde ser desserializado como JSON.
O que fazer: Envie JSON válido com `content-type: application/json`.
Endpoints: /api/public/countdown-desync
HTTP/1.1 400 Bad Request
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: no-store
{
"error": "invalid_json",
"code": "invalid_json",
"message": "Corpo da requisição não é JSON válido",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
invalid_report
Relatório de desync malformado
Quando acontece: O corpo é JSON válido, mas não passou no schema do relatório de desync do countdown.
O que fazer: Corrija os campos listados em `issues` (caminhos do schema) e reenvie.
Endpoints: /api/public/countdown-desync
HTTP/1.1 400 Bad Request
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: no-store
{
"error": "invalid_report",
"issues": [
"lot_id",
"client_ends_at"
],
"code": "invalid_report",
"message": "Relatório de desync malformado",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
invalid_range
Janela temporal impossível
Quando acontece: `?since=` é igual ou posterior a `?until=`: a janela nunca devolveria lance algum.
O que fazer: Corrija a janela para `since < until`. Uma lista vazia com esses parâmetros não significa fim do histórico.
Endpoints: /api/public/bids
HTTP/1.1 400 Bad Request
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: no-store
{
"error": "invalid_range",
"message": "Parâmetro `since` deve ser anterior a `until`.",
"code": "invalid_range",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
invalid_cursor
Cursor do feed inválido
Quando acontece: O `?cursor=` do feed não é um token devolvido pelo servidor (base64url com `updated`+`id`).
O que fazer: Reenvie exatamente o valor do header `X-Feed-Cursor` (ou `_arsenale.next_cursor` no JSON Feed). Omita `cursor` para recomeçar do início do delta.
Endpoints: /api/public/feed.json, /api/public/feed.xml, /api/public/atom.xml
HTTP/1.1 400 Bad Request
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: no-store
{
"error": "invalid_cursor",
"message": "Parâmetro cursor inválido. Reenvie exatamente o valor recebido no header X-Feed-Cursor (ou omita para começar do início).",
"code": "invalid_cursor",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
page_out_of_range
Paginação profunda bloqueada
Quando acontece: O deslocamento `(page - 1) * per_page` passou de 1000 registros — padrão típico de enumeração/varredura do catálogo.
O que fazer: Não pagine indefinidamente: use filtros (`auction_id`, `status`, `q`, `since`/`until`) ou o campo `next_cursor` para estreitar o resultado. Insistir soma violações e leva ao cooldown 429 `abuse_cooldown`.
Endpoints: /api/public/lots, /api/public/bids, /api/public/index
HTTP/1.1 400 Bad Request
content-type: application/json; charset=utf-8
access-control-allow-origin: *
access-control-expose-headers: retry-after, x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset, x-ratelimit-scope, x-api-version, x-api-supported-versions, x-correlation-id
cache-control: no-store
x-ratelimit-limit: 60
x-ratelimit-remaining: 0
x-ratelimit-reset: 1785312060
x-ratelimit-scope: distributed
{
"error": "page_out_of_range",
"message": "Paginação limitada a um deslocamento de 1000 registros. Use filtros (auction_id, status, q, since/until) para refinar a consulta.",
"max_offset": 1000,
"code": "page_out_of_range",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| access-control-expose-headers | Libera a leitura dos headers de cota por clientes cross-origin. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
| x-ratelimit-limit | Teto da janela avaliada (requisições/minuto ou linhas/hora). |
| x-ratelimit-remaining | Saldo restante; sempre 0 em respostas rejeitadas. |
| x-ratelimit-reset | Epoch em segundos do reinício da janela. |
| x-ratelimit-scope | Camada que rejeitou: `distributed`/`local` (cota por minuto), `rows` (orçamento de linhas) ou `abuse` (cooldown). |
- É 400 (e não 429) porque a requisição é inválida por si só — repetir com a mesma página nunca vai funcionar.
- Cada ocorrência conta como violação na janela anti-abuso.
unsupported_version
Versão de contrato não suportada
Quando acontece: O header `x-api-version` (ou `?api_version=`) pediu uma versão que o servidor não serve mais.
O que fazer: Envie uma das versões listadas em `x-api-supported-versions` ou omita o parâmetro para receber a versão corrente.
Endpoints: *
HTTP/1.1 400 Bad Request
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: no-store
x-api-version: 1
x-api-supported-versions: 1
{
"error": "unsupported_version",
"message": "Versão 0 não suportada. Versões disponíveis: 1.",
"supported_versions": [
"1"
],
"code": "unsupported_version",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
| x-api-version | Versão do contrato usada para montar a resposta. |
| x-api-supported-versions | Versões que o servidor ainda aceita. |
lot_not_found
Lote inexistente ou não publicado
Quando acontece: O UUID é válido, mas o lote não existe na view pública (leilão em rascunho ou lote removido).
O que fazer: Trate como 404 definitivo; não faça retry.
Endpoints: /api/public/lots/{lot_id}, /api/public/lots/{lot_id}/stream
HTTP/1.1 404 Not Found
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: no-store
x-api-version: 1
x-api-supported-versions: 1
{
"error": "lot_not_found",
"version": "1",
"code": "lot_not_found",
"message": "Lote inexistente ou não publicado",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
| x-api-version | Versão do contrato usada para montar a resposta. |
| x-api-supported-versions | Versões que o servidor ainda aceita. |
- Lotes de leilões não publicados retornam 404, nunca 403, para não revelar existência.
auction_not_found
Leilão inexistente ou não publicado
Quando acontece: O UUID é válido, mas o leilão não está visível publicamente.
O que fazer: Trate como 404 definitivo; não faça retry.
Endpoints: /api/public/auctions/{auction_id}/metrics, /api/public/auctions/{auction_id}/stream
HTTP/1.1 404 Not Found
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: no-store
x-api-version: 1
x-api-supported-versions: 1
{
"error": "auction_not_found",
"version": "1",
"code": "auction_not_found",
"message": "Leilão inexistente ou não publicado",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
| x-api-version | Versão do contrato usada para montar a resposta. |
| x-api-supported-versions | Versões que o servidor ainda aceita. |
lot_not_in_auction
Lote não pertence ao leilão pedido
Quando acontece: O stream recebeu `?auction_id=` e `?lot_id=` juntos, mas o lote não está entre os lotes públicos daquele leilão.
O que fazer: Confira o par leilão/lote em `/api/public/lots?auction_id=...` ou envie apenas um dos dois filtros. Não faça retry.
Endpoints: /api/public/bids/stream
HTTP/1.1 404 Not Found
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: no-store
{
"error": "lot_not_in_auction",
"code": "lot_not_in_auction",
"message": "Lote não pertence ao leilão pedido",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
- A checagem acontece antes de abrir o `text/event-stream`: o cliente recebe JSON, não eventos SSE.
query_failed
Consulta às views públicas falhou
Quando acontece: O banco recusou ou abortou a consulta que monta a exportação (timeout, indisponibilidade momentânea ou filtro impossível de planejar).
O que fazer: Repita com backoff exponencial e, se persistir, estreite a janela (`since`/`until`) ou reduza o intervalo de valores exportado.
Endpoints: /api/public/bids/csv, /api/public/archive-realized/lots
HTTP/1.1 502 Bad Gateway
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: no-store
{
"error": "query_failed",
"message": "canceling statement due to statement timeout",
"code": "query_failed",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
- É 502 (e não 500) porque a falha vem da dependência de dados, não do handler.
- `message` repassa o erro do banco para diagnóstico; nunca contém dados de usuários.
rate_limited
Cota de requisições por minuto atingida
Quando acontece: O IP passou do teto de requisições/minuto do endpoint. Páginas grandes (`per_page > 50`) e clientes automatizados (User-Agent ausente ou de scraper) consomem 2 a 3 unidades por chamada.
O que fazer: Espere `retry_after` segundos (ou até `x-ratelimit-reset`) e repita com backoff. Não faça retry imediato: cada rejeição soma violação.
Endpoints: *
HTTP/1.1 429 Too Many Requests
content-type: application/json; charset=utf-8
access-control-allow-origin: *
access-control-expose-headers: retry-after, x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset, x-ratelimit-scope, x-api-version, x-api-supported-versions, x-correlation-id
cache-control: no-store
retry-after: 24
x-api-version: 1
x-api-supported-versions: 1
x-ratelimit-limit: 60
x-ratelimit-remaining: 0
x-ratelimit-reset: 1785312060
x-ratelimit-scope: distributed
{
"error": "rate_limited",
"message": "Limite de 60 requisições por minuto atingido. Tente novamente em 24s.",
"retry_after": 24,
"code": "rate_limited",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| access-control-expose-headers | Libera a leitura dos headers de cota por clientes cross-origin. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
| retry-after | Segundos a esperar antes de repetir a chamada. Igual a `retry_after` no corpo. |
| x-api-version | Versão do contrato usada para montar a resposta. |
| x-api-supported-versions | Versões que o servidor ainda aceita. |
| x-ratelimit-limit | Teto da janela avaliada (requisições/minuto ou linhas/hora). |
| x-ratelimit-remaining | Saldo restante; sempre 0 em respostas rejeitadas. |
| x-ratelimit-reset | Epoch em segundos do reinício da janela. |
| x-ratelimit-scope | Camada que rejeitou: `distributed`/`local` (cota por minuto), `rows` (orçamento de linhas) ou `abuse` (cooldown). |
- `x-ratelimit-scope` vem como `distributed` (contador no banco) ou `local` (fallback em memória do worker).
rate_limited:row_budget_exhausted
Orçamento de linhas por hora esgotado
Quando acontece: A soma de `per_page` das chamadas do IP na última hora ultrapassou o orçamento de linhas do endpoint, mesmo respeitando a cota por minuto.
O que fazer: Reduza `per_page`, use `since`/`next_cursor` para buscar só o que mudou, ou consuma o SSE em vez de fazer polling do catálogo inteiro. Volte após `retry_after` segundos.
Endpoints: /api/public/lots, /api/public/bids, /api/public/index
HTTP/1.1 429 Too Many Requests
content-type: application/json; charset=utf-8
access-control-allow-origin: *
access-control-expose-headers: retry-after, x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset, x-ratelimit-scope, x-api-version, x-api-supported-versions, x-correlation-id
cache-control: no-store
retry-after: 1800
x-api-version: 1
x-api-supported-versions: 1
x-ratelimit-limit: 10000
x-ratelimit-remaining: 0
x-ratelimit-reset: 1785312060
x-ratelimit-scope: rows
{
"error": "rate_limited",
"reason": "row_budget_exhausted",
"message": "Orçamento de 10000 registros por hora atingido para este endpoint. Tente novamente em 1800s.",
"retry_after": 1800,
"code": "rate_limited",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| access-control-expose-headers | Libera a leitura dos headers de cota por clientes cross-origin. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
| retry-after | Segundos a esperar antes de repetir a chamada. Igual a `retry_after` no corpo. |
| x-api-version | Versão do contrato usada para montar a resposta. |
| x-api-supported-versions | Versões que o servidor ainda aceita. |
| x-ratelimit-limit | Teto da janela avaliada (requisições/minuto ou linhas/hora). |
| x-ratelimit-remaining | Saldo restante; sempre 0 em respostas rejeitadas. |
| x-ratelimit-reset | Epoch em segundos do reinício da janela. |
| x-ratelimit-scope | Camada que rejeitou: `distributed`/`local` (cota por minuto), `rows` (orçamento de linhas) ou `abuse` (cooldown). |
- A janela é de 1 hora deslizante, então `retry_after` pode chegar a milhares de segundos.
- O orçamento é contado em linhas pedidas (`per_page`), não em linhas devolvidas.
- O teto varia por endpoint: 10.000 linhas/hora em `/api/public/bids` (exemplo acima) e 3.000 em `/api/public/lots` e `/api/public/index`.
rate_limited:abuse_cooldown
Caixa de castigo (cooldown progressivo)
Quando acontece: O IP acumulou mais de 12 rejeições (cota, orçamento de linhas ou paginação profunda) em 10 minutos. Todas as chamadas seguintes são recusadas até o cooldown expirar.
O que fazer: Pare completamente as chamadas por `retry_after` segundos. Continuar tentando dobra o cooldown a cada nova violação.
Endpoints: *
HTTP/1.1 429 Too Many Requests
content-type: application/json; charset=utf-8
access-control-allow-origin: *
access-control-expose-headers: retry-after, x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset, x-ratelimit-scope, x-api-version, x-api-supported-versions, x-correlation-id
cache-control: no-store
retry-after: 120
x-api-version: 1
x-api-supported-versions: 1
x-ratelimit-limit: 60
x-ratelimit-remaining: 0
x-ratelimit-reset: 1785312060
x-ratelimit-scope: abuse
{
"error": "rate_limited",
"reason": "abuse_cooldown",
"message": "Muitas requisições rejeitadas em lots. Aguarde 120s antes de tentar novamente.",
"retry_after": 120,
"code": "rate_limited",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| access-control-expose-headers | Libera a leitura dos headers de cota por clientes cross-origin. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
| retry-after | Segundos a esperar antes de repetir a chamada. Igual a `retry_after` no corpo. |
| x-api-version | Versão do contrato usada para montar a resposta. |
| x-api-supported-versions | Versões que o servidor ainda aceita. |
| x-ratelimit-limit | Teto da janela avaliada (requisições/minuto ou linhas/hora). |
| x-ratelimit-remaining | Saldo restante; sempre 0 em respostas rejeitadas. |
| x-ratelimit-reset | Epoch em segundos do reinício da janela. |
| x-ratelimit-scope | Camada que rejeitou: `distributed`/`local` (cota por minuto), `rows` (orçamento de linhas) ou `abuse` (cooldown). |
- Duração: 60s na primeira vez, dobrando a cada violação, com teto de 900s.
- Vale para o IP inteiro, incluindo os streams SSE — a rejeição acontece antes do upgrade para `text/event-stream`.
internal_error
Falha ao consultar as views públicas
Quando acontece: Erro inesperado no banco ou no loader por trás do endpoint.
O que fazer: Repita com backoff exponencial; o erro costuma ser transitório.
Endpoints: *
HTTP/1.1 500 Internal Server Error
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: no-store
x-api-version: 1
x-api-supported-versions: 1
x-ratelimit-limit: 60
x-ratelimit-remaining: 0
x-ratelimit-reset: 1785312060
x-ratelimit-scope: distributed
{
"error": "internal_error",
"message": "Falha ao consultar lots_public.",
"code": "internal_error",
"details": null
}| Header | Descrição |
|---|---|
| access-control-allow-origin | A API pública é aberta a qualquer origem, inclusive nas respostas de erro. |
| cache-control | Respostas de erro nunca são cacheadas por navegadores ou CDNs. |
| x-api-version | Versão do contrato usada para montar a resposta. |
| x-api-supported-versions | Versões que o servidor ainda aceita. |
| x-ratelimit-limit | Teto da janela avaliada (requisições/minuto ou linhas/hora). |
| x-ratelimit-remaining | Saldo restante; sempre 0 em respostas rejeitadas. |
| x-ratelimit-reset | Epoch em segundos do reinício da janela. |
| x-ratelimit-scope | Camada que rejeitou: `distributed`/`local` (cota por minuto), `rows` (orçamento de linhas) ou `abuse` (cooldown). |
- A mensagem é genérica de propósito: nenhum detalhe interno de SQL ou de usuário é exposto.
- Correlacione pelo header `x-correlation-id` ao abrir um chamado.