Começando
Visão geral
Toda a API pública vive sob um único formato de endereço. O slug identifica o projeto e o namespace agrupa registros — ele é criado automaticamente no primeiro POST.
/api/v1/{slug}/{namespace}| Elemento | Regras |
|---|---|
slug | Minúsculas, números e hífen. Definido na criação do projeto e imutável. |
namespace | De 1 a 64 caracteres: letras, números, hífen e underscore. Normalizado para minúsculas. Nomes reservados (admin, system, __proto__) são recusados com 400 INVALID_NAMESPACE. |
Content-Type | application/json em POST, PUT e PATCH. |
X-Request-Id | Devolvido em toda resposta. Envie o seu para correlacionar logs. |
null. Não há schema para declarar.Autenticação
Cada projeto usa Basic, OAuth 2.0 ou ambos. O projeto autenticado precisa ser exatamente o projeto do slug na URL — caso contrário a resposta é 403 CLIENT_MISMATCH.
# O par usuario:senha e enviado em Base64.
curl 'https://api.jsondock.catini.org/api/v1/meu-projeto/produtos' \
-H "Authorization: Basic $(printf '%s' 'usuario:senha' | base64)"| Escopo OAuth | Libera |
|---|---|
records:read | GET (lista e item individual) |
records:write | POST, PUT, PATCH |
records:delete | DELETE (exclusão lógica) |
Credenciais Basic recebem os três escopos implicitamente — a granularidade por escopo é um recurso do OAuth 2.0.
Envelope de resposta
Seu JSON fica sempre dentro de data. Os campos ao redor são gerenciados pela plataforma — se você enviar chaves com esses nomes, elas permanecem dentro de data e nunca sobrescrevem o controle interno.
{
"id": "665f1f77bcf86cd799439011",
"client": "meu-projeto",
"namespace": "produtos",
"data": { "nome": "Notebook", "preco": 4500 },
"version": 1,
"createdAt": "2026-07-20T10:00:00.000Z",
"updatedAt": "2026-07-20T10:00:00.000Z"
}Endpoints
Resumo
/api/v1/{slug}/{namespace}201 · cria/api/v1/{slug}/{namespace}200 · lista/api/v1/{slug}/{namespace}/{id}200 · consulta/api/v1/{slug}/{namespace}/{id}200 · substitui/api/v1/{slug}/{namespace}/{id}200 · mescla/api/v1/{slug}/{namespace}/{id}204 · exclusão lógicaPUT e PATCH incrementam version. A exclusão permanente não existe na API pública: fica restrita ao painel administrativo, com auditoria.Criar registro
/api/v1/{slug}/{namespace}curl -X POST 'https://api.jsondock.catini.org/api/v1/meu-projeto/produtos' \
-H "Authorization: Basic $(printf '%s' 'usuario:senha' | base64)" \
-H 'Content-Type: application/json' \
-d '{"nome":"Teclado mecanico","preco":349.9,"estoque":12,"ativo":true}'Listar registros
/api/v1/{slug}/{namespace}O GET de lista aceita paginação, ordenação, janelas de data e a DSL de filtros. Todos os parâmetros são opcionais e podem ser combinados livremente.
curl -G 'https://api.jsondock.catini.org/api/v1/meu-projeto/produtos' \
-H "Authorization: Basic $(printf '%s' 'usuario:senha' | base64)" \
--data-urlencode 'page=1' \
--data-urlencode 'limit=20' \
--data-urlencode 'sort=createdAt' \
--data-urlencode 'direction=desc' \
--data-urlencode 'filter[ativo][eq]=true' \
--data-urlencode 'filter[preco][lte]=500'Obter por ID
/api/v1/{slug}/{namespace}/{id}curl 'https://api.jsondock.catini.org/api/v1/meu-projeto/produtos/665f1f77bcf86cd799439011' \
-H "Authorization: Basic $(printf '%s' 'usuario:senha' | base64)"ID fora do formato ObjectId responde 400 INVALID_OBJECT_ID; ID válido inexistente responde 404 RECORD_NOT_FOUND.
Substituir (PUT)
/api/v1/{slug}/{namespace}/{id}Troca data integralmente. O que não estiver no corpo desaparece.
curl -X PUT 'https://api.jsondock.catini.org/api/v1/meu-projeto/produtos/665f1f77bcf86cd799439011' \
-H "Authorization: Basic $(printf '%s' 'usuario:senha' | base64)" \
-H 'Content-Type: application/json' \
-d '{"nome":"Teclado mecanico RGB","preco":399.9}'Atualizar (PATCH)
/api/v1/{slug}/{namespace}/{id}curl -X PATCH 'https://api.jsondock.catini.org/api/v1/meu-projeto/produtos/665f1f77bcf86cd799439011' \
-H "Authorization: Basic $(printf '%s' 'usuario:senha' | base64)" \
-H 'Content-Type: application/json' \
-d '{"preco":329.9,"desconto":null}'Excluir
/api/v1/{slug}/{namespace}/{id}curl -X DELETE 'https://api.jsondock.catini.org/api/v1/meu-projeto/produtos/665f1f77bcf86cd799439011' \
-H "Authorization: Basic $(printf '%s' 'usuario:senha' | base64)"Responde 204 sem corpo. A exclusão é lógica: o registro some das consultas públicas, mas permanece recuperável pelo painel.
Consultas no GET
Paginação
| Parâmetro | Padrão | Regras |
|---|---|---|
page | 1 | Inteiro ≥ 1. |
limit | 20 | Inteiro de 1 a 100. Não existe consulta sem limite. |
?page=1&limit=20
?page=3&limit=100 # maximo permitido
?limit=101 # 400 VALIDATION_ERROROrdenação
| Parâmetro | Padrão | Valores aceitos |
|---|---|---|
sort | createdAt | createdAt, updatedAt, version |
direction | desc | asc, desc |
data não são ordenáveis pela API — filtre pela API e ordene o resultado na sua aplicação.?sort=createdAt&direction=desc # mais recentes primeiro (padrao)
?sort=updatedAt&direction=desc # ultimos alterados
?sort=version&direction=desc # mais editados
?sort=preco # 400 VALIDATION_ERRORFiltros por data
Quatro parâmetros filtram pelas datas gerenciadas pela plataforma. Todos esperam ISO 8601 e são inclusivos nas extremidades.
| Parâmetro | Efeito |
|---|---|
createdAfter | Criados a partir da data informada. |
createdBefore | Criados até a data informada. |
updatedAfter | Alterados a partir da data informada. |
updatedBefore | Alterados até a data informada. |
# Janela por data de criacao e de atualizacao (ISO 8601).
curl -G 'https://api.jsondock.catini.org/api/v1/meu-projeto/pedidos' \
-H "Authorization: Basic $(printf '%s' 'usuario:senha' | base64)" \
--data-urlencode 'createdAfter=2026-01-01T00:00:00.000Z' \
--data-urlencode 'createdBefore=2026-02-01T00:00:00.000Z'Filtros em data
Para consultar qualquer propriedade do seu JSON, a API usa uma DSL própria no formato:
filter[caminho][operador]=valorO caminho é a propriedade dentro de data (sem escrever data.), o operador é um dos nove suportados e o valor é sempre texto na URL — a conversão de tipo é automática.
data. Operadores arbitrários, JavaScript executável e sintaxe de regex do consumidor nunca chegam ao banco.Operadores
São nove operadores. Qualquer outro nome responde 400 INVALID_FILTER listando os válidos.
eqIgual afilter[status][eq]=aprovadoIgualdade exata. Aceita texto, numero, booleano e null.
neDiferente defilter[status][ne]=canceladoRegistros cujo valor e diferente. Documentos sem a propriedade tambem entram.
gtMaior quefilter[preco][gt]=1000Comparacao numerica ou lexicografica (texto e datas ISO 8601).
gteMaior ou igualfilter[preco][gte]=1000Idem gt, incluindo o limite.
ltMenor quefilter[estoque][lt]=5Idem gt, na direcao oposta.
lteMenor ou igualfilter[estoque][lte]=5Idem lt, incluindo o limite.
inPertence a listafilter[categoria][in]=perifericos,monitoresLista separada por virgula. Espacos ao redor sao removidos. Maximo de 25 valores.
existsPropriedade existefilter[desconto][exists]=truetrue retorna quem tem a propriedade; false retorna quem nao tem. Qualquer valor diferente de "false" e tratado como true.
containsContem o textofilter[nome][contains]=tecladoSubstring, sem diferenciar maiusculas. O valor e 100% escapado — nenhuma sintaxe de regex do consumidor e executada.
# Produtos ativos, acima de R$ 1.000, da categoria perifericos,
# com "mecanico" no nome e que possuam a propriedade garantia.
curl -G 'https://api.jsondock.catini.org/api/v1/meu-projeto/produtos' \
-H "Authorization: Basic $(printf '%s' 'usuario:senha' | base64)" \
--data-urlencode 'filter[ativo][eq]=true' \
--data-urlencode 'filter[preco][gte]=1000' \
--data-urlencode 'filter[categoria][in]=perifericos,monitores' \
--data-urlencode 'filter[nome][contains]=mecanico' \
--data-urlencode 'filter[garantia][exists]=true'Combinando filtros
# Todos os filtros sao combinados com AND.
?filter[ativo][eq]=true&filter[categoria][eq]=perifericos
# Resultado: ativo = true E categoria = perifericosCaminhos aninhados e arrays
Use ponto para descer na estrutura, até 6 níveis. Em arrays, a condição casa se qualquer item satisfizer o filtro.
{
"nome": "Notebook",
"preco": 4500,
"fornecedor": {
"nome": "XPTO Distribuidora",
"endereco": { "cidade": "Recife", "uf": "PE" }
},
"tags": ["promocao", "black-friday"]
}Conversão de tipos
O valor sempre chega como texto na query string. A API converte antes de consultar, seguindo regras fixas:
| Valor na URL | Vira | Tipo |
|---|---|---|
true | true | booleano |
false | false | booleano |
null | null | nulo |
4500 | 4500 | número |
349.9 | 349.9 | número |
-10 | -10 | número |
2026-07-20 | "2026-07-20" | texto |
01234 | 1234 | número — cuidado com CEP, CPF e códigos com zero à esquerda |
01234 é convertido para o número 1234 e não encontra o texto "01234". Para códigos desse tipo, use contains ou grave o valor já como número.Os operadores gt, gte, lt e lte aceitam apenas números e textos. Um booleano ou null nessas comparações responde 400 INVALID_FILTER.
Limites e recusas
| Regra | Limite |
|---|---|
| Filtros por consulta | 10 |
| Profundidade do caminho | 6 níveis |
| Tamanho do caminho | 128 caracteres |
| Tamanho de cada segmento | 64 caracteres |
| Tamanho do valor | 512 caracteres |
Valores em in | 25 |
Rejeitado com 400 INVALID_FILTER
| Situação | Exemplo |
|---|---|
| Operador desconhecido | filter[nome][like]=teclado |
| JavaScript executável ou operador do Mongo | filter[$where][eq]=... |
| Poluição de protótipo | filter[__proto__][eq]=x |
| Caractere inválido no caminho | filter[nome do produto][eq]=x |
| Filtro sem operador | filter[nome]=teclado |
in vazio ou contains vazio | filter[tag][in]= |
| Mais de 10 filtros, ou caminho/valor acima do limite | — |
data não têm índice — para volumes altos, prefira reduzir o conjunto por createdAfter antes de filtrar.Referência
Limites de payload
| Limite | Valor | Erro |
|---|---|---|
| Profundidade do JSON | 32 níveis | 422 PAYLOAD_TOO_DEEP |
| Propriedades por objeto | 1000 | 422 INVALID_JSON |
Chaves __proto__, constructor, prototype | proibidas | 422 INVALID_JSON |
Chaves iniciadas por $ | proibidas | 422 INVALID_JSON |
Chaves contendo . | proibidas | 422 INVALID_JSON |
| Tamanho do corpo | configurado por projeto | 413 PAYLOAD_TOO_LARGE |
Rate limit
O limite é aplicado por projeto autenticado. Toda resposta traz o estado atual da janela nos cabeçalhos:
| Cabeçalho | Significado |
|---|---|
RateLimit-Limit | Requisições permitidas na janela. |
RateLimit-Remaining | Quantas ainda restam. |
RateLimit-Reset | Segundos até a janela reiniciar. |
Projetos criados pelo cadastro gratuito começam com 180 requisições por minuto. A janela é de um minuto e o limite é contado por projeto, não por IP.
Ao estourar, a API responde 429 RATE_LIMIT_EXCEEDED. Trate o 429 com recuo exponencial respeitando RateLimit-Reset.
Códigos de erro
Todo erro usa o mesmo envelope, sempre com code estável e requestId para suporte.
{
"statusCode": 400,
"error": "Bad Request",
"code": "INVALID_FILTER",
"message": "Operador \"like\" nao suportado. Use: eq, ne, gt, gte, lt, lte, in, exists, contains.",
"requestId": "01J8Z9K2M4N6P8Q0R2S4T6V8",
"timestamp": "2026-07-20T10:00:00.000Z",
"path": "/api/v1/meu-projeto/produtos"
}| Status | Código | Quando acontece |
|---|---|---|
| 400 | INVALID_FILTER | Operador, caminho ou valor de filtro inválido. |
| 400 | VALIDATION_ERROR | Parâmetro de paginação, ordenação ou data fora do aceito. |
| 400 | INVALID_NAMESPACE | Namespace com formato inválido ou reservado. |
| 400 | INVALID_OBJECT_ID | ID que não é um ObjectId válido. |
| 401 | INVALID_CREDENTIALS | Usuário ou senha Basic incorretos. |
| 401 | INVALID_TOKEN | Bearer expirado, malformado ou sem projeto correspondente. |
| 403 | CLIENT_MISMATCH | O projeto do token não é o projeto do slug na URL. |
| 403 | INSUFFICIENT_SCOPE | O token não tem o escopo exigido pela operação. |
| 403 | CLIENT_INACTIVE | Projeto inativo, bloqueado ou excluído. |
| 404 | RECORD_NOT_FOUND | Registro inexistente ou já excluído. |
| 413 | PAYLOAD_TOO_LARGE | Corpo acima do limite do projeto. |
| 422 | PAYLOAD_TOO_DEEP | JSON com mais de 32 níveis. |
| 422 | INVALID_JSON | Chave proibida ou objeto com propriedades demais. |
| 429 | RATE_LIMIT_EXCEEDED | Limite de requisições estourado. |
| 503 | SERVICE_UNAVAILABLE | Dependência indisponível no momento. |
Pronto para testar?
Crie um projeto gratuito, copie as credenciais e faça a primeira chamada em menos de um minuto.