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.

ChavePrefixoUsoPode
Secretsk_live_Somente os seus servidoresTudo o que um admin do workspace pode fazer, exceto ações de identidade e de propriedade
Restrictedrk_live_Servidores, CI, ferramentas de automaçãoSomente 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

EndpointScope (permissão)Status
GET/POST /v1/agents, GET/PATCH/DELETE /v1/agents/:idagents.read, agents.update, …Disponível
GET /v1/conversations?agent&status&created[gte], GET /v1/conversations/:id, GET /v1/conversations/:id/messagesconversations.readDisponível
POST /v1/conversations { agent }conversations.write (somente chaves)Disponível
POST /v1/conversations/:id/messages { content, stream? }conversations.writeDisponível
GET /v1/contacts?agent, GET /v1/contacts/:idcontacts.readDisponível
POST/DELETE /v1/mcp, /v1/mcp/agents/:agentveja MCPDisponí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:

statusSignificado
openEm andamento
escalatedPassada à sua equipe; só uma pessoa a fecha
resolvedFechada 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)
unresolvedFechada 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
failedNã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" } } }
StatusQuandoCódigos típicos
400A requisição é inválidaVALIDATION_FAILED (veja fields), BAD_IDEMPOTENCY_KEY
401A chave está ausente, errada ou revogadaUNAUTHENTICATED
403A chave não tem a permissãoPERMISSION_DENIED
404Não encontrado no seu workspace (objetos de outros workspaces parecem inexistentes)NOT_FOUND
409ConflitosIDEMPOTENCY_KEY_REUSED, IDEMPOTENCY_KEY_IN_USE, INVALID_TRANSITION
402 / 422Limites do plano e regras de negócioQUOTA_EXCEEDED, REFUSED (a mensagem diz por quê)
429Requisições demaisRATE_LIMITED
5xxFalha nossasempre 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: 6

Um 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-Key e 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.