Inovacc Desenvolvedores

Referência da API

Chat com IA

Respostas de chat dos modelos de linguagem da plataforma.

URL base https://ai.inovacc.dev

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;
  • a resposta precisa vir dos seus próprios documentos, com citações: consulte uma coleção na nuvem de Conhecimento e busca vetorial;
  • você precisa de vetores em vez de texto: use Embeddings de IA.

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 <key> 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.

  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). 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

LimiteValor
Corpo da requisição1 MiB por padrão; sua organização pode ser configurada entre 1 KiB e 20 MiB
Imagens por requisição20
Custo de entrada estimado de uma imagem1.600 tokens
Tokens de entrada por requisiçãoo limite da sua organização (400 input_too_large acima dele)
Tokens de saída por requisiçãoo menor entre o teto da rota e o da sua organização
Tempo até a primeira resposta do modelo60 segundos
Resposta armazenada para repetição24 horas
Uma chamada mantida como em andamento5 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áriosconforme definido para a sua organização

Preços: sob consulta. A unidade de preço é tokens.

Erros

StatusCódigoO que significa e o que fazer
400missing_operation_id, invalid_operation_idEnvie X-Operation-Id com 8 a 128 letras, dígitos, _ ou -.
400invalid_bodyO corpo não é um objeto JSON, ou user não é uma string. Corrija o corpo.
400invalid_messagesmessages está vazio ou uma mensagem está malformada.
400unsupported_fieldUm campo de nível superior que este endpoint não aceita; remova-o.
400unsupported_field_for_routeA 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:.
400model_not_allowedO valor de model não é um id de rota válido. Use um id de GET /v1/models.
400input_too_largeA entrada excede o limite por requisição da sua organização, ou há mais de 20 imagens. Encurte-a.
401missing_credentials, invalid_credentialsEnvie uma chave válida.
403key_disabled, organization_disabledA chave ou a organização foi desativada; fale com o seu administrador.
403field_not_allowedUm campo que a sua organização não recebeu permissão para usar.
403route_forbiddenA rota não é uma que a sua organização possa usar neste endpoint.
409operation_in_progressEsse id de operação ainda está em execução; aguarde e tente novamente.
413request_too_largeO corpo excede o seu limite de tamanho.
429rate_limitedRequisições demais; aguarde Retry-After segundos.
429quota_exceeded, concurrency_limitedUma cota de tokens, de custo ou de simultaneidade se esgotou; sem Retry-After.
429budget_exhaustedUm orçamento diário foi consumido; ele é reiniciado às 00:00 UTC (Retry-After).
502upstream_errorO modelo não respondeu de forma utilizável; tente novamente com o mesmo id de operação.
503service_unavailable, route_unavailableTente novamente mais tarde; route_unavailable exige que a Inovacc corrija a sua rota.
504timeout_errorO modelo não começou a responder em 60 segundos; tente novamente.

O envelope e todos os tipos estão em Erros.

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.

Autenticação

Toda chamada leva a sua chave; a sua organização vem dela. Veja o guia de autenticação.

CabeçalhoAuthorizationBearer <chave de API>
CabeçalhoX-Operation-Idum id único que você escolhe, em toda chamada exceto GET

Endpoints

POST /v1/chat/completions

GET /v1/models

POST /v1/run

Exemplo

Linguagem

⋮
POST /v1/chat/completionsExemplo

cURL

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 '{
  "model": "r00",
  "messages": [
    {
      "role": "user",
      "content": "hello"
    }
  ]
}'

TypeScript

import crypto from "node:crypto";

const body: Record<string, unknown> = {
  "model": "r00",
  "messages": [
    {
      "role": "user",
      "content": "hello"
    }
  ]
};

const url = "https://ai.inovacc.dev/v1/chat/completions";

