# Documentação para desenvolvedores da Inovacc: texto completo Atualizado em 2026-10-10. --- Produto: Chat com IA URL: https://developer.inovacc.dev/pt-br/products/ai.chat/ URL base: https://ai.inovacc.dev Respostas de chat dos modelos de linguagem da plataforma. Endpoints: - POST /v1/chat/completions - GET /v1/models - POST /v1/run Exemplo: ```sh curl -X POST "https://ai.inovacc.dev/v1/chat/completions" -H "Authorization: Bearer $INOVACC_API_KEY" -H "X-Operation-Id: $(uuidgen)" -H "Content-Type: application/json" -d '{}' ``` ## Visão geral O Chat com IA dá à sua aplicação respostas conversacionais dos modelos de linguagem que a Inovacc opera para a sua organização. O endpoint, `POST /v1/chat/completions`, fala o formato de comunicação chat-completions da OpenAI, então uma biblioteca cliente da OpenAI já existente pode chamá-lo trocando a URL base por `https://ai.inovacc.dev/v1` e adicionando dois cabeçalhos. Você envia uma lista de mensagens e recebe a resposta do assistente, seja como um único documento JSON, seja como uma transmissão de eventos enquanto ela é escrita. O problema que ele resolve é o acesso sem encanamento: sua organização não precisa ter contas, chaves ou contratos com provedores de modelos. A Inovacc decide qual modelo atende cada uma das suas rotas, aplica os limites e orçamentos da sua organização antes de a chamada ser feita e registra o uso de cada chamada para que você veja quanto cada chave e cada rota gastam. Use o Chat com IA quando a resposta for texto livre: um assistente, um resumo, um rascunho, uma extração para JSON, uma resposta que chama as suas ferramentas. Outro produto serve melhor quando: - você precisa de um veredito estruturado a partir de critérios (uma pontuação, uma escolha, um sim ou não, com confiança): use o [Motor de decisão](/pt-br/products/decision/); - a resposta precisa vir dos seus próprios documentos, com citações: consulte uma coleção na nuvem de [Conhecimento e busca vetorial](/pt-br/products/knowledge/); - você precisa de vetores em vez de texto: use [Embeddings de IA](/pt-br/products/ai.embeddings/). ## Conceitos **Rotas, não modelos.** Você nunca nomeia um modelo. Sua organização recebe **rotas**: ids opacos como `r00`, configurados pela Inovacc exclusivamente para a sua organização. Uma rota decide qual modelo responde, seu teto de saída e os campos que ela aceita. `GET /v1/models` lista as rotas que a sua organização pode usar, cada uma com o `endpoint` que atende; o `id` é sempre o id da rota, nunca o nome do que está por trás dela. Envie o id no campo `model`; envie `"auto"`, ou omita `model`, e a rota padrão da sua organização responde. Uma rota atende exatamente um endpoint: uma rota de chat chamada a partir de `/v1/embeddings` ou `/v1/run` é recusada como uma rota que você não tem permissão de usar. **Campos.** Os campos comuns da OpenAI são sempre aceitos: `messages`, `model`, `stream`, `stream_options`, `max_tokens`, `max_completion_tokens`, `temperature`, `top_p`, `stop`, as penalidades, `logit_bias`, `logprobs`, `tools`, `tool_choice`, `response_format`, `seed`, `reasoning_effort` e mais alguns. Sete campos (`n`, `service_tier`, `store`, `metadata`, `modalities`, `audio`, `web_search_options`) são aceitos apenas quando a sua organização recebeu permissão para eles. Qualquer outro campo é recusado pelo nome. Algumas rotas aceitam um conjunto menor (`messages`, `model`, `stream`, `stream_options`, os dois limites de saída, `temperature`, `top_p`); nelas, `tools` e os demais campos são recusados para aquela rota. **Mensagens e imagens.** `content` é uma string, ou um array de partes de texto e partes `image_url`. Uma imagem é uma URL `data:` (PNG, JPEG, WebP ou GIF, em base64) ou uma URL `https://`; uma rota cujo modelo não consegue buscar uma URL recusa a forma `https://`. Uma requisição carrega no máximo 20 imagens, e cada uma conta como 1.600 tokens de entrada estimados. **Teto de saída.** `max_tokens` e `max_completion_tokens` só podem reduzir o teto definido pela rota e pela sua organização; um valor maior é limitado ao teto, nunca recusado. Os tokens de raciocínio que um modelo gasta estão dentro de `completion_tokens`. **Transmissão.** Com `"stream": true`, a resposta é um `text/event-stream` de eventos `chat.completion.chunk` da OpenAI, cada um em uma linha `data:`, terminando com `data: [DONE]`. Defina `stream_options.include_usage` para receber um bloco final com a contagem de tokens. **Cabeçalhos de uso.** Uma resposta sem transmissão traz `x-route-id`, `x-usage-input-tokens` e `x-usage-output-tokens`, e toda resposta traz `x-operation-id`. ## Como funciona Toda chamada leva `Authorization: Bearer ` e um `X-Operation-Id`. Sua organização vem da chave. O id de operação é a sua chave de idempotência: de 8 a 128 letras, dígitos, `_` ou `-`. O serviço verifica, em ordem: o id de operação, a chave, se aquele id de operação já foi usado, o corpo e seus campos, a rota, as mensagens, o tamanho estimado da entrada (um quarto dos caracteres do corpo inteiro da requisição, mais a estimativa das imagens) e então reserva a chamada contra as cotas da sua organização. Só quando tudo isso passa é que um modelo é chamado. O `id` da resposta é sempre `chatcmpl-` seguido do seu id de operação, e seu `model` é sempre o id da rota. Uma resposta cujo orçamento de saída inteiro foi gasto em raciocínio continua sendo `200`, com `content` vazio e `finish_reason: "length"`; uma resposta interrompida pelo filtro de segurança do modelo é `200` com `finish_reason: "content_filter"`. Uma resposta sem transmissão bem-sucedida é armazenada por 24 horas sob o seu id de operação. Envie o mesmo id novamente e você recebe a resposta armazenada, com `x-idempotent-replay: true`, sem uma segunda chamada ao modelo, sem uma segunda cobrança e sem alteração de cota. Um erro nunca é armazenado, então repetir uma chamada que falhou com o mesmo id a executa de novo. Enquanto uma chamada ainda está em execução, uma segunda chamada com o mesmo id retorna `409 operation_in_progress`. Uma transmissão nunca é armazenada. Se o modelo falhar no meio, a transmissão termina com um evento de erro (`upstream_error`) e `data: [DONE]`; uma transmissão que termina sem `[DONE]` foi cortada e está incompleta. Leia `delta.content` em todos os blocos, incluindo o primeiro e o que carrega `finish_reason`. O que é medido são tokens: de entrada e de saída, conforme informado pelo modelo, ou a estimativa quando não há contagem disponível. `GET /v1/usage/summary` soma o uso da sua organização por chave, rota, dia ou hora, e `GET /v1/capabilities` informa a um agente o que a sua organização pode chamar; nenhum dos dois é cobrado. ## Primeiros passos Você precisa de uma chave de API e de pelo menos uma rota de chat habilitada para a sua organização. As chaves são criadas no console da Inovacc; veja [Autenticação](/pt-br/guides/authentication/). 1. **Liste as suas rotas.** Chame `GET /v1/models`. Cada entrada com `"endpoint": "/v1/chat/completions"` é uma rota com a qual você pode conversar; anote o `id` dela. 2. **Envie uma primeira mensagem.** Chame `POST /v1/chat/completions` com esse id como `model`, uma mensagem `user` e um `X-Operation-Id` novo (veja [os exemplos](#example)). O `id` da resposta termina com o seu id de operação e `x-usage-input-tokens` mostra o que foi contado. 3. **Repita.** Envie a mesma requisição com o mesmo id de operação. A resposta é idêntica e traz `x-idempotent-replay: true`: nada foi executado duas vezes. 4. **Use a transmissão.** Adicione `"stream": true` e `"stream_options": {"include_usage": true}` com um novo id de operação. Os blocos chegam conforme a resposta é escrita, com o último antes de `[DONE]` carregando `usage`. 5. **Confira o gasto.** Chame `GET /v1/usage/summary?group_by=route` para ver as chamadas e os tokens que você acabou de usar. ## Casos de uso **Um assistente de suporte.** O widget de ajuda transmite a resposta para que a pessoa a veja aparecer imediatamente. Cada turno do usuário é uma chamada com um novo id de operação; o seu servidor guarda a conversa e envia as mensagens recentes a cada vez. Se a conexão cair antes de `[DONE]`, o widget mostra a resposta como cortada e oferece perguntar de novo. **Extração estruturada em lote.** Uma tarefa noturna lê os documentos recebidos e pede um objeto JSON com `response_format`. Cada documento recebe um id de operação derivado do seu próprio id, de modo que, quando a tarefa é reiniciada após uma falha, os documentos já concluídos voltam das respostas armazenadas em segundos e não são cobrados novamente. **Um agente que chama as suas ferramentas.** Em uma rota que aceita `tools`, o modelo responde com `tool_calls`; o seu código executa a ferramenta e devolve o resultado como uma mensagem `tool`. Cada etapa tem o seu próprio id de operação, então uma etapa repetida nunca executa uma ferramenta duas vezes do lado do modelo. ## Limites e preços | Limite | Valor | |---|---| | Corpo da requisição | 1 MiB por padrão; sua organização pode ser configurada entre 1 KiB e 20 MiB | | Imagens por requisição | 20 | | Custo de entrada estimado de uma imagem | 1.600 tokens | | Tokens de entrada por requisição | o limite da sua organização (`400 input_too_large` acima dele) | | Tokens de saída por requisição | o menor entre o teto da rota e o da sua organização | | Tempo até a primeira resposta do modelo | 60 segundos | | Resposta armazenada para repetição | 24 horas | | Uma chamada mantida como em andamento | 5 minutos no máximo | | Requisições por minuto e por dia; tokens e custo por dia e por mês; chamadas simultâneas; orçamentos diários | conforme definido para a sua organização | **Preços:** sob consulta. A unidade de preço é **tokens**. ## Erros | Status | Código | O que significa e o que fazer | |---|---|---| | 400 | `missing_operation_id`, `invalid_operation_id` | Envie `X-Operation-Id` com 8 a 128 letras, dígitos, `_` ou `-`. | | 400 | `invalid_body` | O corpo não é um objeto JSON, ou `user` não é uma string. Corrija o corpo. | | 400 | `invalid_messages` | `messages` está vazio ou uma mensagem está malformada. | | 400 | `unsupported_field` | Um campo de nível superior que este endpoint não aceita; remova-o. | | 400 | `unsupported_field_for_route` | A rota aceita um conjunto menor de campos, ou não consegue buscar uma URL de imagem; remova o campo ou envie a imagem como `data:`. | | 400 | `model_not_allowed` | O valor de `model` não é um id de rota válido. Use um id de `GET /v1/models`. | | 400 | `input_too_large` | A entrada excede o limite por requisição da sua organização, ou há mais de 20 imagens. Encurte-a. | | 401 | `missing_credentials`, `invalid_credentials` | Envie uma chave válida. | | 403 | `key_disabled`, `organization_disabled` | A chave ou a organização foi desativada; fale com o seu administrador. | | 403 | `field_not_allowed` | Um campo que a sua organização não recebeu permissão para usar. | | 403 | `route_forbidden` | A rota não é uma que a sua organização possa usar neste endpoint. | | 409 | `operation_in_progress` | Esse id de operação ainda está em execução; aguarde e tente novamente. | | 413 | `request_too_large` | O corpo excede o seu limite de tamanho. | | 429 | `rate_limited` | Requisições demais; aguarde `Retry-After` segundos. | | 429 | `quota_exceeded`, `concurrency_limited` | Uma cota de tokens, de custo ou de simultaneidade se esgotou; sem `Retry-After`. | | 429 | `budget_exhausted` | Um orçamento diário foi consumido; ele é reiniciado às 00:00 UTC (`Retry-After`). | | 502 | `upstream_error` | O modelo não respondeu de forma utilizável; tente novamente com o mesmo id de operação. | | 503 | `service_unavailable`, `route_unavailable` | Tente novamente mais tarde; `route_unavailable` exige que a Inovacc corrija a sua rota. | | 504 | `timeout_error` | O modelo não começou a responder em 60 segundos; tente novamente. | O envelope e todos os tipos estão em [Erros](/pt-br/guides/errors/). ## Boas práticas - **Um id de operação por requisição lógica**, reutilizado apenas para repetir essa mesma requisição. Um id reutilizado devolve a primeira resposta, qualquer que seja o novo corpo. - **Repita em `502`, `503`, `504` e em erros de rede com o mesmo id de operação**, com espera crescente. Em `429 rate_limited` e `budget_exhausted`, aguarde os segundos de `Retry-After`. - **Defina `max_tokens`** com o que você precisa: isso reduz a reserva feita contra as suas cotas e o custo de uma resposta descontrolada. - **Observe `X-Budget-Warning`**: ele aparece quando a sua organização passa do limiar de alerta de um orçamento, antes de as chamadas serem recusadas. - **Use `stream` para pessoas, não para tarefas**: uma resposta transmitida não pode ser repetida, uma sem transmissão pode. - **Envie imagens como URLs `data:`** quando você não souber se o modelo da rota consegue buscar uma URL, e mantenha-as dentro do limite de 20 imagens. - **Nunca envie uma chave secreta a um navegador**: chame o Chat com IA a partir do seu servidor. ## Relacionados - [Autenticação](/pt-br/guides/authentication/), [Erros](/pt-br/guides/errors/), [Limites](/pt-br/guides/limits/) - [Motor de decisão](/pt-br/products/decision/): vereditos estruturados na mesma chave - [Conhecimento e busca vetorial](/pt-br/products/knowledge/): respostas a partir dos seus documentos, com citações - [Embeddings de IA](/pt-br/products/ai.embeddings/) --- Produto: Embeddings de IA URL: https://developer.inovacc.dev/pt-br/products/ai.embeddings/ URL base: https://ai.inovacc.dev Transforme texto em vetores para busca e similaridade. Endpoints: - POST /v1/embeddings Exemplo: ```sh curl -X POST "https://ai.inovacc.dev/v1/embeddings" -H "Authorization: Bearer $INOVACC_API_KEY" -H "X-Operation-Id: $(uuidgen)" -H "Content-Type: application/json" -d '{}' ``` ## Visão geral Os Embeddings de IA transformam texto em vetores: listas de números cuja distância entre si acompanha o significado do texto. Dois trechos sobre o mesmo assunto ficam próximos mesmo quando não compartilham nenhuma palavra. O endpoint, `POST /v1/embeddings`, fala o formato de comunicação de embeddings da OpenAI, então um cliente da OpenAI já existente pode chamá-lo com a URL base `https://ai.inovacc.dev/v1` e dois cabeçalhos extras. O problema que ele resolve é a comparação semântica dentro dos seus próprios sistemas. Com vetores você pode buscar por significado, agrupar itens semelhantes, encontrar quase duplicatas ou direcionar uma mensagem para a categoria mais próxima, usando o banco de dados ou o índice que você já opera. Use os Embeddings de IA quando **você** guarda os vetores. Quando preferir que a Inovacc os guarde, faça a busca e devolva os trechos correspondentes, use o Banco de Dados Vetorial gerenciado de [Conhecimento e busca vetorial](/pt-br/products/knowledge/), que gera os embeddings dos seus documentos por você. Quando precisar de texto gerado em vez de vetores, use o [Chat com IA](/pt-br/products/ai.chat/). ## Conceitos **Rotas.** Como no chat, você nunca nomeia um modelo. Sua organização recebe rotas de embeddings, ids opacos configurados pela Inovacc. `GET /v1/models` as lista: uma entrada cujo `endpoint` é `/v1/embeddings` é uma rota de embeddings. Envie o id dela como `model`, ou envie `"auto"` (ou nenhum `model`) para usar a rota padrão da sua organização. Uma rota atende um único endpoint; uma rota de chat chamada aqui é recusada. **Entrada.** `input` é uma string não vazia, ou um array de strings; dentro de um array, uma string vazia é aceita. A resposta traz um vetor por entrada, em `data[]`, cada um com o `index` da entrada a que pertence. **Os vetores de uma rota pertencem juntos.** Um vetor só é comparável com vetores produzidos pela mesma rota. Guarde o id da rota junto de cada vetor que você armazena, e gere os embeddings dos seus documentos e das suas consultas com a mesma rota. **Campos opcionais.** `encoding_format` e `dimensions` são repassados ao modelo quando o modelo da rota os suporta e ignorados caso contrário. `user` é aceito como string e substituído, antes de sair da Inovacc, por um valor derivado da sua organização, de modo que duas organizações que enviam o mesmo valor nunca colidem. **Uso.** O `usage` da resposta contém `prompt_tokens` e `total_tokens`. Este endpoint não traz cabeçalhos `x-usage-*`; a rota que respondeu está em `x-route-id`. ## Como funciona Toda chamada leva `Authorization: Bearer ` e um `X-Operation-Id`. Sua organização vem da chave. O serviço verifica o id de operação e a chave, depois se aquele id de operação já foi usado, e então o corpo: apenas `model`, `input`, `encoding_format`, `dimensions` e `user` são aceitos, e qualquer outro campo é recusado pelo nome. Ele resolve a rota, verifica se a rota atende embeddings, valida `input`, estima o tamanho da entrada (um quarto dos caracteres de cada string de entrada) contra o limite por requisição da sua organização e reserva a chamada contra as cotas da sua organização. Só então o modelo é chamado. A resposta é `{"object":"list","data":[{"object":"embedding","index":0,"embedding":[...]}],"model":"","usage":{...}}`. `model` é sempre o id da rota. Não há transmissão. Uma resposta bem-sucedida é armazenada por 24 horas sob o seu id de operação: o mesmo id enviado de novo devolve os mesmos vetores com `x-idempotent-replay: true`, sem uma segunda chamada nem cobrança. Um erro nunca é armazenado, então uma chamada que falhou pode ser repetida com o mesmo id. O que é medido são os tokens de entrada. ## Primeiros passos Você precisa de uma chave de API e de uma rota de embeddings habilitada para a sua organização ([Autenticação](/pt-br/guides/authentication/)). 1. **Encontre a sua rota de embeddings.** Chame `GET /v1/models` e escolha uma entrada cujo `endpoint` seja `/v1/embeddings`. 2. **Gere embeddings de dois trechos.** Chame `POST /v1/embeddings` com essa rota como `model`, um array `input` com duas strings e um `X-Operation-Id` novo (veja [os exemplos](#example)). A resposta tem duas entradas em `data`, com `index` 0 e 1, e `model` é o id da sua rota. 3. **Compare-os.** Calcule a similaridade de cosseno dos dois vetores no seu código. Gere o embedding de um terceiro trecho sobre outro assunto e compare de novo: a pontuação dele contra o primeiro é menor. 4. **Repita.** Envie o passo 2 novamente com o mesmo id de operação; os vetores são idênticos e a resposta traz `x-idempotent-replay: true`. ## Casos de uso **Busca no seu próprio banco de dados.** Um catálogo de produtos guarda um vetor por descrição de produto no banco de dados que já usa. A pergunta de um comprador tem o embedding gerado com a mesma rota no momento da consulta, e os produtos mais próximos são exibidos, inclusive aqueles cuja descrição usa palavras diferentes. **Detecção de quase duplicatas.** Um sistema de chamados gera o embedding de cada novo chamado e o compara com os abertos; uma pontuação acima de um limiar que você calibra vincula o chamado ao caso existente em vez de abrir um segundo. **Direcionamento por similaridade.** Um pequeno conjunto de mensagens de exemplo por equipe tem o embedding gerado uma única vez. Cada mensagem recebida tem o embedding gerado e é enviada à equipe cujos exemplos estão mais próximos, sem nenhuma chamada de modelo por mensagem além do embedding. ## Limites e preços | Limite | Valor | |---|---| | Corpo da requisição | 1 MiB por padrão; sua organização pode ser configurada entre 1 KiB e 20 MiB | | Tokens de entrada por requisição | o limite da sua organização (`400 input_too_large` acima dele) | | Tempo até a primeira resposta do modelo | 60 segundos | | Resposta armazenada para repetição | 24 horas | | Requisições, tokens, custo, simultaneidade, orçamentos diários | conforme definido para a sua organização | **Preços:** sob consulta. A unidade de preço é **tokens**. ## Erros | Status | Código | O que significa e o que fazer | |---|---|---| | 400 | `missing_operation_id`, `invalid_operation_id` | Envie um `X-Operation-Id` válido. | | 400 | `unsupported_field` | Um campo diferente de `model`, `input`, `encoding_format`, `dimensions`, `user`; remova-o. | | 400 | `invalid_body` | JSON malformado, `input` com formato errado, ou um `user` que não é string. | | 400 | `model_not_allowed` | `model` não é um id de rota válido. | | 400 | `input_too_large` | A entrada excede o seu limite por requisição; divida-a em várias chamadas. | | 401 | `missing_credentials`, `invalid_credentials` | Envie uma chave válida. | | 403 | `route_forbidden` | A rota não é sua, está desativada, ou não atende embeddings. | | 403 | `key_disabled`, `organization_disabled` | Verifique a chave. | | 409 | `operation_in_progress` | Esse id de operação ainda está em execução; aguarde e tente novamente. | | 413 | `request_too_large` | O corpo excede o seu limite de tamanho. | | 429 | `rate_limited`, `budget_exhausted` | Aguarde os segundos de `Retry-After`. | | 429 | `quota_exceeded`, `concurrency_limited` | Uma cota se esgotou; sem `Retry-After`. | | 502, 503, 504 | `upstream_error`, `service_unavailable`, `timeout_error` | Tente novamente com o mesmo id de operação e espera crescente. | Veja [Erros](/pt-br/guides/errors/) para o envelope. ## Boas práticas - **Agrupe as entradas**: envie muitos trechos em um único array `input`, dentro dos seus limites de tamanho e de tokens, em vez de uma chamada por trecho. - **Guarde o id da rota junto com o vetor**, e gere novamente todos os embeddings se trocar de rota: vetores de duas rotas não são comparáveis. - **Divida documentos longos** em trechos de alguns parágrafos antes de gerar os embeddings; um único vetor para um documento inteiro dilui o seu significado. - **Derive o id de operação do conteúdo** (por exemplo, um hash do lote) para que uma tarefa reiniciada repita a resposta em vez de pagar de novo. - **Repita `502`, `503` e `504` com o mesmo id de operação**; aguarde `Retry-After` em `429 rate_limited`. - **Calibre os limiares com os seus próprios dados**: as pontuações de similaridade são relativas, não probabilidades. ## Relacionados - [Conhecimento e busca vetorial](/pt-br/products/knowledge/): o Banco de Dados Vetorial gerenciado que gera os embeddings e faz a busca por você - [Chat com IA](/pt-br/products/ai.chat/) - [Autenticação](/pt-br/guides/authentication/), [Erros](/pt-br/guides/errors/), [Limites](/pt-br/guides/limits/) --- Produto: Conhecimento e busca vetorial URL: https://developer.inovacc.dev/pt-br/products/knowledge/ URL base: https://ai.inovacc.dev Ingira documentos, monte coleções de conhecimento e consulte por significado. Endpoints: - POST /v1/vector/ingest - POST /v1/vector/query - POST /v1/collections - POST /v1/collections/{id}/query - POST /v1/knowledge/jobs Exemplo: ```sh curl -X POST "https://ai.inovacc.dev/v1/vector/ingest" -H "Authorization: Bearer $INOVACC_API_KEY" -H "X-Operation-Id: $(uuidgen)" -H "Content-Type: application/json" -d '{}' ``` ## Visão geral Conhecimento e busca vetorial mantém o conhecimento da sua organização num lugar onde uma aplicação pode fazer perguntas a ele por significado. Tem três partes, todas em `https://ai.inovacc.dev`: - o **Banco de Dados Vetorial**: um repositório gerenciado de trechos de texto que você ingere e pesquisa, com filtros, escopos e reclassificação opcional; - as **coleções de conhecimento**: envie um lote de arquivos mistos (documentos, imagens, vídeo) e receba-os processados em pacotes de conhecimento; depois baixe o resultado, consulte-o, converse com ele com citações ou peça um relatório escrito sobre ele; - os **trabalhos de conhecimento**: transformam uma gravação longa em uma base de conhecimento que você baixa como um único arquivo compactado. O problema que ele resolve é tudo o que existe entre "temos arquivos" e "o assistente consegue responder a partir deles": extrair o texto, dividi-lo em trechos, gerar os embeddings, indexar, manter o índice consistente e citar a fonte de cada resposta. A Inovacc executa essas etapas e você chama alguns poucos endpoints. Use-o quando as respostas precisarem vir do seu próprio material. Quando você já opera o seu próprio índice vetorial, os [Embeddings de IA](/pt-br/products/ai.embeddings/) entregam apenas os vetores. Quando a resposta é texto livre sem fontes, use o [Chat com IA](/pt-br/products/ai.chat/). Cada parte é habilitada para a sua organização pela Inovacc; uma parte que não está habilitada responde `403` (`vector_database_disabled`, `collections_disabled` ou `knowledge_disabled`). ## Conceitos **Banco de Dados Vetorial e seu perfil.** Sua organização cria um banco de dados com `POST /v1/vector/databases`, escolhendo um **perfil de embeddings** em `GET /v1/vector/profiles`. Um perfil define a modalidade (`text`), os idiomas (`english` ou `multilingual`), as dimensões e a métrica de distância; os ids têm a forma `text-multilingual-1024`. Você escolhe um perfil, nunca um modelo. O perfil não pode ser alterado: para usar outro, exclua o banco de dados, crie um novo e ingira tudo de novo. **Documentos, escopos e modos.** Você ingere trechos com o seu próprio `id`, o `text` deles e `metadata` plano opcional. Um trecho vai para um **escopo**: `shared` (todos os serviços do espaço de trabalho da sua organização) ou `local` (apenas a chave de API que o escreveu). As consultas usam um **modo**: `shared`, `local` ou `hybrid` para pesquisar ambos e mesclar por pontuação. Seis chaves de metadados podem ser usadas em filtros: `kind`, `source`, `category`, `tag`, `language`, `created_at`. Blocos que compartilham um `document_id` formam um documento com uma `generation` (o seu número de versão), o que permite excluir ou substituir um documento inteiro de uma vez. **Coleções e seu modo.** Uma coleção é criada em um de três modos, fixos durante toda a sua vida: `download` (processa os arquivos, você baixa os pacotes e nada permanece depois), `cloud` (a Inovacc guarda o conteúdo processado e seus vetores para que você possa usar `query`, `chat` e executar uma `analysis`) ou `local_vectors` (a Inovacc guarda apenas vetores, nunca texto: você faz `embed` dos seus próprios blocos e `query` devolve ids de blocos e pontuações). As coleções são mantidas por 30 dias por padrão; uma organização configurada com retenção `zero` tem as coleções excluídas uma hora depois do início do download. **Itens.** Um arquivo entra em uma coleção na própria requisição (até 16 MiB), a partir de um envio concluído (vídeo acima de 16 MiB), por URL pública ou por uma URL assinada selada com uma chave de uso único, de modo que nunca seja armazenada. Cada item passa por `queued`, `processing` e depois `done` ou `failed`; um item que falha não interrompe os outros. **Consistência eventual e `searchable`.** O índice vetorial aplica as escritas de forma assíncrona: um vetor fica legível alguns segundos, às vezes minutos, depois de escrito. `GET /v1/vector/databases` e toda resposta de coleção informam `searchable`; uma consulta enviada enquanto ele é `false` pode não encontrar os trechos mais recentes. O `indexing.complete` de uma coleção `cloud` só é `true` quando todos os blocos estão escritos **e** legíveis. **Trabalhos, potência e orçamento.** Um trabalho de conhecimento recebe um envio concluído de uma gravação, uma transcrição e notas opcionais, uma `power` (`light`, `medium` ou `max`) e um `max_price_usd` obrigatório. Um trabalho acima do limite da sua organização é recusado antes de qualquer trabalho pago. ## Como funciona Toda chamada leva `Authorization: Bearer `. Sua organização vem da chave. `X-Operation-Id` é obrigatório nas chamadas `POST` de coleção, envio e trabalho e as torna idempotentes: uma nova tentativa com o mesmo id devolve a primeira resposta (`X-Idempotent-Replay: true`) e não acrescenta nada; o mesmo id com um arquivo diferente retorna `409 operation_id_reused`. No Banco de Dados Vetorial ele é opcional, porque ingestão e exclusão são idempotentes por construção: ingerir um `id` existente o substitui. Uma **consulta** (`POST /v1/vector/query`) recebe `mode`, `query` (de 1 a 8.000 caracteres), `top_k` (de 1 a 50) e um `filter` opcional; devolve as correspondências da melhor para a pior, cada uma com `id`, `score`, `text` e `metadata`. Com `"retrieval": "vector_rerank"` e um `rerank_profile`, uma lista de candidatos mais ampla é reordenada por uma etapa de reclassificação; o objeto `retrieval` da resposta informa se a reclassificação foi aplicada ou se voltou à ordem vetorial. Uma **coleção** funciona em etapas que você pode observar: crie-a, adicione itens (`202`, `queued`), leia-a até que `status` seja `complete` e então baixe, consulte ou converse. Ler uma coleção `cloud` também avança a sua indexação, em uma quantidade limitada por chamada, e toda resposta traz o progresso de `indexing`. O `chat` responde apenas a partir das fontes recuperadas, numera cada citação com o item, o pacote, o bloco e o localizador, e diz que não consegue responder quando as fontes não cobrem a pergunta. Uma `analysis` é construída ao longo de várias requisições: repita `POST` ou `GET` a cada poucos segundos até que ela responda `200` com o relatório. Um **trabalho** é assíncrono: `POST /v1/knowledge/jobs` responde `202` com `job_id`, `status_url` e `poll_after_seconds` (também como `Retry-After`). Leia o status quando for indicado; o serviço prevê o tempo até a conclusão e inclui `eta_seconds` enquanto consegue. Quando `state` for `done`, baixe o arquivo compactado; ele é mantido por 24 horas. O que é medido: tokens de embeddings e vetores escritos na ingestão e na indexação, consultas, reclassificações como unidade própria, chamadas de chat na sua rota de chat e trabalhos pelo seu preço. `POST /v1/knowledge/estimates` precifica uma gravação antes de você enviá-la, sem custo. ## Primeiros passos Você precisa de uma chave de API e da parte que deseja habilitada para a sua organização ([Autenticação](/pt-br/guides/authentication/)). 1. **Crie o banco de dados.** `GET /v1/vector/profiles`, escolha um perfil e então `POST /v1/vector/databases` com `{"profile":""}`. A resposta é `201` com o banco de dados. 2. **Ingira trechos.** `POST /v1/vector/ingest` com `"scope":"shared"` e dois ou três documentos (veja [os exemplos](#example)). A resposta informa quantos foram `ingested` e lista os `skipped`, se houver, com o motivo. 3. **Espere por `searchable`.** `GET /v1/vector/databases` até que `searchable` seja `true`. 4. **Consulte.** `POST /v1/vector/query` com `"mode":"shared"` e uma pergunta redigida de forma diferente dos seus trechos. O trecho mais próximo vem primeiro, com o seu `score`. 5. **Experimente uma coleção.** `POST /v1/collections` com `{"mode":"cloud"}`, adicione um PDF a `/items`, leia a coleção até que `indexing.complete` seja `true`, depois `POST /v1/collections/{id}/chat` e confira as `citations`. ## Casos de uso **Um assistente baseado no seu manual.** Sua intranet ingere cada página de política como blocos sob o seu `document_id`, com metadados de `category`. O assistente consulta com um filtro de `category` e passa os melhores trechos ao seu próprio prompt. Quando uma página muda, ela é ingerida de novo com uma `generation` mais alta, e os blocos que a nova versão não tem mais deixam de aparecer imediatamente. **Perguntas sobre os arquivos entregues por um cliente.** Um consultor cria uma coleção `cloud` por projeto, adiciona os contratos e planilhas que o cliente enviou e faz perguntas por meio de `chat`. Cada resposta cita o item e a página em que se baseia, de modo que cada afirmação possa ser conferida antes de entrar em um relatório; `analysis` produz um resumo, entidades e contradições entre os arquivos. **De gravações de reuniões a uma base de conhecimento.** Depois de cada reunião gravada, o aplicativo estima o preço, envia o vídeo em partes de 64 MiB com a transcrição da própria chamada como referência e inicia um trabalho com `max_price_usd`. Quando o trabalho está `done`, o arquivo compactado (áudio, quadros-chave e a base de conhecimento) é arquivado junto com a reunião. ## Limites e preços | Limite | Valor | |---|---| | Corpo da requisição do Banco de Dados Vetorial | 1 MiB | | Documentos por ingestão, ids por exclusão | 100 | | Um documento (`id` + `text` + `metadata`) | 10 KiB | | Texto da consulta; `top_k` | 8.000 caracteres; 50 | | Valores de `$in` no filtro | 20 | | Item no corpo de uma requisição, ou buscado por URL | 16 MiB | | Itens por coleção | 100; 1 GiB de arquivos enviados em requisições; 20 GiB de vídeo por envio | | `top_k` da consulta à coleção; mensagens de chat | 20; de 1 a 20 mensagens de até 8.000 caracteres | | Blocos por chamada `embed` | 100, cada um com até 8.000 caracteres | | Chamadas de modelo da análise por relatório | 32 | | Tamanho da parte de um envio | 64 MiB (todas as partes, exceto a última) | | Envio que não é vídeo (transcrição, notas) | 16 MiB | | Envio de gravação | o limite da sua organização | | Chaves de busca mantidas sem uso | 16, cada uma válida uma vez por 60 segundos | | Resultado do trabalho mantido | 24 horas | | Retenção da coleção | 30 dias por padrão | **Preços:** sob consulta. Uma gravação processada por um trabalho é precificada em **minutos de vídeo**, e `POST /v1/knowledge/estimates` devolve o preço linha por linha antes de você enviar qualquer coisa. O chat sobre uma coleção é medido como [Chat com IA](/pt-br/products/ai.chat/) na sua rota de chat. ## Erros | Status | Código | O que significa e o que fazer | |---|---|---| | 400 | `invalid_body`, `unsupported_field` | Um campo ou valor que a rota não aceita; confira os campos da rota. | | 400 | `invalid_profile` | Escolha um perfil listado por `GET /v1/vector/profiles`. | | 400 | `confirmation_required` | Excluir o banco de dados exige `{"confirm":"delete-database-and-all-vectors"}`. | | 400 | `invalid_url`, `signed_url_must_be_sealed` | Apenas URLs `https` públicas na porta 443; uma URL assinada deve ser selada. | | 400 | `fetch_key_invalid`, `invalid_sealed_url` | Solicite uma nova chave de busca e sele novamente. | | 403 | `vector_database_disabled`, `collections_disabled`, `knowledge_disabled` | Essa parte não está habilitada para a sua organização. | | 403 | `budget_exceeded` | O `max_price_usd` do trabalho está acima do limite da sua organização. | | 404 | `collection_not_found`, `job_not_found`, `upload_not_found`, `analysis_not_found` | Confira o id; o download de um trabalho também retorna `404` até que ele esteja `done`. | | 409 | `vector_database_not_created`, `vector_database_exists`, `vector_database_deleting` | Crie o banco de dados primeiro; um por organização; aguarde a conclusão de uma exclusão. | | 409 | `mode_not_supported` | A operação não existe no modo desta coleção. | | 409 | `collection_incomplete`, `collection_full` | Aguarde os itens terminarem; a coleção está no limite. | | 409 | `upload_incomplete`, `operation_id_reused`, `operation_in_progress` | Conclua o envio; use um novo id de operação para um arquivo diferente; aguarde. | | 410 | `collection_expired`, `result_expired` | A retenção terminou; processe novamente. | | 413 | `request_too_large`, `url_too_large` | Use `POST /v1/uploads` para arquivos grandes. | | 415, 422 | `unsupported_media_type`, `input_rejected`, `archive_rejected` | O tipo de arquivo não é lido, ou o arquivo foi recusado (`reason` diz o motivo). | | 429 | `too_many_fetch_keys` e os códigos de cota | Use ou deixe expirar as chaves que você mantém; veja [Erros](/pt-br/guides/errors/). | | 502, 504 | `url_fetch_failed`, `url_fetch_timeout`, `upstream_error`, `timeout_error` | A URL ou o processamento falhou; tente novamente. | | 503 | `service_unavailable` | Tente novamente mais tarde; nada foi presumido. | ## Boas práticas - **Agrupe os blocos sob um `document_id` e incremente `generation`** quando a fonte mudar; a exclusão e a substituição passam então a funcionar por documento. - **Envie `content_sha256` com cada bloco** e compare-o com `GET /v1/vector/documents` para ressincronizar a sua cópia sem ingerir tudo de novo. - **Verifique `searchable` (ou `indexing.complete`) antes de confiar nos trechos mais novos.** - **Mantenha a resposta de um trecho dentro dos seus primeiros 2.000 caracteres** quando usar a reclassificação; apenas essa parte é lida pelo reclassificador. - **Compare `vector_rerank` com `vector` simples nos seus próprios dados**, especialmente fora do inglês, antes de confiar nele. - **Estime sempre antes de um trabalho e defina `max_price_usd`**; consulte o status em `poll_after_seconds`, não mais rápido. - **Sele as URLs assinadas**; nunca envie uma URL que carregue um login. Envie os bytes em vez disso. - **Confira as citações**: um modelo pode citar uma fonte real para algo que ela não diz. ## Relacionados - [Embeddings de IA](/pt-br/products/ai.embeddings/), [Chat com IA](/pt-br/products/ai.chat/) - [Arquivos](/pt-br/products/files/): guarde os próprios arquivos de origem - [Autenticação](/pt-br/guides/authentication/), [Erros](/pt-br/guides/errors/), [Limites](/pt-br/guides/limits/) --- Produto: Motor de decisão URL: https://developer.inovacc.dev/pt-br/products/decision/ URL base: https://ai.inovacc.dev Decisões estruturadas por critérios, em um nível de velocidade e precisão a sua escolha. Endpoints: - POST /v1/run Exemplo: ```sh curl -X POST "https://ai.inovacc.dev/v1/run" -H "Authorization: Bearer $INOVACC_API_KEY" -H "X-Operation-Id: $(uuidgen)" -H "Content-Type: application/json" -d '{}' ``` ## Visão geral O Motor de decisão responde a perguntas estruturadas sobre um conteúdo com vereditos estruturados. Você envia um **estado** (a coisa a julgar: um texto, um registro, um objeto JSON) e um conjunto de **perguntas**, cada uma de um tipo conhecido; você recebe de volta uma resposta por pergunta, com o rótulo ou a pontuação escolhidos, as probabilidades por trás deles e uma confiança. O endpoint é `POST /v1/run` em `https://ai.inovacc.dev`, chamado em uma rota de decisão da sua organização. O problema que ele resolve é transformar um julgamento em dados sobre os quais um programa possa agir. Perguntar a um modelo de chat "isto está bom?" devolve prosa que você depois precisa interpretar e que não pode comparar de uma chamada para outra. O Motor de decisão devolve sempre o mesmo formato, então você pode armazená-lo, aplicar limiares e auditá-lo. Use-o para classificação, pontuação, triagem e verificações contra critérios: este chamado precisa de uma pessoa, qual das cinco categorias se encaixa, quão bem esta resposta atinge o padrão. Quando precisar de prosa gerada, use o [Chat com IA](/pt-br/products/ai.chat/); quando o veredito precisar se apoiar nos seus próprios documentos, recupere antes os trechos com [Conhecimento e busca vetorial](/pt-br/products/knowledge/) e coloque-os no estado. ## Conceitos **Rotas de decisão.** Como em todo o Inovacc AI, você chama uma rota, nunca um modelo. `GET /v1/models` lista as suas rotas; uma entrada cujo `endpoint` é `/v1/run` é uma rota de execução, e as que a Inovacc configurou como rotas de decisão respondem no formato abaixo. **Perguntas e seus tipos.** `questions` é um objeto de 1 a 64 entradas, identificadas pelos seus próprios ids (letras, dígitos, `_`, `.` ou `-`, até 100 caracteres). Cada pergunta tem um `type`, normalmente `instructions`, e `criteria` cujo formato é fixado pelo tipo: | Tipo | Pede | `criteria` | |---|---|---| | `noul` | sim ou não | um objeto `{"true": "...", "false": "..."}` | | `choice` | um rótulo entre vários | um objeto `{"label": "description", ...}` | | `score` | um nível em uma escala | um array de níveis, do mais baixo ao mais alto | Os formatos são estritos: uma string de critérios como `"1-5"` ou `"yes|no"` é recusada. **Respostas.** Cada resposta traz o que o seu tipo produziu: o `choice` ou o `score` com `probabilities`, uma `legend` e uma `confidence`. Uma resposta `noul` traz a sua probabilidade `p` em vez de uma confiança. **Níveis.** Uma rota de decisão atende um de três níveis: `fast`, `standard` ou `precise`. Todos respondem em um único formato, e o `engine.tier` da resposta diz qual deles respondeu. **A confiança não é comparável entre níveis**: cada nível informa em sua própria escala, então defina um limiar por nível. **Escalonamento.** Com `escalate`, as perguntas respondidas abaixo de um limiar de confiança são perguntadas de novo, isoladamente, no nível mais forte seguinte (`fast`, depois `standard`, depois `precise`), e a resposta mais forte substitui a mais fraca. Os padrões são `fast` 0.40, `standard` 0.80 e `precise` 0.55; você pode passar `min_confidence` (um número, ou um por nível) e `max_tier`. A confiança de uma resposta `noul` é a distância de `p` em relação a uma moeda ao ar, `|2p - 1|`. ## Como funciona Toda chamada leva `Authorization: Bearer ` e um `X-Operation-Id`. Sua organização vem da chave. O corpo aceita apenas `model`, `input` e `escalate`. Em uma rota de decisão, `input` é `{"state", "questions", "images"?}`: `state` é qualquer valor JSON não nulo, `images` tem no máximo 16 entradas. Qualquer outro campo dentro de `input` é recusado com `invalid_decision_input`, e a resposta nunca o repete. A resposta é: `{"model": "", "result": {"answers": {...}, "usage": {"input_tokens", "output_tokens"}}, "state": "Completed", "engine": {"tier", "latency_ms"}}` e seus cabeçalhos trazem `x-route-id`, `x-usage-input-tokens` e `x-usage-output-tokens`. Com escalonamento, cada resposta também diz qual `tier` a respondeu e, quando foi escalonada, `escalated_from` lista os níveis mais baixos e a confiança que cada um deu. Um objeto `escalation` informa cada tentativa, quantas perguntas foram feitas e quantas voltaram abaixo do limiar, e quantas respostas cada nível deu ao final. Cada tentativa é uma chamada própria, reservada contra as suas cotas e medida no seu próprio nível. Se uma tentativa falha, o escalonamento para, as respostas anteriores são mantidas e a requisição continua sendo `200`. Não há transmissão nem tempo limite de 60 segundos neste endpoint. Uma resposta bem-sucedida é armazenada por 24 horas sob o seu id de operação: o mesmo id devolve a mesma resposta mesclada com `x-idempotent-replay: true` e não chama nada. O que é medido são tokens, ao preço de cada nível que respondeu. ## Primeiros passos Você precisa de uma chave de API e de uma rota de decisão habilitada para a sua organização ([Autenticação](/pt-br/guides/authentication/)). 1. **Encontre a sua rota de decisão** com `GET /v1/models`: uma entrada cujo `endpoint` é `/v1/run`. 2. **Faça uma pergunta `noul`.** `POST /v1/run` com a sua rota como `model`, um texto curto como `state` e uma pergunta `{"type":"noul","instructions":"...","criteria":{"true":"...","false":"..."}}` (veja [os exemplos](#example)). A resposta traz o id da sua pergunta em `result.answers`, com a probabilidade `p`. 3. **Adicione uma pergunta `score`** com três níveis à mesma chamada. As duas respostas voltam em uma só resposta; `engine.tier` nomeia o nível. 4. **Escalone.** Envie a chamada de novo com um novo id de operação e `"escalate": true`. A resposta agora traz `tier` por resposta e um objeto `escalation` listando as tentativas. ## Casos de uso **Triagem de chamados.** Cada chamado de suporte recebido é o `state`; uma pergunta `choice` escolhe a equipe, uma pergunta `noul` pergunta se uma pessoa precisa responder, uma pergunta `score` avalia a urgência. As respostas são armazenadas junto com o chamado, e um chamado cuja confiança está abaixo do seu limiar vai para uma pessoa. **Verificações de qualidade em texto gerado.** Antes de o rascunho de um assistente ser enviado, uma chamada de decisão o pontua contra o seu padrão ("Abaixo do padrão", "No padrão", "Acima do padrão") e verifica algumas regras `noul`. Com `escalate`, apenas os rascunhos sobre os quais o nível rápido ficou em dúvida pagam pelo nível preciso. **Moderação de conteúdo com imagens.** O texto de um anúncio e até 16 imagens são julgados contra as suas perguntas de política; a confiança por pergunta decide entre publicar, rejeitar e enviar para revisão. ## Limites e preços | Limite | Valor | |---|---| | Perguntas por chamada | 1 a 64 | | Id da pergunta | 1 a 100 caracteres: letras, dígitos, `_`, `.`, `-` | | Imagens por chamada | 16 | | Corpo da requisição | 1 MiB por padrão; sua organização pode ser configurada entre 1 KiB e 20 MiB | | Tokens de entrada por requisição | o limite da sua organização | | Resposta armazenada para repetição | 24 horas | | Requisições, tokens, custo, simultaneidade, orçamentos diários | conforme definido para a sua organização | **Preços:** sob consulta. A unidade de preço é **tokens**, ao preço do nível que respondeu. ## Erros | Status | Código | O que significa e o que fazer | |---|---|---| | 400 | `invalid_input` | `input` está ausente ou não é um objeto JSON. | | 400 | `invalid_decision_input` | `input` não é `{state, questions, images?}` ou uma pergunta está malformada; confira tipos e ids. | | 400 | `invalid_escalate` | `escalate` tem uma chave ou valor que não aceita, ou a rota não é uma rota de decisão. | | 400 | `unsupported_field` | Um campo de nível superior diferente de `model`, `input`, `escalate`. | | 400 | `model_not_allowed`, `input_too_large` | Use um id de rota válido; encurte o estado. | | 400 | `missing_operation_id`, `invalid_operation_id` | Envie um `X-Operation-Id` válido. | | 401 | `missing_credentials`, `invalid_credentials` | Envie uma chave válida. | | 403 | `route_forbidden` | A rota não é sua, ou não é uma rota de execução. | | 409 | `operation_in_progress` | Esse id de operação ainda está em execução. | | 413 | `request_too_large` | O corpo excede o seu limite de tamanho. | | 429 | `rate_limited`, `quota_exceeded`, `concurrency_limited`, `budget_exhausted` | Veja [Erros](/pt-br/guides/errors/); aguarde `Retry-After` quando informado. | | 502 | `upstream_error` | O nível falhou, ou um formato de critérios foi recusado; confira os critérios e tente novamente. | | 503 | `service_unavailable` | As decisões não podem ser alcançadas; tente novamente mais tarde. | ## Boas práticas - **Escreva os critérios nos formatos estritos**: um objeto para `noul` e `choice`, um array para `score`. - **Mantenha limiares por nível**, nunca um único número para todos os níveis. - **Use `escalate` com `max_tier`** para limitar o custo: a maioria das perguntas para no nível mais barato. - **Coloque no `state` tudo de que o julgamento precisa**, incluindo os trechos recuperados; o motor não vê mais nada. - **Use ids de pergunta estáveis**, para que as respostas possam ser comparadas entre chamadas e armazenadas por id. - **Derive o id de operação do item julgado** para que um lote repetido reaproveite a resposta em vez de pagar duas vezes. ## Relacionados - [Chat com IA](/pt-br/products/ai.chat/), [Conhecimento e busca vetorial](/pt-br/products/knowledge/) - [Autenticação](/pt-br/guides/authentication/), [Erros](/pt-br/guides/errors/), [Limites](/pt-br/guides/limits/) --- Produto: Dados URL: https://developer.inovacc.dev/pt-br/products/data/ URL base: https://data.inovacc.dev Bancos, coleções e registros com esquemas e regras, por uma única porta REST/JSON. Endpoints: - GET /v1/databases - PUT /v1/databases/{database} - PUT /v1/databases/{database}/collections/{collection} - POST /v1/databases/{database}/collections/{collection}/records - POST /v1/databases/{database}/batch Exemplo: ```sh curl -X GET "https://data.inovacc.dev/v1/databases" -H "Authorization: Bearer $INOVACC_API_KEY" ``` ## Visão geral Dados é o banco de dados da sua aplicação, servido por uma única porta REST/JSON em `https://data.inovacc.dev`. Você cria **bancos de dados**, dá a eles **coleções** e lê e grava **registros** com chamadas HTTP simples. Uma coleção é tipada, com campos declarados por um esquema, ou livre, contendo documentos JSON sem esquema. Quem pode fazer o quê é decidido em cada requisição, primeiro pelas permissões da credencial e depois, registro a registro, pelas **regras** que a coleção declara. O problema que ele resolve é manter dados persistentes sem operar um banco de dados: sem servidor, sem pool de conexões, sem ferramenta de migração, sem backups para agendar. Sua aplicação mantém o próprio código e armazena seus dados aqui; onde os dados vivem é decidido pela Inovacc e nunca é exibido. A mesma API atende os seus servidores, as suas páginas web (com uma chave de navegador) e as pessoas autenticadas no seu aplicativo, e um ouvinte em tempo real envia as mudanças conforme elas acontecem. Use Dados para o estado da aplicação: notas de usuários, pedidos, configurações, catálogos, qualquer coisa com formato de registro. Armazene conteúdo binário grande com [Arquivos](/pt-br/products/files/), consulte o que aconteceu com o [Registro de atividade](/pt-br/products/activity/) e avise outros sistemas com [Eventos](/pt-br/products/events/). ## Conceitos **Bancos de dados.** Um banco de dados é uma chave que a sua aplicação escolhe, como `shop` ou `crm/v2` (uma `/` é escrita `%2F` em um caminho). Um banco de dados pertence à aplicação cuja credencial o criou; o banco de dados de outra aplicação responde `404`, como se não existisse. Uma credencial no nível da organização enxerga todos os bancos de dados da organização. **Coleções: com esquema ou livres.** Uma coleção com **esquema** declara até 64 campos, cada um com um tipo: `text`, `integer`, `number`, `bool`, `datetime`, `json`, `relation` (um id de registro em uma coleção `target`) ou `blob` (o SHA-256 de um arquivo no mesmo banco de dados). Um campo pode ser `required`, `unique`, `indexed` ou `fulltext` (em `text`). Uma coleção **livre** não declara nada: cada registro é um documento JSON, consultado por caminho com pontos (`profile.city`), e pode receber um esquema mais tarde, quando todos os documentos se encaixarem nele. Gravar em uma coleção que não existe cria uma coleção livre, quando a sua credencial pode alterar esquemas. **Registros e versões.** Um registro é `{id, version, created_at, updated_at, ...fields}`. Seu `id` é gerado pelo serviço (`rec_` mais 26 caracteres ordenáveis) ou escolhido por você. Toda alteração aumenta `version` em um; atualizações e exclusões devem enviar `If-Match: `, para que dois escritores nunca se sobrescrevam silenciosamente. **Regras.** Uma coleção declara cinco regras, `list`, `view`, `create`, `update` e `delete`. Cada uma é `null` (ninguém), `""` (qualquer credencial de servidor da sua organização), `public` (qualquer pessoa, chaves de navegador incluídas), `users` (as pessoas autenticadas da aplicação proprietária, e os servidores) ou uma expressão como `owner = @auth.id`. As regras valem para todas as credenciais, inclusive a de um administrador. **Credenciais.** Uma **chave secreta** é para servidores. Uma **chave publicável** (`apb_...`) é para páginas web: funciona apenas a partir das origens que a sua aplicação lista e apenas onde uma regra a admite. O **token de acesso** de uma pessoa autenticada carrega apenas permissões de registros e arquivos. ## Como funciona Toda chamada leva `Authorization: Bearer `. Não há cabeçalho de organização: a sua organização, e a aplicação, vêm da credencial, e nada em um caminho, consulta ou cabeçalho pode nomear outra. Uma requisição sem credencial válida, ou para um caminho que não é uma rota, recebe um `401` idêntico. Em cada chamada, o serviço verifica primeiro a permissão da credencial para a ação (leitura, escrita, criação, atualização, exclusão ou alterações de esquema) no banco de dados. Qualquer coisa diferente de "permitir" é `403 forbidden` sem detalhes. Depois a regra da coleção decide por registro: uma listagem devolve apenas os registros que a regra `list` admite; ler um registro que a regra `view` oculta é `404`, igual a um registro inexistente; uma criação verifica os dados novos; uma atualização verifica tanto o registro armazenado quanto os dados novos. As escritas são versionadas. `POST /records` cria e responde `201` com `ETag: "1"`. `PATCH` altera os campos informados (em uma coleção livre é um JSON merge patch), `PUT` substitui o registro, e `PUT` com `If-None-Match: *` o cria no id que você escolheu. Um `If-Match` errado é `409 version_conflict`; um ausente é `428`. As listagens aceitam `filter` (`field op value` unidos por `&&` e `||`), `sort`, `limit` (até 200) e um `cursor` opaco, e devolvem `next_cursor` até a última página; `q` pesquisa os campos `fulltext`. Um **lote** aplica até 100 criações, atualizações e exclusões em uma única transação: todas têm sucesso, ou nenhuma. Um **ouvinte em tempo real** é um WebSocket em `GET .../collections/{c}/listen`: ele envia `ready` e depois eventos `added`, `modified` e `removed` para os registros que a sua regra permite listar. Toda chamada é registrada no [Registro de atividade](/pt-br/products/activity/). ## Primeiros passos Você precisa de uma chave secreta com permissão para criar bancos de dados e coleções ([Autenticação](/pt-br/guides/authentication/)). 1. **Crie um banco de dados.** `PUT /v1/databases/notes` sem corpo. A resposta é `201` com `{key, created_at}`; repetir a chamada responde `200`. 2. **Declare uma coleção.** `PUT /v1/databases/notes/collections/items` com os campos `owner` e `body` e as regras (veja [os exemplos](#example)). A resposta é a coleção com `schema_version` 1. 3. **Grave um registro.** `POST .../collections/items/records` com os campos. A resposta é `201` com o registro, seu `id` e `version` 1. 4. **Atualize-o.** `PATCH .../records/{id}` com `If-Match: 1`. A resposta tem `version` 2; enviar `If-Match: 1` de novo resulta em `409 version_conflict`. 5. **Liste.** `GET .../records?filter=owner%20%3D%20%22me%22&limit=10` devolve o seu registro e `next_cursor: null`. ## Casos de uso **Dados por usuário em um aplicativo web.** Um aplicativo de notas declara uma coleção cujas cinco regras dizem `owner = @auth.id`. A página chama Dados diretamente com o token da pessoa autenticada; cada pessoa lista e edita apenas as próprias notas, e a nota de outra pessoa resulta em `404`. Nenhum código de servidor garante isso: as regras garantem. **Um catálogo público.** Uma loja online mantém `products` como uma coleção livre com `list` e `view` definidos como `public` e as escritas fechadas. A vitrine a lê do navegador com uma chave publicável; o back office a escreve a partir de um servidor com uma chave secreta. **Painéis em tempo real.** Uma tela de operações abre um ouvinte em `orders` filtrado pelos pedidos abertos de hoje. Ela executa a consulta após `ready`, depois aplica os eventos `added`, `modified` e `removed` conforme chegam, sem fazer polling. ## Limites e preços | Limite | Valor | |---|---| | Corpo da requisição JSON | 1 MiB | | Um registro | 900 KiB | | Um campo `json` | 64 KiB | | Campos por coleção; coleções por banco de dados | 64; 64 | | Registros por página | 200 (padrão 50) | | Operações por lote | 100, em uma única transação | | Filtro | 2.048 caracteres, 40 valores, profundidade de aninhamento 8 | | Query string | 16 KiB | | Busca de texto completo `q` | 16 termos, 256 caracteres | | Ouvintes por coleção; um evento de ouvinte | 1.000; 512 KiB | | Taxa | 600 requisições por minuto por titular de credencial, por localização (`429 rate_limited`) | **Preços:** sob consulta. ## Erros | Status | Código | O que significa e o que fazer | |---|---|---| | 400 | `invalid_body`, `invalid_name`, `unknown_field`, `missing_field`, `invalid_value` | O corpo ou um nome viola as regras; corrija-o. | | 400 | `record_too_large`, `field_too_large`, `reserved_field` | Reduza o registro; não envie `id`, `version`, `created_at`, `updated_at` em um corpo. | | 400 | `invalid_schema`, `invalid_rule`, `schema_change_unsupported` | A definição da coleção não é válida, ou um campo foi alterado no lugar. | | 400 | `invalid_filter`, `invalid_sort`, `invalid_cursor`, `invalid_limit`, `invalid_search` | Corrija a consulta da listagem; recomece sem o cursor. | | 400 | `invalid_if_match`, `batch_too_large`, `cross_shard_batch` | Confira o cabeçalho ou divida o lote. | | 401 | `invalid_credentials` | Envie uma credencial válida. | | 403 | `forbidden` | As permissões da credencial ou a regra da coleção a recusam. | | 403 | `origin_not_allowed`, `secret_key_in_browser` | Uma chave de navegador vinda de uma origem não listada, ou uma chave secreta em um navegador. | | 404 | `database_not_found`, `collection_not_found`, `record_not_found` | Não existe, ou você não pode vê-lo. | | 409 | `version_conflict` | Alguém alterou o registro; leia-o novamente e tente de novo. | | 409 | `already_exists`, `unique_violation`, `not_empty`, `schema_violation` | O id ou valor já está em uso; esvazie antes de excluir; os documentos não se encaixam no esquema. | | 412, 428 | `precondition_failed`, `precondition_required` | O registro já existe; envie `If-Match`. | | 413 | `payload_too_large` | O corpo excede 1 MiB. | | 429 | `rate_limited`, `too_many_listeners` | Diminua o ritmo; feche os ouvintes de que não precisa. | | 503 | `service_unavailable` | Tente novamente mais tarde; nada foi gravado. | ## Boas práticas - **Envie sempre `If-Match`** com a versão que você leu e, em `409 version_conflict`, leia de novo antes de tentar novamente. - **Feche toda coleção por padrão** e abra-a regra a regra; uma coleção nascida de uma escrita admite qualquer credencial de servidor até que você a restrinja. - **Nunca coloque uma chave secreta em uma página web**: use uma chave publicável e regras `public` ou `@auth`. - **Escolha os seus próprios ids de registro** nas importações, para que uma importação repetida não crie nada duas vezes (`409 already_exists`). - **Use um lote** quando várias escritas precisarem ter sucesso juntas. - **Indexe os campos em que você filtra e ordena** e siga `next_cursor` em vez de usar páginas grandes. - **Com um ouvinte, espere por `ready` antes de consultar**, e descarte depois os eventos que não sejam mais novos do que o que a consulta devolveu. ## Relacionados - [Arquivos](/pt-br/products/files/): conteúdo binário ao lado dos seus registros - [Registro de atividade](/pt-br/products/activity/): o que foi gravado e por quem - [Eventos](/pt-br/products/events/): avise outros sistemas sobre uma mudança - [Autenticação](/pt-br/guides/authentication/), [Erros](/pt-br/guides/errors/), [Limites](/pt-br/guides/limits/) --- Produto: Arquivos URL: https://developer.inovacc.dev/pt-br/products/files/ URL base: https://data.inovacc.dev Armazenamento de arquivos por conteúdo, com envio em partes para arquivos grandes. Endpoints: - PUT /v1/databases/{database}/blobs/{sha256} - GET /v1/databases/{database}/blobs/{sha256} - DELETE /v1/databases/{database}/blobs/{sha256} - POST /v1/databases/{database}/blobs/{sha256}/uploads Exemplo: ```sh curl -X PUT "https://data.inovacc.dev/v1/databases/{database}/blobs/{sha256}" -H "Authorization: Bearer $INOVACC_API_KEY" -H "Content-Type: application/json" -d '{}' ``` ## Visão geral Arquivos armazena o conteúdo binário da sua aplicação (imagens, documentos, exportações, gravações) em `https://data.inovacc.dev`, com envios em partes para tudo o que for grande. Ele oferece duas formas de endereçar um arquivo: - **por caminho, na pasta da sua aplicação**: `PUT /v1/files/users/123/avatar.png`, do jeito que um bucket de armazenamento na nuvem nomeia arquivos, com listagens por pasta, metadados do usuário e pastas compartilhadas com outras aplicações do seu espaço de trabalho; - **por conteúdo, dentro de um banco de dados**: `PUT /v1/databases/{db}/blobs/{sha256}`, em que o próprio SHA-256 do arquivo é o seu nome, de modo que um registro de [Dados](/pt-br/products/data/) pode apontar para ele com um campo `blob`. O problema que ele resolve é manter arquivos junto dos seus dados sem operar armazenamento: a Inovacc escolhe onde os bytes vivem, verifica-os contra o hash, remove duplicatas dentro da sua pasta e os devolve com cabeçalhos que impedem que um arquivo baixado seja executado em um navegador. Use Arquivos para tudo o que for bytes em vez de campos. Mantenha a descrição estruturada de um arquivo (proprietário, título, status) como um registro em [Dados](/pt-br/products/data/). Para tornar um arquivo pesquisável por significado, adicione-o a uma coleção de [Conhecimento e busca vetorial](/pt-br/products/knowledge/). ## Conceitos **A pasta da sua aplicação.** Cada aplicação tem a sua própria pasta. A pasta é escolhida a partir da credencial, nunca da requisição: uma credencial vinculada a uma aplicação usa a pasta dessa aplicação, e uma credencial não vinculada a nenhuma aplicação recebe `403 application_required` em toda rota de caminho. Os caminhos são UTF-8, de 1 a 1.024 bytes, separados por `/`, diferenciam maiúsculas de minúsculas, sem segmentos vazios, `.` ou `..`; um caminho que ainda não esteja nessa forma é recusado, nunca reescrito silenciosamente. **Metadados.** Uma escrita pode levar um `Content-Type` e cabeçalhos `X-File-Meta-` próprios (2 KiB no total). Ambos voltam em toda leitura. Uma escrita substitui por inteiro o conteúdo, o tipo e os metadados do arquivo. **Hashes.** Todo arquivo é identificado pelo seu SHA-256. Envie `X-File-Sha256` com uma escrita e os bytes são conferidos contra ele (`400 hash_mismatch`, nada é armazenado). Dentro da pasta de uma aplicação, dois caminhos com os mesmos bytes compartilham uma única cópia armazenada; a cópia é mantida até que o último caminho seja removido. A deduplicação nunca atravessa aplicações ou organizações. **Blobs de banco de dados.** Um blob é endereçado pelo SHA-256 em seu caminho dentro de um banco de dados. Enviá-lo de novo responde `200` em vez de `201`. Qualquer pessoa com permissão de leitura no banco de dados que conheça o hash pode lê-lo: as regras de registros não se aplicam a blobs. **Pastas compartilhadas.** Uma aplicação pode criar uma pasta `team` que aparece para toda aplicação com acesso como `shared/team/...`. Quem a criou é o proprietário e concede a outras aplicações do mesmo espaço de trabalho `read` ou `read_write`. Uma aplicação sem acesso não consegue saber que a pasta existe: toda operação responde `404`. **Arquivos grandes.** Até 100 MiB vão em uma única requisição. Acima disso, até 5 GiB, você envia em partes e depois vincula o resultado a um caminho (ou ele se torna o blob). ## Como funciona Toda chamada leva `Authorization: Bearer `; não há cabeçalho de organização, porque a sua organização e a aplicação vêm da credencial. A permissão verificada é de leitura, escrita ou exclusão de blobs. Uma página web pode usar essas rotas com uma chave publicável a partir de uma origem que a sua aplicação lista. **Escrita por caminho.** `PUT /v1/files/{path}` com os bytes e um `Content-Length` (obrigatório). A resposta é `201` para um caminho novo ou `200` para uma substituição: `{"path","size","sha256","content_type","updated_at","metadata"}` e `ETag: ""`. **Leitura.** `GET /v1/files/{path}` devolve o arquivo inteiro (intervalos não são suportados) com `Content-Type`, `ETag`, `X-File-Sha256`, `X-File-Updated-At` e os seus cabeçalhos `X-File-Meta-*`. Todo download também traz `X-Content-Type-Options: nosniff`, um `Content-Security-Policy` que o isola e `Cache-Control: no-store`, de modo que uma página HTML enviada nunca possa ser executada como se fosse o seu site. `HEAD` devolve apenas os cabeçalhos. **Listagem.** `GET /v1/files?prefix=photos/&delimiter=/` lista os arquivos diretamente sob uma pasta como `items` e cada subpasta uma única vez em `prefixes`. Siga `next_cursor` até que seja `null`: uma página pode ser menor que `limit` e ainda assim ter uma próxima. **Em partes.** `POST /v1/files-uploads/{sha256}` inicia um envio (ou responde `200` com `exists: true` quando a sua pasta já contém esses bytes). Envie as partes de 1 a 10.000 com `PUT .../{upload_id}/parts/{n}`, cada uma entre 5 MiB e 100 MiB, exceto a última, e depois `POST .../complete` com a lista de partes e seus `etag`s. A Inovacc lê o objeto inteiro de volta e confere o seu SHA-256 e o tamanho. Por fim, `PUT /v1/files/{path}` com `X-File-Sha256` e corpo vazio dá a ele um caminho. Os blobs de banco de dados usam as mesmas quatro etapas em `/v1/databases/{db}/blobs/{sha256}/uploads`. Envios, downloads e exclusões são registrados no [Registro de atividade](/pt-br/products/activity/) com o hash e o tamanho do arquivo. ## Primeiros passos Você precisa de uma chave secreta vinculada a uma aplicação, com permissões de blobs ([Autenticação](/pt-br/guides/authentication/)). 1. **Envie um arquivo.** `PUT /v1/files/reports/2026-10.csv` com o arquivo como corpo e `Content-Type: text/csv` (veja [os exemplos](#example)). A resposta é `201` com o seu `sha256`. 2. **Leia-o de volta.** `GET /v1/files/reports/2026-10.csv`. Os bytes chegam com `ETag` igual ao hash do passo 1. 3. **Liste a pasta.** `GET /v1/files?prefix=reports/&delimiter=/`. O seu arquivo está em `items`. 4. **Substitua-o.** Faça `PUT` no mesmo caminho com bytes novos. A resposta é `200`, com um novo `sha256`. 5. **Exclua-o.** `DELETE /v1/files/reports/2026-10.csv` responde `204`; um segundo `GET` resulta em `404 file_not_found`. ## Casos de uso **Fotos de perfil a partir do navegador.** Um aplicativo web envia cada avatar para `users//avatar.png` com uma chave publicável e guarda o `sha256` devolvido no registro do usuário, para que uma página perceba quando a imagem mudou. **Exportações compartilhadas com um aplicativo parceiro.** Uma aplicação de relatórios cria a pasta compartilhada `exports`, concede `read` à aplicação de faturamento e grava arquivos mensais em `shared/exports/`. A aplicação de faturamento os lista e baixa; revogar a concessão tem efeito já na requisição seguinte dela. **Mídia grande com integridade.** Uma ferramenta de vídeo calcula o hash de uma gravação de 2 GiB no cliente, envia-a em partes de 100 MiB e a conclui. A Inovacc só a armazena se o SHA-256 coincidir, de modo que uma transferência corrompida nunca se torna um arquivo. ## Limites e preços | Limite | Valor | |---|---| | Arquivo ou blob em uma requisição | 100 MiB, `Content-Length` obrigatório | | Arquivo ou blob enviado em partes | 5 GiB; partes de 5 MiB a 100 MiB (exceto a última), numeradas de 1 a 10.000 | | Caminho | 1.024 bytes | | Prefixo de listagem | 256 bytes | | Metadados por arquivo | 2 KiB | | Página de listagem | 1 a 200 (padrão 50) | | Nome da pasta compartilhada | 1 a 64 letras, dígitos, `_` ou `-` | | Taxa | 600 requisições por minuto por titular de credencial, por localização | **Preços:** sob consulta. ## Erros | Status | Código | O que significa e o que fazer | |---|---|---| | 400 | `invalid_path`, `invalid_prefix` | O caminho ou prefixo não está na forma canônica; corrija do seu lado. | | 400 | `invalid_metadata` | `Content-Type` ou `X-File-Meta-*` viola as regras ou excede 2 KiB. | | 400 | `hash_mismatch` | Os bytes não correspondem ao SHA-256 que você enviou; nada foi armazenado. | | 400 | `invalid_part`, `invalid_limit`, `invalid_cursor`, `invalid_grantee` | Corrija as partes do envio, a listagem ou a concessão. | | 401 | `invalid_credentials` | Envie uma credencial válida. | | 403 | `application_required` | As rotas de caminho exigem uma credencial vinculada a uma aplicação. | | 403 | `forbidden` | Falta permissão, ou um beneficiário com `read` tentou escrever. | | 404 | `file_not_found`, `blob_not_found`, `share_not_found`, `upload_not_found` | Não existe, ou você não tem acesso a ele. | | 409 | `already_exists`, `not_empty` | O nome da pasta compartilhada já está em uso; esvazie a pasta antes de excluí-la. | | 411 | `length_required` | Envie `Content-Length`. | | 413 | `payload_too_large` | Mais de 100 MiB em uma requisição (use partes) ou mais de 5 GiB. | | 429 | `rate_limited` | Diminua o ritmo. | | 503 | `service_unavailable` | Tente novamente mais tarde. | ## Boas práticas - **Envie `X-File-Sha256` em toda escrita** para que um envio danificado seja recusado em vez de armazenado. - **Use partes acima de 100 MiB** e comece com `POST .../uploads`: ele responde `exists: true` quando os bytes já estão lá. - **Guarde o `sha256`, não apenas o caminho**, nos seus registros; ele diz exatamente a que conteúdo um registro se refere. - **Siga `next_cursor` até o fim** ao listar; páginas curtas são normais. - **Conceda `read`, a menos que um parceiro precise escrever**, e revogue as concessões de que não precisa mais. - **Não conte com blobs serem privados por regra**: qualquer pessoa que possa ler o banco de dados e conheça o hash pode ler um blob. ## Relacionados - [Dados](/pt-br/products/data/): registros que apontam para arquivos com campos `blob` - [Registro de atividade](/pt-br/products/activity/): envios e downloads com seus hashes - [Conhecimento e busca vetorial](/pt-br/products/knowledge/): torne documentos pesquisáveis - [Autenticação](/pt-br/guides/authentication/), [Erros](/pt-br/guides/errors/), [Limites](/pt-br/guides/limits/) --- Produto: Registro de atividade URL: https://developer.inovacc.dev/pt-br/products/activity/ URL base: https://data.inovacc.dev Leia o registro da sua organização com as chamadas de API e os eventos de arquivos e registros. Endpoints: - GET /v1/activity Exemplo: ```sh curl -X GET "https://data.inovacc.dev/v1/activity" -H "Authorization: Bearer $INOVACC_API_KEY" ``` ## Visão geral O Registro de atividade é o registro da própria organização sobre o que aconteceu na Inovacc: toda chamada de API e todo evento de arquivo e de registro que essas chamadas causaram. Você o lê com um único endpoint, `GET /v1/activity` em `https://data.inovacc.dev`, filtrado por período, tipo de evento ou hash de arquivo. O problema que ele resolve é responder "quem fez o quê, e quando" sem construir a sua própria trilha de auditoria. O registro é mantido pela Inovacc para toda chamada às APIs de Dados, de IA e de Eventos, quer a sua aplicação se lembre ou não de gravar alguma coisa. Registrar é um fato do serviço, não uma opção, e uma organização só enxerga os próprios registros. Use-o para auditorias, para investigar uma integração que falhou ("quais chamadas foram recusadas esta manhã, e com qual código?"), para provar que um arquivo foi entregue (o evento de download carrega o SHA-256 do arquivo) e para ter uma visão do tráfego por chave. Para ver quanto o seu uso de IA **custou**, use o resumo de uso do [Chat com IA](/pt-br/products/ai.chat/) (`GET /v1/usage/summary`): o Registro de atividade registra eventos, nunca preços. ## Conceitos **Eventos e tipos.** Cada registro é um evento com um `kind`: | Tipo | Gravado quando | |---|---| | `api.call` | qualquer chamada autenticada, inclusive as recusadas (`403`, `429`) | | `record.write`, `record.delete` | um registro é criado, alterado ou excluído (um por operação de um lote) | | `blob.write`, `blob.read`, `blob.delete` | um blob de banco de dados é enviado, baixado ou excluído | | `file.upload.completed`, `file.download`, `file.delete` | um arquivo é gravado, baixado ou excluído | | `file.upload.started`, `file.processed` | gravados por outros serviços da Inovacc, como envios e conversões de IA | **O que um registro contém.** O horário (`at_ms`, milissegundos Unix), a organização, quem agiu (`actor_kind`: `user`, `key` ou `service`, e `actor_id`), o serviço de origem `source`, o `method`, a `route` (um modelo como `/v1/databases/{database}/collections/{collection}/records/{record_id}`, nunca os ids em si), o `status`, o `outcome`, o `error_code` de uma falha, a latência, os tamanhos de entrada e saída e, para um arquivo, seu tamanho, tipo e SHA-256. `related` aponta para o banco de dados, a coleção e o registro, ou para o envio ou trabalho, envolvidos. Todas as chaves estão sempre presentes, `null` quando não se aplicam. **O que ele nunca contém.** Um prompt, o corpo de uma resposta ou o conteúdo de um arquivo. As chamadas de IA nunca registram o nome de um arquivo. **País.** Um registro `api.call` traz `country`: o país de quem chamou, como a borda de rede da Inovacc o vê (duas letras, `XX` quando desconhecido). Ele não pode ser definido por quem chama, e o registro não guarda cidade, endereço IP nem coordenadas. **Retenção.** Os registros são mantidos por um ano. Os últimos 30 dias respondem imediatamente; os registros mais antigos vêm do arquivo morto e demoram mais. ## Como funciona Chame `GET /v1/activity` com `Authorization: Bearer `. A credencial precisa da permissão de leitura de atividade no nível da organização; uma credencial limitada a registros não a tem. A organização é sempre a da credencial: não há parâmetro que nomeie outra. Todo parâmetro é opcional: | Parâmetro | Significado | |---|---| | `from`, `to` | milissegundos Unix, UTC; `from` inclusivo, `to` exclusivo | | `kind` | um ou mais tipos, separados por vírgula | | `file_sha256` | 64 caracteres hexadecimais minúsculos: todos os eventos desse arquivo | | `limit` | de 1 a 500, padrão 100 | | `cursor` | o `next_cursor` da página anterior, sem alteração | Qualquer outro parâmetro, um repetido ou vazio, ou um valor inválido resulta em `400 invalid_query`, e nada é lido. A resposta vem do mais novo para o mais antigo: `{"items":[...],"next_cursor":,"archive_searched":}`. Siga `next_cursor` até que seja `null`. `archive_searched` informa que a leitura foi além dos últimos 30 dias. Uma leitura pode voltar no máximo 366 dias por chamada. Os registros aparecem alguns segundos depois da chamada, não instantaneamente. O registro acontece depois da resposta e nunca a altera: se o registro não puder ser gravado, a chamada é respondida normalmente. Um download de Dados ou de Arquivos é registrado quando começa; um download da API de IA é registrado quando a transferência termina. A API de IA também oferece `GET /v1/activity` em `https://ai.inovacc.dev` para as suas próprias chamadas, com `from` e `to` como instantes RFC 3339; lê-lo ali não é cobrado. ## Primeiros passos Você precisa de uma credencial com a permissão de leitura de atividade ([Autenticação](/pt-br/guides/authentication/)). 1. **Faça uma chamada para ser registrada.** Grave um registro em [Dados](/pt-br/products/data/) ou envie um arquivo em [Arquivos](/pt-br/products/files/). 2. **Leia os eventos mais recentes.** `GET /v1/activity?limit=10` (veja [os exemplos](#example)). A sua chamada está lá como `api.call`, com o modelo de rota e o status, seguida do seu `record.write` ou `file.upload.completed`. 3. **Filtre por tipo.** `GET /v1/activity?kind=api.call&limit=50` mostra apenas chamadas; observe `status` e `error_code` para encontrar recusas. 4. **Acompanhe um arquivo.** Pegue o `file_sha256` do seu envio e chame `GET /v1/activity?file_sha256=`: todo envio, download e exclusão desse conteúdo é listado. 5. **Pagine.** Devolva o `next_cursor` como `cursor` até que seja `null`. ## Casos de uso **Uma resposta de auditoria.** Um cliente pergunta quem excluiu um registro na terça-feira passada. Filtre `kind=record.delete` com `from` e `to` em torno desse dia; o evento nomeia o autor e `related` nomeia o banco de dados, a coleção e o registro. **Prova de entrega.** Uma equipe de conformidade precisa mostrar que um relatório chegou a um parceiro. O evento `file.download` traz o SHA-256 e o tamanho dos bytes enviados, e o horário, que podem ser comparados com o arquivo original. **Saúde de uma integração.** Uma integração começa a falhar à noite. Filtrar `kind=api.call` para essa janela mostra o `status` e o `error_code` de cada chamada feita pela chave da integração, por exemplo uma sequência de `429 rate_limited` que aponta para a falta de espera crescente. ## Limites e preços | Limite | Valor | |---|---| | Retenção | um ano; os últimos 30 dias respondem imediatamente | | Intervalo de uma leitura | 366 dias | | Tamanho da página | 1 a 500 (padrão 100) | | Atraso até um evento ficar legível | alguns segundos | | Taxa | 600 requisições por minuto por titular de credencial, por localização | **Preços:** sob consulta. ## Erros | Status | Código | O que significa e o que fazer | |---|---|---| | 400 | `invalid_query` | Um parâmetro é desconhecido, repetido, vazio ou inválido; corrija a consulta. | | 401 | `invalid_credentials` | Envie uma credencial válida. | | 403 | `forbidden` | A credencial não tem a permissão de leitura de atividade. | | 429 | `rate_limited` | Diminua o ritmo. | | 503 | `service_unavailable` | O registro não pode ser lido agora; tente novamente mais tarde. | ## Boas práticas - **Filtre no servidor**: passe `kind`, `from` e `to` em vez de ler tudo e filtrar no seu código. - **Guarde o `at_ms` mais recente que você processou** e leia a partir dele na próxima execução, seguindo os cursores até o fim. - **Use `file_sha256`** para rastrear um arquivo entre envios, downloads e processamento de IA. - **Espere alguns segundos de atraso**; não trate um evento recém-criado que ainda não aparece como uma falha. - **Ignore chaves que você não conhece**: os registros podem ganhar campos. - **Dê a cada integração a sua própria chave**, para que `actor_id` diga qual delas agiu. ## Relacionados - [Dados](/pt-br/products/data/), [Arquivos](/pt-br/products/files/), [Eventos](/pt-br/products/events/) - [Chat com IA](/pt-br/products/ai.chat/): uso e custo por chave e rota - [Autenticação](/pt-br/guides/authentication/), [Erros](/pt-br/guides/errors/), [Limites](/pt-br/guides/limits/) --- Produto: Eventos URL: https://developer.inovacc.dev/pt-br/products/events/ URL base: https://events.inovacc.dev Publique eventos e entregue-os aos assinantes por webhook, consulta ou transmissão ao vivo, com mensagens mortas e reenvio. Endpoints: - POST /v1/workspaces/{workspace_id}/events - GET /v1/workspaces/{workspace_id}/subscriptions - POST /v1/workspaces/{workspace_id}/subscriptions - DELETE /v1/workspaces/{workspace_id}/subscriptions/{subscription_id} - POST /v1/workspaces/{workspace_id}/subscriptions/{subscription_id}/rotate-secret - POST /v1/workspaces/{workspace_id}/subscriptions/{subscription_id}/pull - POST /v1/workspaces/{workspace_id}/subscriptions/{subscription_id}/ack - GET /v1/workspaces/{workspace_id}/subscriptions/{subscription_id}/stream - GET /v1/workspaces/{workspace_id}/dead - POST /v1/workspaces/{workspace_id}/dead/{event_id}/replay - GET /v1/workspaces/{workspace_id}/stats Exemplo: ```sh curl -X POST "https://events.inovacc.dev/v1/workspaces/{workspace_id}/events" -H "Authorization: Bearer $INOVACC_API_KEY" -H "Content-Type: application/json" -d '{}' ``` ## Visão geral Eventos permite que uma parte do seu sistema anuncie que algo aconteceu, e que cada parte interessada fique sabendo, sem que as duas se conheçam. Um publicador envia um evento como `order.paid` para `https://events.inovacc.dev`; toda **assinatura** cujo padrão corresponda ao tipo do evento o recebe, por **webhook** no seu endpoint HTTPS, por **pull** a partir do seu worker, ou por **transmissão ao vivo** por um WebSocket. Os eventos que não podem ser entregues são mantidos como **mensagens mortas**, que você pode inspecionar e reenviar. O problema que ele resolve é a distribuição confiável. Chamar cada serviço interessado diretamente os acopla, perde mensagens quando um deles está fora do ar e faz novas tentativas de forma ruim. Eventos aceita a publicação uma vez, a entrega pelo menos uma vez a cada assinatura, repete as entregas que falharam com espera crescente, deduplica publicações repetidas e guarda o que não conseguiu entregar. Use Eventos para reagir a mudanças: enviar um e-mail quando um pedido é pago, atualizar um cache quando um registro muda, enviar uma notificação a uma página. Mantenha o próprio estado em [Dados](/pt-br/products/data/) e os bytes em [Arquivos](/pt-br/products/files/): um evento deve dizer *o que aconteceu*, não carregar o objeto. Para a história completa do receptor de webhooks, veja o [guia de Webhooks](/pt-br/guides/webhooks/). ## Conceitos **Espaço de trabalho.** Toda rota fica sob `/v1/workspaces/{workspace}`. O espaço de trabalho no caminho é uma declaração conferida contra a sua credencial: uma chave de aplicação só pode nomear o seu próprio espaço de trabalho, e qualquer outro responde `403 forbidden`, igual a um que não existe. **Eventos e o envelope.** Você publica `type` (palavras minúsculas separadas por pontos, como `invoice.created`, até 128 bytes), `data` (qualquer valor JSON) e uma `idempotency_key` opcional. Os assinantes recebem um envelope com `event_id` (`evt_` e 26 caracteres, atribuído pela Inovacc), `type`, `source` (a sua aplicação, definida a partir da credencial), `time`, `tenant`, `idempotency_key` e `data`. **Níveis.** Uma publicação pode nomear um `tier`: `basic` (o padrão), `reliable` ou `advanced`. O nível define o maior `data` que um evento pode carregar: 16 KiB para `basic` e `reliable`, 32 KiB para `advanced`. **Assinaturas e padrões.** Uma assinatura lista de 1 a 20 padrões em `types`, cada um sendo `*` (tudo), um tipo exato ou um prefixo terminado em `.*` (`order.*` corresponde a `order.paid` e `order.item.added`), e um modo de entrega. **Modos de entrega.** `webhook` envia cada evento por POST à sua URL HTTPS, assinado com o segredo da assinatura. `pull` mantém uma caixa de entrada que o seu código lê e confirma. `websocket` mantém a mesma caixa de entrada e também a transmite ao vivo; o pull continua funcionando ao lado da transmissão. **Pelo menos uma vez.** Cada evento chega a cada assinatura correspondente uma vez em operação normal, mas uma nova tentativa ou uma confirmação perdida pode entregá-lo de novo. Os receptores deduplicam por `event_id`. **Mensagens mortas.** Uma entrega por webhook que continua falhando é movida para as mensagens mortas do seu espaço de trabalho, com o último erro e o número de tentativas, e mantida por 30 dias. ## Como funciona Toda chamada leva `Authorization: Bearer `. A credencial é o tenant: organização, conta e aplicação vêm dela, e nada em um corpo pode nomear outra. Uma **chave secreta** é para servidores e pode usar todas as rotas. Uma **chave publicável** (`apb_...`) só pode abrir uma transmissão, a partir de uma origem que a sua aplicação lista. O token de um usuário final não pode usar nada. Cada rota exige a sua própria permissão, como `events:event.publish`, `events:subscription.write` ou `events:dead.replay`. **Publicar.** `POST /events` com `{"event": {...}}` ou `{"events": [...]}` (de 1 a 100). A resposta é `202` com `accepted` (cada um com o seu `event_id` e `duplicate`) e `rejected` (cada um com um índice e um código); um evento inválido nunca bloqueia os outros. Enviar uma `idempotency_key` já usada no espaço de trabalho nas últimas 168 horas devolve o `event_id` original com `duplicate: true` e não entrega nada de novo. **Entrega por webhook.** A Inovacc envia o envelope por POST à sua URL com `x-event-id`, `x-event-type`, `x-event-timestamp` e `x-event-signature: v1=`, um HMAC-SHA256 do carimbo de data e hora e do corpo bruto. Qualquer `2xx` em até 10 segundos é uma entrega; qualquer outra coisa é repetida após 10 segundos, com o atraso dobrando até 10 minutos, até que o limite de 5 tentativas seja atingido e o evento se torne uma mensagem morta. Redirecionamentos nunca são seguidos, e a sua URL deve ser HTTPS pública na porta 443. **Pull.** `POST /subscriptions/{id}/pull` com `max` (de 1 a 100, padrão 10) e `lease_seconds` (de 5 a 300, padrão 30) devolve as mensagens mais antigas, cada uma com o seu `delivery_count`. Uma mensagem obtida fica oculta durante o seu período de reserva; confirme-a com `POST .../ack` e os ids, ou ela volta quando a reserva termina. **Transmissão.** `GET /subscriptions/{id}/stream` faz o upgrade para um WebSocket com o subprotocolo `inovacc.v1`; um navegador passa a sua chave como um segundo subprotocolo, `bearer.`. Cada quadro é um envelope; responda `{"ack": [...]}` para confirmar. Um quadro não confirmado é enviado de novo após a sua reserva. **Monitoramento.** `GET /stats` devolve `published`, `completed`, `depth`, `oldest_pending_age_seconds`, `retries`, `retry_rate` e `dlq_inflow` do espaço de trabalho. Toda chamada é registrada no [Registro de atividade](/pt-br/products/activity/). O que é medido é o evento entregue. ## Primeiros passos Você precisa de uma chave secreta vinculada ao seu espaço de trabalho com as permissões de eventos ([Autenticação](/pt-br/guides/authentication/)). 1. **Crie uma assinatura pull.** `POST /v1/workspaces/{workspace}/subscriptions` com `{"types":["demo.*"],"delivery":{"mode":"pull"}}` (veja [os exemplos](#example)). A resposta é `201` com um `subscription_id`. 2. **Publique.** `POST .../events` com `{"event":{"type":"demo.hello","data":{"n":1}}}`. A resposta é `202` com uma entrada em `accepted` e o seu `event_id`. 3. **Faça o pull.** `POST .../subscriptions/{id}/pull` com `{}`. O seu evento está em `messages`, com `delivery_count` 1. 4. **Confirme.** `POST .../subscriptions/{id}/ack` com `{"ids":[""]}` responde `{"acked":1}`; um segundo pull vem vazio. 5. **Adicione um webhook.** Crie uma segunda assinatura com `{"mode":"webhook","url":"https://"}`, guarde o `signing_secret` que a resposta mostra uma única vez e siga o [guia de Webhooks](/pt-br/guides/webhooks/) para verificar as entregas. ## Casos de uso **Atendimento de pedidos.** O checkout publica `order.paid` com o id do pedido em `data` e o id do pagamento como `idempotency_key`. Uma assinatura por webhook para `order.*` chega ao sistema do depósito; uma assinatura pull alimenta a tarefa de faturamento. Um checkout repetido pelo cliente publica uma única vez. **Atualizações ao vivo em uma página.** Um painel abre uma transmissão em uma assinatura `websocket` para `ticket.*` com uma chave publicável a partir da sua própria origem, mostra cada novo chamado à medida que o quadro chega e o confirma. **Recuperação após uma queda.** O endpoint de um parceiro ficou fora do ar por uma hora. Suas entregas terminaram em mensagens mortas com `last_error` `webhook_timeout`. Quando ele volta, a sua equipe lista `GET /dead` e reenvia cada evento; ele vai apenas para as assinaturas que nunca o receberam. ## Limites e preços | Limite | Valor | |---|---| | Eventos por publicação | 100 | | Corpo da requisição | 5 MiB | | `data` por evento | 16 KiB (`basic`, `reliable`), 32 KiB (`advanced`) | | Janela de deduplicação de `idempotency_key` | 168 horas | | Assinaturas por espaço de trabalho; padrões por assinatura | 50; 20 | | Mensagens por pull; reserva | 100; 5 a 300 segundos | | Tempo de resposta do webhook | 10 segundos | | Novas tentativas | a partir de 10 segundos, dobrando até 10 minutos; limite 5, depois mensagem morta | | Mensagens mortas mantidas | 30 dias | | Quadro de transmissão vindo do cliente | 49.152 bytes | | Taxa | 600 chamadas por minuto por credencial, por localização | **Preços:** sob consulta. A unidade de preço é o **evento entregue**. ## Erros | Status | Código | O que significa e o que fazer | |---|---|---| | 400 | `invalid_body` | O corpo está malformado, ou nomeia `source` (ele vem da sua credencial). | | 400 | `invalid_query` | Apenas `GET /dead` aceita uma consulta (`limit`). | | 400 | `invalid_subscription`, `invalid_delivery`, `invalid_limit`, `invalid_id` | Corrija a assinatura, a entrega ou o parâmetro. | | 400 | `invalid_url`, `url_not_https`, `url_has_credentials`, `url_port_not_allowed`, `url_destination_blocked` | A URL do webhook deve ser HTTPS pública na porta 443, sem credenciais. | | 401 | `invalid_credentials` | Envie uma credencial válida. | | 403 | `forbidden`, `account_required` | Falta permissão ou o espaço de trabalho está errado; use uma chave de aplicação. | | 403 | `publishable_key_not_allowed`, `origin_not_allowed`, `secret_key_in_browser` | Uma chave publicável só pode transmitir, a partir de uma origem listada; mantenha as chaves secretas em servidores. | | 404 | `subscription_not_found`, `dead_event_not_found` | Não existe no seu espaço de trabalho. | | 409 | `wrong_delivery_mode`, `too_many_subscriptions`, `secret_not_managed` | A operação não se encaixa no modo de entrega, ou você está em 50 assinaturas. | | 413 | `payload_too_large` | O corpo excede 5 MiB. | | 426 | `upgrade_required` | A rota de transmissão exige um upgrade para WebSocket. | | 429 | `rate_limited`, `too_many_streams` | Diminua o ritmo; feche os sockets de que não precisa. | | 503 | `service_unavailable`, `events_disabled`, `signing_unavailable` | Tente novamente mais tarde; uma publicação repetida com as mesmas chaves reutiliza seus ids. | Um evento rejeitado dentro de um `202` traz o seu próprio código: `invalid_event`, `unknown_field`, `invalid_type`, `invalid_idempotency_key`, `payload_too_large` ou `data_required`. ## Boas práticas - **Envie uma `idempotency_key`** derivada do que aconteceu (o id do pagamento, a versão do registro), para que uma publicação repetida não seja um segundo evento. - **Deduplique por `event_id`** em todo receptor: a entrega é de pelo menos uma vez. - **Coloque ids em `data`, não objetos**: busque o estado atual em [Dados](/pt-br/products/data/) quando tratar o evento. - **Responda aos webhooks rapidamente** com um `2xx` e faça o trabalho depois; 10 segundos é o limite. - **Verifique a assinatura de todo webhook** antes de interpretar o corpo ([guia de Webhooks](/pt-br/guides/webhooks/)). - **Confirme as mensagens obtidas por pull** depois de processá-las, e escolha uma reserva maior que o seu tempo de processamento. - **Acompanhe `depth` e `dlq_inflow`** em `/stats`, e reenvie as mensagens mortas depois que a causa for corrigida. ## Relacionados - [Guia de Webhooks](/pt-br/guides/webhooks/): receba, verifique e reenvie entregas - [Dados](/pt-br/products/data/), [Registro de atividade](/pt-br/products/activity/) - [Autenticação](/pt-br/guides/authentication/), [Erros](/pt-br/guides/errors/), [Limites](/pt-br/guides/limits/) --- Guia: Autenticação URL: https://developer.inovacc.dev/pt-br/guides/authentication/ # Autenticação Toda chamada a uma API da Inovacc é autenticada por um único cabeçalho, `Authorization: Bearer `. A credencial identifica a sua organização e, no caso da credencial de uma aplicação, a aplicação também, então você nunca as nomeia na requisição. As chamadas que alteram algo na API de IA também levam um `X-Operation-Id`, que as torna seguras para repetir. Este guia explica as credenciais, os cabeçalhos que cada API lê, como funciona a idempotência e como manter as chaves seguras durante toda a sua vida. ## Os cabeçalhos | Cabeçalho | Onde | Valor | |---|---|---| | `Authorization` | toda chamada, toda API | `Bearer ` | | `X-Operation-Id` | API de IA (`ai.inovacc.dev`): todo `POST`, `PUT` e `DELETE`; opcional em `GET` | um id único que você escolhe: de 8 a 128 letras, dígitos, `_` ou `-` | Dados (`data.inovacc.dev`) e Eventos (`events.inovacc.dev`) não leem nenhum cabeçalho de organização ou de operação: o tenant vem apenas da credencial, e qualquer cabeçalho que tente nomear outro é ignorado. Dados usa versões HTTP (`If-Match`, `If-None-Match`) e Eventos usa uma `idempotency_key` no corpo para repetições seguras; veja as páginas dos produtos. Uma requisição sem credencial, com uma credencial malformada ou com uma que não é reconhecida é recusada antes de qualquer coisa ser executada: `401` com `missing_credentials` ou `invalid_credentials`. Em todas as APIs essa resposta é a mesma, quer o caminho chamado exista ou não, de modo que nada sobre a API pode ser descoberto sem uma credencial. ## Obter uma chave **As chaves secretas** são criadas no console da Inovacc por uma pessoa da sua organização e mostradas **uma única vez**: a Inovacc guarda apenas um hash, então uma chave perdida não pode ser exibida de novo, só substituída. O acesso é por convite atualmente: peça ao seu contato na Inovacc que convide você e depois crie uma chave na sua organização. ## Credenciais | Credencial | Aparência | Para | Aceita por | |---|---|---|---| | Chave de API secreta | `aik_` seguido de 64 caracteres hexadecimais | os seus servidores | IA, Dados, Eventos | | Token de acesso de cliente OAuth | um token assinado emitido para um cliente de uma aplicação | os seus servidores | IA, Dados, Eventos | | Chave publicável | `apb_...` | páginas web, a partir das origens que a sua aplicação lista | Dados (registros e arquivos, onde as regras permitem), Eventos (apenas transmissões) | | Token de acesso de usuário final | emitido quando uma pessoa se autentica na sua aplicação | o navegador ou aplicativo dessa pessoa | Dados (registros e arquivos, conforme as regras da coleção) | Uma chave pode ser **vinculada a uma aplicação**. Essa chave alcança apenas o que a aplicação habilitou: na API de IA cada rota exige uma capacidade (`ai.chat`, `ai.embeddings`, `knowledge`, `decision`), recusada com `403 capability_not_enabled` caso contrário; em Dados ela enxerga apenas os bancos de dados que a sua aplicação criou e a pasta de arquivos da sua aplicação; em Eventos ela só pode nomear o seu próprio espaço de trabalho. **As chaves publicáveis não são segredos.** Elas foram feitas para ir dentro de uma página web. O que protege os seus dados é a lista de origens permitidas e, acima de tudo, as regras de cada coleção: uma chave publicável não pode fazer nada que uma regra não admita. ## Idempotência Na API de IA, `X-Operation-Id` é uma chave de idempotência. A primeira resposta bem-sucedida a um id de operação é armazenada por 24 horas. Envie o mesmo id de novo e você recebe essa mesma resposta, marcada com `x-idempotent-replay: true`, sem que o trabalho seja executado duas vezes e sem uma segunda cobrança. É isso que torna segura uma nova tentativa após um tempo esgotado ou uma conexão interrompida. - Um **erro nunca é armazenado**: repetir uma chamada que falhou com o mesmo id a executa de novo. - Enquanto a primeira chamada **ainda está em execução**, uma segunda chamada com o mesmo id retorna `409 operation_in_progress`; aguarde e tente novamente. - Em chat, embeddings e run, um id reutilizado **devolve a resposta armazenada, qualquer que seja o novo corpo**. Em itens de coleção, o mesmo id com um arquivo diferente retorna `409 operation_id_reused`. - Gere um id novo para cada operação nova e reutilize um id apenas para repetir a chamada para a qual ele foi criado. Toda resposta de IA repete o id sob o qual foi executada em `x-operation-id`; em um `GET` sem um id, o serviço cria um. Uma resposta de chat transmitida nunca é armazenada, então não pode ser repetida. ## Exemplo ```sh export INOVACC_API_KEY="" ``` ```sample GET https://ai.inovacc.dev/v1/models ``` A resposta lista as rotas configuradas para a sua organização. As rotas são nomeadas por organização, então a lista que você vê é a sua. Uma chamada que altera algo acrescenta o seu id de operação: ```sh curl -X POST "https://ai.inovacc.dev/v1/chat/completions" \ -H "Authorization: Bearer $INOVACC_API_KEY" \ -H "Content-Type: application/json" \ -H "X-Operation-Id: $(uuidgen)" \ -d '{"model":"auto","messages":[{"role":"user","content":"Hello"}]}' ``` ## Ciclo de vida da chave Uma chave passa por quatro etapas, e cada uma tem os seus próprios cuidados. 1. **Criação.** Crie uma chave por aplicação e por ambiente (produção, homologação, o notebook de um desenvolvedor), nunca uma chave compartilhada por tudo. Copie a chave direto do console para o seu repositório de segredos. 2. **Uso.** Carregue a chave a partir do ambiente ou de um gerenciador de segredos na inicialização. Envie-a apenas no cabeçalho `Authorization`, apenas por HTTPS e apenas a partir de um servidor: uma chave secreta que chega à API de Dados ou de Eventos a partir de um navegador (com um cabeçalho `Origin`) é recusada com `403 secret_key_in_browser`. 3. **Rotação.** Crie uma segunda chave, implante-a em todos os lugares onde a primeira é usada, confirme no [Registro de atividade](/pt-br/products/activity/) que o id da chave antiga não aparece mais como `actor_id` e então desative a chave antiga. Uma chave desativada responde `403 key_disabled`; revogar a credencial de uma aplicação tem efeito em até um minuto. 4. **Aposentadoria.** Remova a chave de todo repositório de segredos e pipeline quando uma aplicação ou ambiente deixar de existir. Um comportamento para planejar: no Banco de Dados Vetorial, o escopo `local` pertence à chave que o escreveu. Uma chave nova enxerga um escopo `local` novo e vazio; use o escopo `shared` para o conhecimento que precisa sobreviver a uma rotação. Os tokens de acesso OAuth expiram. Quando uma chamada responde `401 invalid_credentials` com um token que antes funcionava, obtenha um novo token e tente novamente uma vez; não repita um `401` em um laço. ## Higiene das chaves - **Nunca faça commit de uma chave**, nem mesmo em um repositório privado ou em um arquivo de teste. Mantenha os arquivos `.env` fora do controle de versão. - **Nunca registre em log o cabeçalho `Authorization`** e oculte-o dos relatórios de erro e dos traces. - **Dê a cada integração a sua própria chave**, para que o tráfego dela seja visível no Registro de atividade e ela possa ser rotacionada isoladamente. - **Prefira uma chave vinculada a uma aplicação** com apenas as capacidades de que precisa a uma chave de toda a organização. - **Rotacione em um calendário** e imediatamente quando alguém que tinha acesso sair ou uma chave puder ter vazado. - **Em um navegador, use uma chave publicável ou o token de uma pessoa autenticada** e feche toda coleção com regras. ## Veja também - [Erros](/pt-br/guides/errors/): o envelope de erro e os códigos que você pode tratar. - [Limites](/pt-br/guides/limits/): tamanhos de requisição, tempos limite e taxas. - [Webhooks](/pt-br/guides/webhooks/): verificação de entregas com um segredo de assinatura. - [Referência da API](/pt-br/reference/): cada produto e seus endpoints. --- Guia: Erros URL: https://developer.inovacc.dev/pt-br/guides/errors/ # Erros Quando uma API da Inovacc recusa ou não consegue concluir uma chamada, ela responde com um status HTTP e um envelope de erro em JSON. Este guia descreve o envelope, os tipos de erro, os códigos que todas as APIs compartilham e o que fazer para cada status: corrigir a requisição, esperar ou tentar novamente. ## O envelope ```json { "error": { "message": "Human-readable explanation", "type": "validation_error", "code": "invalid_body" } } ``` - **`code`** é aquilo em que o seu programa deve se basear para ramificar. Os códigos fazem parte do contrato de cada API: dentro de um caminho de versão como `/v1`, novos códigos podem ser acrescentados, e um código existente mantém o seu significado. - **`type`** agrupa os códigos em famílias, úteis para registro em log e tratamento amplo. - **`message`** é uma frase fixa em inglês para pessoas. Ela nunca repete um valor da sua requisição (no máximo o nome de um campo recusado) e nunca descreve o que falhou dentro da Inovacc. Não a interprete programaticamente. Algumas respostas acrescentam um campo ao envelope: um arquivo recusado traz `reason` (por exemplo `executable` ou `password_protected`), e uma conversão de esquema que não se encaixa traz `failing_documents`, uma contagem. Ignore os campos que você não conhece. Duas respostas não usam o envelope. Na API de IA, um caminho que não existe responde `404 {"error":"not_found"}`. Um WebSocket (uma transmissão de Eventos ou um ouvinte de Dados) recusado antes do upgrade responde com um erro HTTP comum; depois de aberto, ele termina com um código de fechamento. ## Tipos | `type` | Significa | Status típico | |---|---|---| | `validation_error` | A requisição está malformada: um cabeçalho, um campo ou um valor viola as regras. | 400 | | `invalid_request_error` | A requisição está bem formada, mas não pode ser atendida como foi enviada: grande demais, um tipo de arquivo não suportado, uma URL que não pode ser buscada. | 400, 413, 415, 422 | | `authentication_error` | Nenhuma credencial, ou uma que não é válida. | 401 | | `authorization_error`, `permission_error`, `forbidden` | A credencial é válida, mas não pode fazer isto. | 403 | | `not_found_error`, `not_found` | A coisa não existe, ou você não pode saber que ela existe. | 404, 410 | | `conflict_error`, `conflict` | A requisição entra em conflito com o estado atual: uma versão, um modo, um limite de uma coleção. | 409 | | `idempotency_error` | Um id de operação está em uso ou foi usado para outra coisa. | 409 | | `rate_limit_error`, `rate_limited` | Chamadas demais, ou uma cota ou orçamento foi consumido. | 429 | | `api_error`, `service_error`, `service_unavailable`, `internal_error` | Algo do lado da Inovacc, ou uma fonte que ela chamou por você, falhou. | 500, 502, 503, 504 | As APIs de Dados, de IA e de Eventos usam as famílias acima; a string exata de `type` pode diferir entre APIs para a mesma família, então trate o `code` e use o status HTTP como alternativa. ## Códigos que toda API compartilha | Status | Código | Significado | O que fazer | |---|---|---|---| | 401 | `missing_credentials`, `invalid_credentials` | Nenhuma chave, ou uma chave que não é válida, expirou ou foi revogada. | Corrija a credencial; não tente de novo sem alterá-la. | | 403 | `forbidden`, `route_forbidden`, `key_disabled`, `capability_not_enabled` | A credencial não pode fazer isto. | Peça a permissão, a rota ou a capacidade. | | 403 | `origin_not_allowed`, `secret_key_in_browser` | Uma chamada de navegador a partir de uma origem não listada, ou uma chave secreta em um navegador. | Liste a origem; use uma chave publicável. | | 400 | `missing_operation_id`, `invalid_operation_id` | IA: um `POST`, `PUT` ou `DELETE` sem um `X-Operation-Id` válido. | Envie de 8 a 128 letras, dígitos, `_` ou `-`. | | 400 | `invalid_body`, `unsupported_field`, `invalid_field` | O corpo ou um parâmetro não é válido para este endpoint. | Corrija a requisição. | | 404 | `*_not_found` | Não existe, ou não é seu. | Confira o id. | | 409 | `operation_in_progress` | O mesmo id de operação ainda está em execução. | Aguarde e tente novamente com o mesmo id. | | 409 | `operation_id_reused` | IA: um id de operação já usado para outro arquivo em uma coleção. | Use um novo id de operação para uma nova operação. | | 409 | `version_conflict` | Dados: o registro mudou desde que você o leu. | Leia de novo e tente novamente. | | 413 | `request_too_large`, `payload_too_large` | O corpo excede o limite de tamanho. | Reduza-o ou envie em partes. | | 429 | `rate_limited` | Requisições demais na janela. | Aguarde `Retry-After` segundos, quando informado. | | 429 | `quota_exceeded`, `concurrency_limited` | IA: uma cota de tokens, de custo ou de simultaneidade se esgotou. | Diminua o ritmo; peça à Inovacc para aumentar a cota. | | 429 | `budget_exhausted` | IA: um orçamento diário foi consumido. | Aguarde até 00:00 UTC (`Retry-After`). | | 502 | `upstream_error` | Uma fonte chamada por você falhou. | Tente novamente com espera crescente. | | 503 | `service_unavailable` | Uma dependência não pôde ser alcançada; nada foi feito nem presumido. | Tente novamente com espera crescente. | | 504 | `timeout_error` | IA: o modelo não começou a responder a tempo. | Tente novamente com espera crescente. | Cada página de produto lista todos os códigos que ele pode devolver, com o que fazer. ## Política de novas tentativas | Status | Tentar de novo? | Como | |---|---|---| | 400, 401, 403, 404, 410, 413, 415, 422 | Não | A mesma requisição falhará da mesma forma. Corrija-a primeiro. | | 409 `operation_in_progress` | Sim | Após uma curta espera, com o **mesmo** id de operação. | | 409 `version_conflict` | Sim, após reler | Leia o registro, aplique a sua alteração à nova versão, envie o `If-Match` dela. | | 409, outros códigos | Não | O estado precisa mudar primeiro (crie o banco de dados, aguarde os itens, esvazie a pasta). | | 429 com `Retry-After` | Sim | Não antes do número de segundos informado. | | 429 sem `Retry-After` | Mais tarde | Uma cota se esgotou: espere minutos, não segundos, ou aumente-a. | | 500, 502, 503, 504 | Sim | Com espera exponencial e jitter (por exemplo 1, 2, 4, 8 segundos), no máximo algumas vezes. | | Erro de rede, sem resposta | Sim | Como para 503. | **Repita com segurança.** Na API de IA, repita uma chamada que altera algo com o **mesmo** `X-Operation-Id`: se a primeira tentativa teve sucesso, você recebe a resposta armazenada em vez de uma segunda execução. Em Dados, repita uma criação com o seu próprio id de registro ou `If-None-Match: *`, e uma atualização com o mesmo `If-Match`. Em Eventos, repita uma publicação com a mesma `idempotency_key`: o `event_id` original volta com `duplicate: true`. ## Veja também - [Autenticação](/pt-br/guides/authentication/): credenciais e idempotência. - [Limites](/pt-br/guides/limits/): os tamanhos e taxas por trás de `413` e `429`. - [Webhooks](/pt-br/guides/webhooks/): como as entregas que falharam são repetidas. --- Guia: Limites URL: https://developer.inovacc.dev/pt-br/guides/limits/ # Limites Toda API da Inovacc limita o tamanho do que você envia, quanto tempo uma chamada pode levar e com que frequência você pode chamar. Este guia lista esses limites por API e diz o que acontece quando você atinge cada um, para que o seu código possa ficar abaixo deles ou tratar a recusa. Os valores marcados como "por organização" são definidos para a sua organização pela Inovacc; os demais são fixos. ## Como os limites respondem | Você atinge | Resposta | O que fazer | |---|---|---| | Um limite de tamanho (corpo, arquivo, registro, item) | `413` (`request_too_large`, `payload_too_large`, `url_too_large`), ou `400` para um campo ou documento grande demais | Envie menos, ou use o envio em partes | | Um limite de quantidade (documentos por chamada, operações por lote, itens por coleção) | `400 invalid_body`, `400 batch_too_large` ou `409 collection_full` | Divida a chamada; inicie uma nova coleção | | Um limite de taxa | `429 rate_limited`, com `Retry-After` na API de IA | Aguarde e tente novamente | | Uma cota de tokens, de custo ou de simultaneidade (IA) | `429 quota_exceeded` ou `429 concurrency_limited`, sem `Retry-After` | Diminua o ritmo por minutos, ou aumente a cota | | Um orçamento diário (IA) | `429 budget_exhausted`, `Retry-After` até 00:00 UTC | Aguarde o próximo dia UTC | | Um limite de entrada por requisição (IA) | `400 input_too_large` | Encurte a entrada | Uma chamada recusada em um limite é recusada antes de o seu trabalho começar: nada é chamado em seu nome e nada é gravado. ## IA | Limite | Valor | |---|---| | Corpo da requisição (chat, embeddings, run) | 1 MiB por padrão; por organização, de 1 KiB a 20 MiB | | Tokens de entrada por requisição | por organização (`400 input_too_large`) | | Tokens de saída por requisição | o menor entre o teto da rota e o da sua organização; um `max_tokens` maior é reduzido, não recusado | | Tempo até o modelo começar a responder | 60 segundos (`504 timeout_error`); não em `/v1/run` | | Imagens em uma requisição de chat | 20 | | Custo de entrada estimado de uma imagem | 1.600 tokens | | Resposta armazenada para uma repetição idempotente | 24 horas | | Uma chamada mantida como em andamento | 5 minutos | | Banco de Dados Vetorial: documentos por ingestão, ids por exclusão | 100 | | Banco de Dados Vetorial: um documento (`id` + `text` + `metadata`) | 10 KiB | | Banco de Dados Vetorial: corpo da requisição | 1 MiB | | Consulta vetorial: texto; `top_k` | 8.000 caracteres; 50 | | Item de coleção no corpo de uma requisição, ou por URL | 16 MiB | | Coleção | 100 itens; 1 GiB de arquivos enviados em requisições; 20 GiB de vídeo por envio | | Parte de um envio | 64 MiB, todas as partes exceto a última | | Envio que não é vídeo (transcrição, notas) | 16 MiB | | Envio de gravação | por organização | | Resultado de um trabalho de conhecimento | mantido por 24 horas | | Leituras de atividade e de uso | até 366 dias e 92 dias por chamada | **Cotas por organização.** Cada uma delas é definida para a sua organização, e é ilimitada quando não definida: | Cota | Janela | Quando atingida | |---|---|---| | Requisições | por minuto de relógio UTC, por dia UTC | `429 rate_limited`, `Retry-After` até o próximo minuto ou dia | | Tokens | por dia UTC, por mês UTC | `429 quota_exceeded` | | Custo | por dia UTC, por mês UTC | `429 quota_exceeded` | | Chamadas simultâneas | a qualquer momento | `429 concurrency_limited` | | Orçamento diário, por provedor e opcionalmente por aplicação | por dia UTC | `429 budget_exhausted`, `Retry-After` até 00:00 UTC | Uma requisição conta contra os limites de requisições por minuto e por dia assim que é admitida, mesmo que falhe depois. Os limites de tokens e de custo permitem uma chamada que atinja exatamente o limite. A partir do nível de alerta de um orçamento (80% por padrão), as respostas trazem `X-Budget-Warning` antes de as chamadas começarem a ser recusadas. ## Dados e Arquivos | Limite | Valor | |---|---| | Corpo da requisição JSON | 1 MiB (`413 payload_too_large`) | | Um registro | 900 KiB (`400 record_too_large`) | | Um campo `json` | 64 KiB | | Campos por coleção; coleções por banco de dados | 64; 64 | | Registros por página | 200 (padrão 50) | | Operações por lote | 100, uma transação | | Filtro | 2.048 caracteres, 40 valores, profundidade de aninhamento 8 | | Query string | 16 KiB (`400 invalid_query`) | | Arquivo ou blob em uma requisição | 100 MiB, com `Content-Length` (`411` sem ele) | | Arquivo ou blob em partes | 5 GiB; partes de 5 MiB a 100 MiB, numeradas de 1 a 10.000 | | Caminho do arquivo; prefixo de listagem; metadados do arquivo | 1.024 bytes; 256 bytes; 2 KiB | | Ouvintes em tempo real por coleção; um evento | 1.000; 512 KiB | | Página do Registro de atividade | 1 a 500 (padrão 100) | | Taxa | 600 requisições por minuto por titular de credencial, por localização (`429 rate_limited`) | O limite de taxa é contado por localização e é um freio, não uma contagem exata. ## Eventos | Limite | Valor | |---|---| | Corpo da requisição | 5 MiB (`413 payload_too_large`) | | Eventos por publicação | 100 | | `data` por evento | 16 KiB (`basic`, `reliable`), 32 KiB (`advanced`) | | Janela de deduplicação de uma `idempotency_key` | 168 horas | | Assinaturas por espaço de trabalho; padrões por assinatura | 50; 20 | | Mensagens por pull; reserva do pull | 100; 5 a 300 segundos | | Tempo de resposta do webhook | 10 segundos | | Novas tentativas do webhook | a partir de 10 segundos, dobrando até 10 minutos; limite 5 | | Mensagens mortas mantidas | 30 dias | | Taxa | 600 chamadas por minuto por credencial, por localização (`429 rate_limited`) | ## Como ficar abaixo dos limites - **Agrupe**: envie até 100 documentos, operações ou eventos por chamada em vez de um de cada vez. - **Envie arquivos grandes em partes** em vez de aumentar o tamanho dos corpos. - **Espere em `429`**: respeite `Retry-After` e adicione jitter para que muitos clientes não tentem novamente no mesmo instante. - **Defina `max_tokens`** nas chamadas de chat: isso reduz o que cada chamada reserva contra as suas cotas. - **Observe `X-Budget-Warning`** e o resumo de uso de IA para ver uma cota se aproximando antes de ela se esgotar. ## Veja também - [Erros](/pt-br/guides/errors/): todos os códigos e a política de novas tentativas. - [Autenticação](/pt-br/guides/authentication/): credenciais e idempotência. - Cada página de produto lista os seus próprios limites por completo. --- Guia: Webhooks URL: https://developer.inovacc.dev/pt-br/guides/webhooks/ # Webhooks Um webhook é a forma como [Eventos](/pt-br/products/events/) entrega a um servidor que você opera: todo evento que corresponde a uma assinatura chega ao seu endpoint HTTPS como um `POST` assinado. Este guia cobre a criação de uma assinatura de webhook, a requisição que o seu endpoint recebe, a verificação da assinatura, como funcionam as novas tentativas e as mensagens mortas, e a rotação do segredo de assinatura sem perder nenhuma entrega. ## O que é uma assinatura de webhook Uma assinatura diz quais eventos um receptor quer e como eles chegam até ele. Uma **assinatura de webhook** tem uma lista de padrões de tipo e um bloco de entrega com `"mode": "webhook"` e a sua `url`. A partir daí, cada evento publicado no espaço de trabalho cujo `type` corresponda a um dos padrões é enviado por POST a essa URL, uma vez por assinatura. A entrega é **de pelo menos uma vez**. Em operação normal cada evento chega uma vez; uma nova tentativa, uma resposta lenta ou uma conexão perdida pode fazê-lo chegar de novo. O seu receptor deve, portanto, ser construído para aceitar uma duplicata sem consequências, usando o id do evento como chave. A URL deve ser `https`, na porta 443, sem nome de usuário ou senha, sem fragmento e com um host público: nomes privados, de loopback, de link local e de uso local são recusados quando a assinatura é criada e verificados de novo a cada entrega. Redirecionamentos nunca são seguidos. ## Crie uma Chame `POST https://events.inovacc.dev/v1/workspaces/{workspace}/subscriptions` com uma chave secreta que tenha a permissão de escrita de assinaturas: ```json {"types": ["order.*"], "delivery": {"mode": "webhook", "url": "https://hooks.example.com/inovacc"}} ``` A resposta é `201`: ```json {"subscription_id": "sub_...", "types": ["order.*"], "delivery": {"mode": "webhook", "url": "https://hooks.example.com/inovacc", "secret_ref": "managed"}, "created_at": "2026-10-06T12:00:00.000Z", "signing_secret": "whsec_..."} ``` `signing_secret` é a chave que o seu endpoint usa para verificar as entregas. **Ele é mostrado uma única vez, nesta resposta, e nunca mais**: as listagens mostram `"secret_ref": "managed"` e nada mais. Guarde-o imediatamente no seu gerenciador de segredos. Se for perdido, rotacione-o (abaixo). Um espaço de trabalho comporta no máximo 50 assinaturas, cada uma com 1 a 20 padrões. ## A requisição de entrega Cada entrega é: ```http POST https://hooks.example.com/inovacc content-type: application/json x-event-id: evt_01K... x-event-type: order.paid x-event-timestamp: 1791201600 x-event-signature: v1=<64 lowercase hex characters> {"event_id":"evt_01K...","type":"order.paid", ... } ``` `x-event-timestamp` é o horário Unix, em segundos, em que a entrega foi assinada. Durante uma rotação de segredo, `x-event-signature` traz uma entrada por segredo ativo, a mais nova primeiro, separadas por vírgulas: `v1=,v1=`. Responda com qualquer status `2xx` para confirmar a entrega. Qualquer outra coisa (um `4xx`, um `5xx`, nenhuma resposta em 10 segundos, um erro de rede) é uma tentativa que falhou e será repetida. ## O envelope do evento O corpo é o envelope do evento, exatamente como os assinantes de todos os modos o recebem: | Campo | Significado | |---|---| | `event_id` | `evt_` seguido de 26 caracteres, atribuído pela Inovacc quando o evento foi publicado. Único por evento. | | `type` | O tipo do evento, como `order.paid`: palavras minúsculas separadas por pontos, até 128 bytes. | | `source` | A aplicação que publicou o evento, obtida da sua credencial. | | `time` | Quando foi publicado, RFC 3339 UTC com milissegundos. | | `tenant` | A organização, a conta, o espaço de trabalho e, quando conhecida, a aplicação a que o evento pertence. | | `idempotency_key` | A chave do publicador; quando ele não enviou nenhuma, o `event_id`. | | `data` | A carga JSON do publicador: o que aconteceu, normalmente ids em vez de objetos inteiros. | Leia apenas os campos de que precisa e ignore os campos que você não conhece. ## Verifique a assinatura Verifique cada entrega **antes** de interpretá-la ou agir sobre ela: 1. Leia `x-event-timestamp` e os **bytes brutos do corpo**, exatamente como recebidos, antes de qualquer interpretação de JSON. 2. Calcule `HMAC-SHA256(secret, timestamp + "." + body)`, em que `secret` é a string `whsec_...` inteira em UTF-8, e escreva o resultado em hexadecimal minúsculo. 3. Divida `x-event-signature` pelas vírgulas e aceite a entrega quando **qualquer** entrada `v1=` for igual ao seu valor, comparando em tempo constante. 4. Rejeite um carimbo de data e hora a mais de cinco minutos do seu relógio, para que uma entrega antiga não possa ser reenviada contra você. **Exemplo prático.** Com o segredo `example-key-0001`, o carimbo `1791201600` e o corpo `{"hello":"world"}`, o texto assinado é `1791201600.{"hello":"world"}` e a assinatura são os 64 caracteres hexadecimais abaixo, impressos aqui em duas metades que você junta sem espaço: ```text 05080ab29a6abfb44033966c7837c2a1 889fbf1a909f9cbd12b9dd5d12bb2bf5 ``` de modo que o cabeçalho fica `v1=` seguido das duas metades. Execute o seu verificador neste exemplo antes de implantá-lo. **TypeScript** (Node.js 18 ou posterior): ```ts import { createHmac, timingSafeEqual } from "node:crypto"; export function verifyInovaccWebhook( secret: string, timestamp: string, signatureHeader: string, rawBody: Buffer, nowSeconds: number = Math.floor(Date.now() / 1000), ): boolean { const ts = Number(timestamp); if (!Number.isInteger(ts) || Math.abs(nowSeconds - ts) > 300) return false; const expected = createHmac("sha256", secret) .update(`${timestamp}.`) .update(rawBody) .digest(); return signatureHeader.split(",").some((entry) => { const part = entry.trim(); if (!part.startsWith("v1=")) return false; const given = Buffer.from(part.slice(3), "hex"); return given.length === expected.length && timingSafeEqual(given, expected); }); } ``` **Python** (3.10 ou posterior): ```python import hashlib import hmac import time def verify_inovacc_webhook(secret: str, timestamp: str, signature_header: str, raw_body: bytes, now: int | None = None) -> bool: try: ts = int(timestamp) except ValueError: return False now = int(time.time()) if now is None else now if abs(now - ts) > 300: return False expected = hmac.new(secret.encode(), timestamp.encode() + b"." + raw_body, hashlib.sha256).hexdigest() return any( part.strip().startswith("v1=") and hmac.compare_digest(part.strip()[3:], expected) for part in signature_header.split(",") ) ``` Ambas as funções recebem o corpo bruto: configure o seu framework web para entregar os bytes, e não um objeto interpretado, nesta rota. ## Novas tentativas e tempos limite O seu endpoint tem **10 segundos** para responder. Uma tentativa que falhou é repetida após 10 segundos, e o atraso dobra a cada nova falha até 10 minutos. Quando o limite de 5 tentativas é atingido, o evento vai para as mensagens mortas do seu espaço de trabalho. Uma falha afeta apenas a entrega que falhou: os outros eventos, e as outras assinaturas do mesmo evento, continuam fluindo. Como uma entrega pode ser repetida, um `2xx` que chega depois de o seu endpoint já ter processado o evento é inofensivo, desde que você deduplique por `x-event-id`. ## Rotacione o segredo `POST /v1/workspaces/{workspace}/subscriptions/{id}/rotate-secret` devolve um novo segredo, uma única vez: ```json {"subscription_id": "sub_...", "signing_secret": "whsec_...", "previous_valid_until": "2026-10-07T12:00:00.000Z"} ``` Até `previous_valid_until` (24 horas por padrão), **ambos os segredos assinam**: cada entrega traz `v1=,v1=`. Implante o novo segredo no seu receptor dentro dessa janela; como o verificador aceita qualquer entrada correspondente, nada é perdido durante a troca. Rotacionar de novo dentro da janela mantém todos os segredos não expirados. A rotação se aplica apenas a assinaturas de webhook (`409 wrong_delivery_mode` caso contrário). ## Mensagens mortas e reenvio `GET /v1/workspaces/{workspace}/dead?limit=50` lista as mensagens mortas, da mais nova para a mais antiga, com o evento, `attempts`, `dead_at`, `replay_count` e `last_error`: | `last_error` | Significado | |---|---| | `webhook_status_` | O seu endpoint respondeu esse status, por exemplo `webhook_status_500`. | | `webhook_timeout` | Nenhuma resposta em 10 segundos. | | `webhook_network` | A conexão falhou. | | `url_destination_blocked` | A URL agora aponta para um lugar aonde as entregas não podem ir. | | `secret_missing` | O segredo de assinatura da assinatura não pôde ser usado. | Corrija a causa e depois faça `POST /v1/workspaces/{workspace}/dead/{event_id}/replay`. A resposta é `202`, e o mesmo envelope, com o mesmo `event_id`, é entregue de novo às assinaturas que nunca o receberam. As mensagens mortas são mantidas por 30 dias. ## Boas práticas - **Verifique antes de interpretar**: calcule a assinatura sobre os bytes brutos e só depois interprete. - **Torne o receptor idempotente**: guarde cada `x-event-id` processado e responda `2xx` imediatamente para um que você já viu. - **Responda rápido**: confirme com um `2xx` e faça o trabalho lento depois, a partir de uma tarefa sua. - **Rejeite carimbos de data e hora obsoletos** (a mais de cinco minutos de diferença) e mantenha o relógio do seu servidor sincronizado. - **Mantenha o segredo em um gerenciador de segredos** e rotacione-o quando alguém que o conhecia sair, ou em um calendário. - **Monitore as mensagens mortas** e `dlq_inflow` em `GET /stats`; reenvie quando o endpoint estiver saudável. - **Devolva `2xx` apenas quando tiver o evento em segurança**: um `2xx` encerra as novas tentativas. ## Veja também - [Eventos](/pt-br/products/events/): publicação, assinaturas, pull e transmissão - [Erros](/pt-br/guides/errors/), [Autenticação](/pt-br/guides/authentication/), [Limites](/pt-br/guides/limits/) --- Guia: Inovacc MCP URL: https://developer.inovacc.dev/pt-br/guides/connect-your-ai-agent/ # Inovacc MCP O [Model Context Protocol](https://modelcontextprotocol.io) (MCP) é um padrão aberto que permite a assistentes de IA chamar ferramentas expostas por um servidor. O servidor MCP da Inovacc é um programa, `inovacc mcp serve`, que roda na sua máquina com esta documentação embutida, para que seu assistente consulte produtos, endpoints e guias da Inovacc e responda com as fontes. Funciona com qualquer cliente compatível com MCP, incluindo Cursor, Claude Code, VS Code (GitHub Copilot), Windsurf, Cline, Claude Desktop, IDEs JetBrains, Codex CLI e Gemini CLI. Para deixar o seu agente fazer toda a configuração sozinho, dê a ele esta linha (em inglês, como o texto que ele busca): ```text Fetch and execute the appropriate instructions to set me up for Inovacc from https://developer.inovacc.dev/agent-setup/prompt.md ``` ## Capacidades Com o servidor conectado, seu assistente pode: - buscar na documentação: seções de contrato, produtos, guias e quickstarts - explorar endpoints: a seção do contrato para qualquer método e caminho, como `POST /v1/vector/query` - obter o quickstart de um produto: URL base, cabeçalhos e um esqueleto de curl - informar de qual versão da documentação está respondendo Ele não executa requisições e não toca na sua conta. O servidor é somente leitura, não exige chave de API e responde a partir da documentação embutida no programa. ## Pré-requisitos - Windows x86_64. macOS e Linux estão a caminho; ainda não há data. - Um cliente compatível com MCP, da lista abaixo. - Os arquivos de release do programa `inovacc`. O repositório é privado até o lançamento: baixe a versão que seu contato da Inovacc compartilhar com você. ## Instale a CLI inovacc 1. Baixe `inovacc-windows-x86_64.exe` e `inovacc-windows-x86_64.exe.sha256` da release. 2. Confira o download no PowerShell. Os dois valores devem ser idênticos: ```powershell (Get-FileHash .\inovacc-windows-x86_64.exe -Algorithm SHA256).Hash.ToLower() Get-Content .\inovacc-windows-x86_64.exe.sha256 ``` 3. Renomeie o arquivo para `inovacc.exe` e coloque-o em uma pasta do `PATH`. 4. Abra um terminal novo e verifique: ```powershell inovacc docs version ``` A saída tem este formato; os números de versão mudam a cada release: ```text embedded 2026.10.09-0 installed none active embedded 2026.10.09-0 previous none published unknown; run `inovacc docs update --check` data dir C:\Users\\AppData\Local\Inovacc\knowledge ``` ## Conecte seu editor ou aplicativo de chat Todo cliente precisa dos mesmos três dados: o transporte é stdio, o comando é `inovacc` e os argumentos são `mcp` e `serve`. Reinicie o cliente depois de mudar a configuração. ### Cursor Crie `.cursor/mcp.json` em um projeto, ou `~/.cursor/mcp.json` para todos os projetos: ```json { "mcpServers": { "inovacc": { "command": "inovacc", "args": ["mcp", "serve"] } } } ``` ### Claude Code ```sh claude mcp add inovacc -- inovacc mcp serve ``` O `--` separa as opções do próprio Claude do comando que executa o servidor. Por padrão o servidor é adicionado no escopo `local`: disponível só para você, no projeto atual. Escolha outro escopo com `-s` antes do nome: ```sh claude mcp add -s project inovacc -- inovacc mcp serve claude mcp add -s user inovacc -- inovacc mcp serve ``` `project` grava `.mcp.json` na raiz do projeto, compartilhado com quem usa o repositório. `user` deixa o servidor disponível em todos os seus projetos. ### VS Code (GitHub Copilot) Crie `.vscode/mcp.json` em um workspace, ou execute **MCP: Open User Configuration** para o seu perfil de usuário: ```json { "servers": { "inovacc": { "type": "stdio", "command": "inovacc", "args": ["mcp", "serve"] } } } ``` **Importante:** `.vscode/mcp.json` usa `servers`, não `mcpServers`. A documentação do próprio VS Code define `"type": "stdio"` nos exemplos stdio, e esta página faz o mesmo. Um `.mcp.json` na raiz do projeto usa `mcpServers`, como os outros clientes. ### Windsurf A documentação do Windsurf agora fica junto com a do Devin Desktop. Adicione o servidor ao `mcp_config.json`, em `%APPDATA%\devin\mcp_config.json` no Windows: ```json { "mcpServers": { "inovacc": { "command": "inovacc", "args": ["mcp", "serve"] } } } ``` ### Cline No painel do Cline, clique no ícone MCP Servers na barra superior, abra a aba Configure e clique em **Configure MCP Servers**. Adicione o servidor ao arquivo de configurações que abrir (`cline_mcp_settings.json`): ```json { "mcpServers": { "inovacc": { "command": "inovacc", "args": ["mcp", "serve"] } } } ``` ### Claude Desktop Abra o menu Claude, depois **Settings**, a aba **Developer** e **Edit Config**. No Windows o arquivo é `%APPDATA%\Claude\claude_desktop_config.json`: ```json { "mcpServers": { "inovacc": { "command": "inovacc", "args": ["mcp", "serve"] } } } ``` Feche o Claude Desktop por completo e abra de novo. Se o aplicativo não achar o `inovacc`, use o caminho completo de `inovacc.exe` como comando, com cada barra invertida dobrada no JSON. ### IDEs JetBrains Abra **Settings | Tools | AI Assistant | Model Context Protocol (MCP)**, clique em **Add**, escolha o tipo de conexão **STDIO** e informe: ```json { "mcpServers": { "inovacc": { "command": "inovacc", "args": ["mcp", "serve"] } } } ``` Clique em **OK** e depois em **Apply**. ### Codex CLI ```sh codex mcp add inovacc -- inovacc mcp serve ``` ou escreva em `~/.codex/config.toml` (um projeto confiável pode usar `.codex/config.toml`): ```toml [mcp_servers.inovacc] command = "inovacc" args = ["mcp", "serve"] ``` **Importante:** o Codex usa TOML e `mcp_servers`, não JSON e `mcpServers`. ### Gemini CLI ```sh gemini mcp add inovacc inovacc mcp serve ``` ou adicione o servidor a `~/.gemini/settings.json` (um projeto pode usar `.gemini/settings.json`): ```json { "mcpServers": { "inovacc": { "command": "inovacc", "args": ["mcp", "serve"] } } } ``` ### Outro cliente Use o transporte stdio com o comando `inovacc` e os argumentos `mcp` e `serve`. Veja na documentação de MCP do seu cliente onde isso entra. ## Verifique sua configuração Pergunte ao seu assistente: "What does POST /v1/vector/query take?" Uma configuração correta responde a partir do contrato e cita o documento de origem e a versão do conhecimento. Sem assistente, busque pelo terminal: ```sh inovacc docs search "vector query" ``` Cada resultado mostra o id do documento, o título e a citação (repositório, caminho e commit de origem). ## Solução de problemas - **`inovacc` não é encontrado.** A pasta com `inovacc.exe` não está no `PATH`, ou o terminal foi aberto antes da mudança. Abra um terminal novo. Na configuração do cliente, você pode dar o caminho completo de `inovacc.exe` como comando. - **O cliente não lista o servidor.** Reinicie o cliente por completo e confira se o comando da configuração roda em um terminal: `inovacc mcp serve` deve ficar esperando em silêncio (Ctrl+C para sair). - **As respostas parecem antigas.** Rode `inovacc docs version` para ver o que está em uso e o que está publicado, depois `inovacc docs update`. - **O Windows SmartScreen avisa na primeira execução.** Hoje o programa não tem assinatura de código, então o Windows pode mostrar "O Windows protegeu seu PC". Confira o checksum, como descrito acima, antes de decidir executá-lo. ## Ferramentas MCP disponíveis | Ferramenta | O que faz | |---|---| | `search_documentation` | Busca em texto completo em seções de contrato, capacidades, quickstarts e guias | | `get_document` | Um documento completo, pelo id, com a sua proveniência | | `get_api_reference` | A seção do contrato para um endpoint, como `POST /v1/vector/query` | | `list_products` | Os produtos e capacidades com documentação, e quantos documentos cada um tem | | `get_quickstart` | URL base, endpoints, escopos, os cabeçalhos de toda chamada e um esqueleto de curl | | `get_knowledge_version` | Qual pacote de documentação está respondendo: versão, data de build, commits fixados e número de documentos | ## Mantenha a documentação atualizada O programa traz a documentação com a qual foi construído e pode instalar documentação mais nova e assinada sem um programa novo. ```sh inovacc docs version # versões embutida, instalada, ativa, anterior e publicada inovacc docs update # baixa, verifica e instala a documentação publicada mais nova inovacc docs update --check inovacc docs rollback # volta à documentação instalada anterior ``` - A documentação é publicada em pacotes assinados. Um pacote só é instalado se o tamanho, o SHA-256 e a assinatura Ed25519 conferirem, e um pacote que não seja mais novo do que o em uso é recusado, então não é possível forçar um downgrade. - A verificação automática roda no máximo a cada 24 horas, nunca atrasa uma resposta, não instala nada e, no máximo, imprime uma linha avisando que existe versão mais nova. - Até o lançamento, as atualizações chegam pela versão que seu contato da Inovacc compartilhar com você. ## Referência de configuração | Configuração | O que faz | |---|---| | `INOVACC_KNOWLEDGE_DIR` | A pasta onde a documentação instalada é guardada. Padrão no Windows: `%LOCALAPPDATA%\Inovacc\knowledge` | | `INOVACC_NO_UPDATE_CHECK` | Defina como `1` para desligar a verificação automática de documentação mais nova. A opção `--no-update-check` faz o mesmo em uma execução | | `INOVACC_UPDATE_URL` | O endereço do `latest.json` de onde as atualizações são lidas; precisa ser HTTPS | ## Perguntas frequentes **Preciso de uma chave de API?** Não. O servidor só lê documentação e nunca usa a sua conta. **Ele envia minhas perguntas para algum lugar?** Não. As perguntas são respondidas na sua máquina. O único uso de rede é a verificação automática de documentação mais nova, no máximo uma vez por dia, que você pode desligar. **Meu assistente pode chamar a API da Inovacc por ele?** Não. Ele diz ao assistente como um endpoint funciona e como chamá-lo; não faz a chamada. **Existe um servidor MCP hospedado?** Um servidor remoto em `https://mcp.inovacc.dev` está planejado. Ele ainda não existe. **Quais plataformas são suportadas?** Windows x86_64 hoje. macOS e Linux estão a caminho, sem data. ## Veja também - [Autenticação](/pt-br/guides/authentication/): os cabeçalhos que toda chamada de API leva. - [Referência da API](/pt-br/reference/): cada produto e seus endpoints. - [llms.txt](/llms.txt): a mesma documentação como índice para modelos de linguagem.