REST API v1
Gerencie agentes, leia conversas e contatos e converse a partir do seu próprio backend, com HTTP simples.
curl https://api.onetype.ai/v1/agents -H "Authorization: Bearer sk_live_…"Autenticação e chaves
Crie chaves em Developer › API keys (proprietário ou admin). Uma chave é mostrada uma única vez.
| Chave | Prefixo | Uso | Pode |
|---|---|---|---|
| Secret | sk_live_ | Somente os seus servidores | Tudo o que um admin do workspace pode fazer, exceto ações de identidade e de propriedade |
| Restricted | rk_live_ | Servidores, CI, ferramentas de automação | Somente as permissões que você marca ao criá-la (nunca mais do que as suas próprias) |
As chaves de API vêm com o Premium. Envie a chave como Authorization: Bearer <key>. As chaves pertencem a um workspace, e uma chave nunca pode ler os dados de outro workspace. Mantenha as chaves secret e restricted fora de navegadores, apps móveis e repositórios. Se uma vazar, revogue-a no dashboard, e a requisição seguinte com ela falha.
Recursos
| Endpoint | Scope (permissão) | Status |
|---|---|---|
GET/POST /v1/agents, GET/PATCH/DELETE /v1/agents/:id | agents.read, agents.update, … | Disponível |
GET /v1/conversations?agent&status&created[gte], GET /v1/conversations/:id, GET /v1/conversations/:id/messages | conversations.read | Disponível |
POST /v1/conversations { agent } | conversations.write (somente chaves) | Disponível |
POST /v1/conversations/:id/messages { content, stream? } | conversations.write | Disponível |
GET /v1/contacts?agent, GET /v1/contacts/:id | contacts.read | Disponível |
POST/DELETE /v1/mcp, /v1/mcp/agents/:agent | veja MCP | Disponível |
O conhecimento e o uso são gerenciados no dashboard.
Um contato pertence a um agente (agent, um id agt_… ): a mesma pessoa nos sites de dois dos seus agentes vira dois contatos. ?agent=agt_… lista os de um agente.
Os objetos públicos usam campos snake_case e ids com prefixo (as rotas de visitante de um chat personalizado usam camelCase, por exemplo isAiGenerated; snake_case, is_ai_generated, existe apenas nos formatos /v1 ). Eles nunca contêm campos internos. Todo objeto de mensagem tem is_ai_generated (true para as respostas do agente, false para as da sua equipe), como o AI Act da UE exige.
OpenAPI: https://api.onetype.ai/v1/openapi.json, gerado a partir dos mesmos schemas com que a API valida.
Status das conversas
Os objetos de conversa (em /v1 e nos webhooks conversation.* ) trazem status e, quando resolvidas, resolved_by:
status | Significado |
|---|---|
open | Em andamento |
escalated | Passada à sua equipe; só uma pessoa a fecha |
resolved | Fechada com uma resposta. resolved_by: ai (fechada automaticamente após uma boa resposta), member (uma pessoa da sua equipe), visitor (o visitante confirmou) ou idle (conversas fechadas antes de 2026-09-24) |
unresolved | Fechada automaticamente depois que a última resposta do agente disse que não sabia, ou foi mal avaliada. Volta para open se o visitante escrever de novo |
failed | Não pôde ser respondida por causa de um erro, ou foi fechada pela sua equipe como não resolvida (também após um repasse) |
Uma conversa que o agente trata sozinho é fechada automaticamente 30 minutos após a última mensagem. Conversas com repasse, mantidas pela sua equipe ou aguardando uma mensagem de visitante sem resposta nunca são fechadas automaticamente. Novos valores podem ser adicionados; trate os desconhecidos como open.
Paginação
Os endpoints de lista usam cursores:
curl "https://api.onetype.ai/v1/conversations?limit=50" -H "Authorization: Bearer sk_live_…"{ "object": "list", "data": [ … ], "has_more": true, "next_cursor": "b3BhcXVl…" }Passe cursor=<next_cursor> para a próxima página. limit é 20 por padrão, com máximo de 100. Os cursores são opacos e permanecem estáveis quando chegam novos itens enquanto você pagina.
Idempotência
Envie Idempotency-Key: <any unique string> em qualquer POST para tornar as novas tentativas seguras. O primeiro resultado é mantido por 24 horas, e uma nova tentativa com a mesma chave o retorna em vez de refazer o trabalho.
curl -X POST https://api.onetype.ai/v1/conversations \
-H "Authorization: Bearer sk_live_…" \
-H "Idempotency-Key: 6f1c9f2e-3b1d-4a0e-9d0f-2f6f0b3c9a11" \
-H "Content-Type: application/json" \
-d '{"agent":"YOUR_AGENT_ID"}'- Uma resposta reproduzida traz
Idempotent-Replayed: true. - As chaves têm de 1 a 255 caracteres ASCII imprimíveis. Qualquer outra coisa é
400 BAD_IDEMPOTENCY_KEY. - A mesma chave com um corpo diferente é
409 IDEMPOTENCY_KEY_REUSED. Use uma chave nova para uma requisição nova. - Enquanto a primeira requisição com uma chave ainda está em execução, uma nova tentativa recebe
409 IDEMPOTENCY_KEY_IN_USE. Aguarde e tente de novo. - Erros de validação não são armazenados (corrija a requisição e tente de novo com a mesma chave). Uma recusa produzida pelo próprio trabalho (p. ex. um limite do plano) é armazenada e reproduzida.
- As chaves são privadas do seu workspace e da sua chave.
Erros
Todo erro tem o mesmo formato, mais um header x-request-id . Inclua o id da requisição ao falar com o suporte.
{ "error": { "status": 422, "code": "VALIDATION_FAILED", "message": "content: required", "fields": { "content": "Required" } } }| Status | Quando | Códigos típicos |
|---|---|---|
| 400 | A requisição é inválida | VALIDATION_FAILED (veja fields), BAD_IDEMPOTENCY_KEY |
| 401 | A chave está ausente, errada ou revogada | UNAUTHENTICATED |
| 403 | A chave não tem a permissão | PERMISSION_DENIED |
| 404 | Não encontrado no seu workspace (objetos de outros workspaces parecem inexistentes) | NOT_FOUND |
| 409 | Conflitos | IDEMPOTENCY_KEY_REUSED, IDEMPOTENCY_KEY_IN_USE, INVALID_TRANSITION |
| 402 / 422 | Limites do plano e regras de negócio | QUOTA_EXCEEDED, REFUSED (a mensagem diz por quê) |
| 429 | Requisições demais | RATE_LIMITED |
| 5xx | Falha nossa | sempre INTERNAL, com o id da requisição. Se continuar acontecendo, escreva para support@onetype.ai com o id da requisição |
code é um valor estável. Baseie o seu tratamento nele, não em message.
Limites de taxa
Por chave: 100 requisições a cada 10 segundos e 20 mensagens de chat a cada 10 segundos. Limites maiores vêm com planos maiores. Toda resposta traz:
RateLimit-Limit: 100
RateLimit-Remaining: 87
RateLimit-Reset: 6Um 429 também traz Retry-After (segundos). Espere esse tempo e tente de novo. Não tente de novo em um loop sem pausa.
A autenticação com falha é limitada por endereço de rede. As requisições com uma chave errada ou revogada contam contra o endereço de onde vêm. Se muitos clientes compartilham um endereço público (um NAT corporativo, um provedor de CI), um cliente mal configurado pode esgotar o orçamento, e então até as requisições com uma chave válida desse endereço recebem 429 RATE_LIMITED até a janela reiniciar. Trate como qualquer 429: respeite Retry-After, e depois corrija o cliente que envia a chave ruim.
async function call(url: string, init: RequestInit, attempts = 3): Promise<Response>
{
const response = await fetch(url, init);
if (response.status !== 429 || attempts <= 1)
{
return response;
}
const waitSeconds = Number(response.headers.get("retry-after") ?? "1");
await new Promise((resolve) => setTimeout(resolve, waitSeconds * 1000));
return call(url, init, attempts - 1);
}Chat a partir do seu backend
Crie uma conversa para um agente e depois envie mensagens para ela. Cada resposta é escrita, armazenada e cobrada exatamente como uma resposta do widget.
curl -X POST https://api.onetype.ai/v1/conversations \
-H "Authorization: Bearer sk_live_…" -H "Content-Type: application/json" \
-d '{"agent":"YOUR_AGENT_ID"}'
# → { "id": "cnv_…", "object": "conversation", "status": "open", … }
curl -X POST https://api.onetype.ai/v1/conversations/cnv_…/messages \
-H "Authorization: Bearer sk_live_…" -H "Idempotency-Key: order-1234-question-1" -H "Content-Type: application/json" \
-d '{"content":"Where is order 1234?"}'
# → { "id": "msg_…", "object": "message", "role": "assistant", "is_ai_generated": true, "parts": [ … ], … }Os parts da resposta contêm partes text e uma parte source-document para cada fonte citada (title e url para páginas da web).
Streaming
Envie "stream": true para receber a resposta conforme é escrita, como server-sent events no formato AI SDK UI Message Stream v1 . A resposta traz x-vercel-ai-ui-message-stream: v1, e o data de cada evento é uma parte JSON: start, text-start, text-delta (com delta), text-end, source-document, finish (com messageMetadata.outcome), error ou abort. O stream termina com data: [DONE].
const response = await fetch(`https://api.onetype.ai/v1/conversations/${conversationId}/messages`, {
method: "POST",
headers: { "Authorization": `Bearer ${process.env.ONETYPE_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify({ content: "How do refunds work?", stream: true }),
});
const reader = response.body!.pipeThrough(new TextDecoderStream()).getReader();
let buffer = "";
for (;;)
{
const { value, done } = await reader.read();
if (done) break;
buffer += value;
const events = buffer.split("\n\n");
buffer = events.pop() ?? "";
for (const event of events)
{
const data = event.split("\n").find((line) => line.startsWith("data: "))?.slice(6);
if (data === undefined || data === "[DONE]") continue;
const part = JSON.parse(data);
if (part.type === "text-delta") process.stdout.write(part.delta);
if (part.type === "source-document") console.log(`\n[source] ${part.title}`);
}
}Com o Vercel AI SDK no seu próprio servidor, você pode repassar a resposta diretamente para useChat, porque é o mesmo formato.
- Desconectar não cancela a resposta. A resposta continua sendo escrita, armazenada e cobrada.
- Repetir um stream concluído é seguro. Repita com o mesmo
Idempotency-Keye você recebe a resposta armazenada como JSON (status 200), não uma segunda resposta.
Versionamento
/v1 só muda de forma aditiva: novos campos, novos endpoints, novos tipos de evento. Seu código deve ignorar campos que não conhece. Se uma mudança incompatível for necessária, ela sairá como uma nova versão escolhida por chave, com aviso prévio.