const response = await fetch(url, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.INOVACC_API_KEY}`,
    "X-Operation-Id": crypto.randomUUID(),
    "Content-Type": "application/json",
  },
  body: JSON.stringify(body),
});

console.log(response.status, await response.text());

Python

import json
import os
import urllib.request
import uuid

body = {
    "model": "r00",
    "messages": [
        {
            "role": "user",
            "content": "hello",
        },
    ],
}

request = urllib.request.Request(
    "https://ai.inovacc.dev/v1/chat/completions",
    data=json.dumps(body).encode(),
    method="POST",
    headers={
        "User-Agent": "inovacc-python-sample",
        "Authorization": "Bearer " + os.environ["INOVACC_API_KEY"],
        "X-Operation-Id": str(uuid.uuid4()),
        "Content-Type": "application/json",
    },
)

with urllib.request.urlopen(request) as response:
    print(response.status, response.read().decode())

Go

package main

import (
	"crypto/rand"
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
)

const url = "https://ai.inovacc.dev/v1/chat/completions"

const body = `{
  "model": "r00",
  "messages": [
    {
      "role": "user",
      "content": "hello"
    }
  ]
}`

// newUUID returns a random (version 4) UUID, from the standard library alone.
func newUUID() string {
	b := make([]byte, 16)
	if _, err := rand.Read(b); err != nil {
		panic(err)
	}
	b[6] = b[6]&0x0f | 0x40
	b[8] = b[8]&0x3f | 0x80
	return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
}

func main() {
	req, err := http.NewRequest("POST", url, strings.NewReader(body))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("INOVACC_API_KEY"))
	req.Header.Set("X-Operation-Id", newUUID())
	req.Header.Set("Content-Type", "application/json")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	out, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	fmt.Println(res.Status, string(out))
}

Rust

// Cargo.toml: reqwest = { version = "0.12", features = ["blocking", "json"] }
// Cargo.toml: serde_json = "1"
// Cargo.toml: uuid = { version = "1", features = ["v4"] }

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api_key = std::env::var("INOVACC_API_KEY")?;
    let body = serde_json::json!({
        "model": "r00",
        "messages": [
            {
                "role": "user",
                "content": "hello"
            }
        ]
    });
    let response = reqwest::blocking::Client::new()
        .post("https://ai.inovacc.dev/v1/chat/completions")
        .bearer_auth(api_key)
        .header("X-Operation-Id", uuid::Uuid::new_v4().to_string())
        .json(&body)
        .send()?;
    println!("{} {}", response.status(), response.text()?);
    Ok(())
}

JavaScript

import crypto from "node:crypto";

const body = {
  "model": "r00",
  "messages": [
    {
      "role": "user",
      "content": "hello"
    }
  ]
};

const url = "https://ai.inovacc.dev/v1/chat/completions";

const response = await fetch(url, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.INOVACC_API_KEY}`,
    "X-Operation-Id": crypto.randomUUID(),
    "Content-Type": "application/json",
  },
  body: JSON.stringify(body),
});

console.log(response.status, await response.text());

PHP

<?php

$body = <<<'JSON'
{
  "model": "r00",
  "messages": [
    {
      "role": "user",
      "content": "hello"
    }
  ]
}
JSON;

function uuid4(): string
{
    $bytes = random_bytes(16);
    $bytes[6] = chr(ord($bytes[6]) & 0x0f | 0x40);
    $bytes[8] = chr(ord($bytes[8]) & 0x3f | 0x80);
    return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($bytes), 4));
}

$curl = curl_init('https://ai.inovacc.dev/v1/chat/completions');
curl_setopt_array($curl, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('INOVACC_API_KEY'),
        'X-Operation-Id: ' . uuid4(),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => $body,
]);

$response = curl_exec($curl);
echo curl_getinfo($curl, CURLINFO_HTTP_CODE), ' ', $response, "\n";
curl_close($curl);

Ruby

require "net/http"
require "securerandom"
require "uri"

