API REST v1

Gestisca agenti, legga conversazioni e contatti e chatti dal suo backend, con semplice HTTP.

curl https://api.onetype.ai/v1/agents -H "Authorization: Bearer sk_live_…"

Autenticazione e chiavi

Crei le chiavi in Developer › API keys (proprietario o amministratore). Una chiave viene mostrata una sola volta.

ChiavePrefissoUsoPuò fare
Secretsk_live_Solo i suoi serverTutto ciò che può fare un amministratore del workspace, tranne le azioni di identità e di proprietà
Restrictedrk_live_Server, CI, strumenti di automazioneSolo le autorizzazioni che seleziona alla creazione (mai più delle sue)

Le chiavi API sono incluse con Premium. Invii la chiave come Authorization: Bearer <key>. Le chiavi appartengono a un solo workspace e una chiave non può mai leggere i dati di un altro workspace. Tenga le chiavi secret e restricted fuori da browser, app mobili e repository. Se una chiave trapela, la revochi nella dashboard e la richiesta successiva con essa fallisce.

Risorse

EndpointScope (autorizzazione)Stato
GET/POST /v1/agents, GET/PATCH/DELETE /v1/agents/:idagents.read, agents.update, …Disponibile
GET /v1/conversations?agent&status&created[gte], GET /v1/conversations/:id, GET /v1/conversations/:id/messagesconversations.readDisponibile
POST /v1/conversations { agent }conversations.write (solo chiavi)Disponibile
POST /v1/conversations/:id/messages { content, stream? }conversations.writeDisponibile
GET /v1/contacts?agent, GET /v1/contacts/:idcontacts.readDisponibile
POST/DELETE /v1/mcp, /v1/mcp/agents/:agentvedere MCPDisponibile

La conoscenza e l'utilizzo si gestiscono nella dashboard.

Un contatto appartiene a un solo agente (agent, un id agt_… ): la stessa persona sui siti di due dei suoi agenti corrisponde a due contatti. ?agent=agt_… elenca quelli di un agente.

