Responses API do Muitto
Use modelos de texto do catálogo Muitto com o SDK oficial da OpenAI ou com HTTP direto. A API é stateless, cobra o uso real e expõe somente as capacidades descritas nesta página.
Crie um token pessoal em Configurações → Tokens MCP e envie-o como Bearer. Para gerar, conceda write:generate; para consultar /models, conceda read:catalog. Tokens b2b_ são rejeitados por este endpoint.
Revogue o token na mesma tela de Configurações; chamadas futuras com ele retornam 401.
https://muitto.app/api/public/v1
lv_mcp_YOUR_TOKEN
Primeira requisição
Consulte GET /models primeiro com read:catalog para descobrir IDs de modelos de texto.
curl https://muitto.app/api/public/v1/models \
-H "Authorization: Bearer lv_mcp_YOUR_TOKEN"Os IDs são slugs reais do catálogo. Faça GET /models com read:catalog e use um id retornado; não adivinhe nomes de modelos.
curl https://muitto.app/api/public/v1/responses \
-H "Authorization: Bearer lv_mcp_YOUR_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: REQUEST_UUID" \
-d '{"model":"MODEL_FROM_GET_MODELS","input":"Hello from Muitto"}'import { randomUUID } from "node:crypto";
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.MUITTO_TOKEN,
baseURL: "https://muitto.app/api/public/v1",
maxRetries: 0,
});
const response = await client.responses.create({
model: "MODEL_FROM_GET_MODELS",
instructions: "Be concise.",
input: "Hello from Muitto",
}, { headers: { "Idempotency-Key": randomUUID() } });
console.log(response.output_text);import os
import uuid
from openai import OpenAI
client = OpenAI(
api_key=os.environ["MUITTO_TOKEN"],
base_url="https://muitto.app/api/public/v1",
max_retries=0,
)
response = client.responses.create(
model="MODEL_FROM_GET_MODELS",
input="Hello from Muitto",
extra_headers={"Idempotency-Key": str(uuid.uuid4())},
)
print(response.output_text)Entrada e parâmetros
input aceita uma string ou itens de mensagem com conteúdo de texto. instructions vira uma mensagem de sistema no provedor. Imagens, áudio e outros itens multimodais não são aceitos.
{
"model": "MODEL_FROM_GET_MODELS",
"instructions": "Optional system guidance",
"input": "A text string",
"max_output_tokens": 1024,
"temperature": 0.2,
"top_p": 0.9,
"store": false
}Os parâmetros aceitos são validados estritamente. Campos desconhecidos retornam erro 400 com uma mensagem explícita.
const response = await client.responses.create({
model: "MODEL_FROM_GET_MODELS",
input: "Find the order",
tools: [{
type: "function",
name: "lookup_order",
description: "Find an order by id",
parameters: { type: "object", properties: { id: { type: "string" } }, required: ["id"] },
}],
}, { headers: { "Idempotency-Key": randomUUID() } });
const calls = response.output.filter((item) => item.type === "function_call");
if (calls.length === 0) throw new Error("The model did not call lookup_order");
const outputs = await Promise.all(calls.map(async (call) => ({
type: "function_call_output",
call_id: call.call_id,
output: JSON.stringify(await lookupOrder(call.arguments)),
})));
// Run every requested function, then send all results in a new stateless request:
const next = await client.responses.create({
model: "MODEL_FROM_GET_MODELS",
input: [
{ role: "user", content: "Find the order" },
...response.output,
...outputs,
],
}, { headers: { "Idempotency-Key": randomUUID() } });As function tools usam o formato de funções do Responses. Built-in tools são rejeitadas. Resultados são enviados como itens function_call_output na próxima requisição stateless.
const response = await client.responses.create({
model: "MODEL_FROM_GET_MODELS",
input: "Return the status",
text: {
format: {
type: "json_schema",
name: "status",
schema: { type: "object", properties: { ok: { type: "boolean" } }, required: ["ok"], additionalProperties: false },
strict: true,
},
},
}, { headers: { "Idempotency-Key": randomUUID() } });Use json_schema ou json_object. O modelo e a rota selecionados precisam declarar suporte a saída estruturada.
Streaming buffered
O provedor conclui e a cobrança é liquidada antes de o endpoint emitir o stream. Os eventos são eventos semânticos genuínos do Responses, mas o texto e os argumentos de função são agrupados em deltas completos; isso não é streaming de tokens em tempo real.
const stream = client.responses.stream({
model: "MODEL_FROM_GET_MODELS",
input: "Hello",
}, { headers: { "Idempotency-Key": randomUUID() } });
for await (const event of stream) console.log(event.type);
const response = await stream.finalResponse();A sequência inclui response.created, response.in_progress, eventos de item e parte, deltas de texto ou argumentos e eventos done. response.completed é emitido somente para uma resposta concluída; um limite de saída ou filtro de conteúdo termina em response.incomplete com o motivo correspondente. Cada evento tem ID estável e número de sequência.
Limites e estados
| Recurso | Aceita | Rejeita |
|---|---|---|
| Entrada e saída de texto | ✓ | — |
| Function tools | ✓ | — |
| Saída estruturada json_schema | ✓ | — |
| Entrada multimodal | — | ✕ |
| previous_response_id / estado da conversa | — | ✕ |
| background / built-in tools | — | ✕ |
| store:true | — | ✕ |
O corpo da requisição é limitado a 8 MB, a entrada estimada a 2 milhões de tokens e max_output_tokens a 1 milhão. O limite é de 60 requisições por minuto por token e por instância. O stream é emitido depois da conclusão do provedor e da liquidação da cobrança.
A cobrança usa o snapshot USD atual da rota selecionada e o multiplicador de preço do modelo (padrão 4 quando não configurado). Entrada e saída são medidas por 1.000 tokens. Tokens de entrada em cache usam a tarifa de entrada vigente e são reportados separadamente no uso. Cada requisição tem cobrança mínima de US$ 0,001.
Os créditos são reservados antes do envio ao provedor e liquidados com o uso informado após a conclusão. Uso ausente ou resultado upstream incerto deixa a reserva pendente para reconciliação.
O SDK oficial tenta novamente erros 502/503 por padrão e não cria Idempotency-Key automaticamente. Desative os retries automáticos (JavaScript maxRetries: 0; Python max_retries=0) e envie uma chave única na tentativa inicial. Se você repetir manualmente uma tentativa cujo resultado é desconhecido, reutilize a mesma chave: ela retorna 409, não reproduz o corpo nem chama o provedor, e o consumo permanece reservado até a reconciliação.
Entrada inválida retorna 400, token pessoal ausente ou inválido retorna 401, escopo ausente retorna 403, créditos insuficientes retornam 402 e modelo desconhecido retorna 404. Um limite de saída retorna uma resposta incompleta com reason max_output_tokens; um filtro de conteúdo usa reason content_filter. Timeout ou uso ausente mantém os créditos reservados e pendentes.