uri = URI('https://ai.inovacc.dev/v1/chat/completions')
body = <<~'JSON'
{
  "model": "r00",
  "messages": [
    {
      "role": "user",
      "content": "hello"
    }
  ]
}
JSON

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch('INOVACC_API_KEY')}"
request["X-Operation-Id"] = SecureRandom.uuid
request["Content-Type"] = "application/json"
request.body = body

response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |http|
  http.request(request)
end

puts "#{response.code} #{response.body}"

Java

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.UUID;

public class Main {
    public static void main(String[] args) throws Exception {
        String apiKey = System.getenv("INOVACC_API_KEY");
        String body = "{" +
                "\"model\": \"r00\"," +
                "\"messages\": [" +
                "{" +
                "\"role\": \"user\"," +
                "\"content\": \"hello\"" +
                "}" +
                "]" +
                "}";

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://ai.inovacc.dev/v1/chat/completions"))
                .header("Authorization", "Bearer " + apiKey)
                .header("X-Operation-Id", UUID.randomUUID().toString())
                .header("Content-Type", "application/json")
                .method("POST", HttpRequest.BodyPublishers.ofString(body))
                .build();

        HttpResponse<String> response = HttpClient.newHttpClient()
                .send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.statusCode() + " " + response.body());
    }
}

C#

using System.Text;

var body = "{" +
    "\"model\": \"r00\"," +
    "\"messages\": [" +
    "{" +
    "\"role\": \"user\"," +
    "\"content\": \"hello\"" +
    "}" +
    "]" +
    "}";

var url = "https://ai.inovacc.dev/v1/chat/completions";
var apiKey = Environment.GetEnvironmentVariable("INOVACC_API_KEY");

using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post, url);
request.Headers.Add("Authorization", $"Bearer {apiKey}");
request.Headers.Add("X-Operation-Id", Guid.NewGuid().ToString());
request.Content = new StringContent(body, Encoding.UTF8, "application/json");

using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");

Kotlin

import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse
import java.util.UUID

fun main() {
    val apiKey = System.getenv("INOVACC_API_KEY")
    val body = "{" +
        "\"model\": \"r00\"," +
        "\"messages\": [" +
        "{" +
        "\"role\": \"user\"," +
        "\"content\": \"hello\"" +
        "}" +
        "]" +
        "}"

    val request = HttpRequest.newBuilder()
        .uri(URI.create("https://ai.inovacc.dev/v1/chat/completions"))
        .header("Authorization", "Bearer " + apiKey)
        .header("X-Operation-Id", UUID.randomUUID().toString())
        .header("Content-Type", "application/json")
        .method("POST", HttpRequest.BodyPublishers.ofString(body))
        .build()

    val response = HttpClient.newHttpClient()
        .send(request, HttpResponse.BodyHandlers.ofString())
    println("${response.statusCode()} ${response.body()}")
}

Swift

import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

let body = #"""
{
  "model": "r00",
  "messages": [
    {
      "role": "user",
      "content": "hello"
    }
  ]
}
"""#

let apiKey = ProcessInfo.processInfo.environment["INOVACC_API_KEY"] ?? ""

let url = URL(string: "https://ai.inovacc.dev/v1/chat/completions")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
request.setValue(UUID().uuidString, forHTTPHeaderField: "X-Operation-Id")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = Data(body.utf8)

let (data, response) = try await URLSession.shared.data(for: request)
let status = (response as? HTTPURLResponse)?.statusCode ?? 0
print(status, String(decoding: data, as: UTF8.self))
Detalhes da fonte

Entrada do catálogo

Id
identity/component-taxonomy/capabilities#ai.chat
Repositório
identity
Caminho
contracts/component-taxonomy/catalog/capabilities.json
Commit
08ef3cd75d82

Exemplo

Id
identity/component-taxonomy/quickstart#ai.chat
Repositório
identity
Caminho
contracts/component-taxonomy/catalog/capabilities.json
Commit
08ef3cd75d82
Atualizado em 2026-10-10.