Gli oggetti pubblici usano campi snake_case e id con prefisso (le route dei visitatori di una chat personalizzata usano camelCase, per esempio isAiGenerated; snake_case, is_ai_generated, esiste solo nelle strutture /v1 ). Non contengono mai campi interni. Ogni oggetto messaggio ha is_ai_generated (true per le risposte dell'agente, false per quelle del suo team), come richiede il Regolamento UE sull'IA (AI Act).

OpenAPI: https://api.onetype.ai/v1/openapi.json, generato dagli stessi schemi con cui l'API convalida.

Stati delle conversazioni

Gli oggetti conversazione (in /v1 e nei webhook conversation.* ) contengono status e, quando risolta, resolved_by:

statusSignificato
openIn corso
escalatedPassata al suo team; solo una persona la chiude
resolvedChiusa con una risposta. resolved_by: ai (chiusa automaticamente dopo una buona risposta), member (una persona del suo team), visitor (confermata dal visitatore) oppure idle (conversazioni chiuse prima del 2026-09-24)
unresolvedChiusa automaticamente dopo che l'ultima risposta dell'agente ha dichiarato di non sapere, o è stata valutata negativamente. Torna a open se il visitatore scrive di nuovo
failedNon ha potuto ricevere risposta a causa di un errore, oppure è stata chiusa dal suo team come non risolta (anche dopo un passaggio a un operatore)

Una conversazione gestita dal solo agente si chiude automaticamente 30 minuti dopo l'ultimo messaggio. Le conversazioni con passaggio a un operatore, gestite dal suo team o in attesa di un messaggio del visitatore senza risposta non vengono mai chiuse automaticamente. Possono essere aggiunti nuovi valori; tratti quelli sconosciuti come open.

Paginazione

Gli endpoint di elenco usano i cursori:

curl "https://api.onetype.ai/v1/conversations?limit=50" -H "Authorization: Bearer sk_live_…"
{ "object": "list", "data": [ … ], "has_more": true, "next_cursor": "b3BhcXVl…" }

Passi cursor=<next_cursor> per la pagina successiva. limit è 20 per impostazione predefinita, con un massimo di 100. I cursori sono opachi e restano stabili quando arrivano nuovi elementi mentre scorre le pagine.

Idempotenza

Invii Idempotency-Key: <any unique string> su qualsiasi POST per rendere sicuri i nuovi tentativi. Il primo risultato viene conservato per 24 ore, e un nuovo tentativo con la stessa chiave lo restituisce invece di rifare il lavoro.

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"}'
  • Una risposta riproposta contiene Idempotent-Replayed: true.
  • Le chiavi sono 1–255 caratteri ASCII stampabili. Qualsiasi altra cosa è 400 BAD_IDEMPOTENCY_KEY.
  • La stessa chiave con un corpo diverso è 409 IDEMPOTENCY_KEY_REUSED. Usi una nuova chiave per una nuova richiesta.
  • Finché la prima richiesta con una chiave è ancora in corso, un nuovo tentativo riceve 409 IDEMPOTENCY_KEY_IN_USE. Attenda e riprovi.
  • Gli errori di convalida non vengono memorizzati (corregga la richiesta e riprovi con la stessa chiave). Un rifiuto prodotto dal lavoro stesso (per esempio un limite del piano) viene memorizzato e riproposto.
  • Le chiavi sono private per il suo workspace e la sua chiave.

Errori

Ogni errore ha la stessa struttura, più un'intestazione x-request-id . Includa l'id della richiesta quando contatta l'assistenza.

{ "error": { "status": 422, "code": "VALIDATION_FAILED", "message": "content: required", "fields": { "content": "Required" } } }
StatoQuandoCodici tipici
400La richiesta non è validaVALIDATION_FAILED (vedere fields), BAD_IDEMPOTENCY_KEY
401La chiave manca, è errata o è stata revocataUNAUTHENTICATED
403La chiave non ha l'autorizzazionePERMISSION_DENIED
404Non trovato nel suo workspace (gli oggetti di altri workspace appaiono come inesistenti)NOT_FOUND
409ConflittiIDEMPOTENCY_KEY_REUSED, IDEMPOTENCY_KEY_IN_USE, INVALID_TRANSITION
402 / 422Limiti del piano e regole di businessQUOTA_EXCEEDED, REFUSED (il messaggio ne spiega il motivo)
429Troppe richiesteRATE_LIMITED
5xxColpa nostrasempre INTERNAL, con l'id della richiesta. Se continua a succedere, scriva a support@onetype.ai con l'id della richiesta

code i valori sono stabili. Basi la gestione su di essi, non su message.

Limiti di frequenza

Per chiave: 100 richieste ogni 10 secondi e 20 messaggi di chat ogni 10 secondi. Limiti più alti sono inclusi nei piani superiori. Ogni risposta contiene:

RateLimit-Limit: 100
RateLimit-Remaining: 87
RateLimit-Reset: 6

Una 429 contiene anche Retry-After (secondi). Attenda tanto, poi riprovi. Non riprovi in un ciclo serrato.

L'autenticazione fallita è limitata per indirizzo di rete. Le richieste con una chiave errata o revocata contano sull'indirizzo da cui provengono. Se molti client condividono un indirizzo pubblico (un NAT aziendale, un provider di CI), un solo client configurato male può esaurire il limite, e allora anche le richieste con una chiave valida da quell'indirizzo ricevono 429 RATE_LIMITED finché la finestra non si azzera. Lo gestisca come qualsiasi 429: rispetti Retry-After, poi corregga il client che invia la chiave errata.

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 dal suo backend

Crei una conversazione per un agente, poi vi invii dei messaggi. Ogni risposta viene scritta, memorizzata e fatturata esattamente come una risposta del 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": [ … ], … }

Il campo parts della risposta contiene parti text e una parte source-document per ogni fonte citata (title e url per le pagine web).

Streaming

Invii "stream": true per ricevere la risposta mentre viene scritta, come eventi inviati dal server nel formato AI SDK UI Message Stream v1 . La risposta contiene x-vercel-ai-ui-message-stream: v1, e il campo data di ogni evento è una parte JSON: start, text-start, text-delta (con delta), text-end, source-document, finish (con messageMetadata.outcome), error oppure abort. Lo stream termina con 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}`);
    }
}

Con il Vercel AI SDK sul suo server può passare la risposta direttamente a useChat, perché è lo stesso formato.

  • Disconnettersi non annulla la risposta. La risposta viene comunque scritta, memorizzata e fatturata.
  • Riprovare uno stream terminato è sicuro. Riprovi con la stessa Idempotency-Key e otterrà la risposta memorizzata come JSON (stato 200), non una seconda risposta.

Versionamento

/v1 cambia solo in modo additivo: nuovi campi, nuovi endpoint, nuovi tipi di evento. Il suo codice deve ignorare i campi che non conosce. Se mai servisse una modifica non retrocompatibile, uscirà come nuova versione selezionata per chiave, con preavviso.