REST API v1
Gérez des agents, lisez les conversations et les contacts, et discutez depuis votre propre backend, avec du HTTP simple.
curl https://api.onetype.ai/v1/agents -H "Authorization: Bearer sk_live_…"Authentification et clés
Créez des clés dans Developer › API keys (propriétaire ou admin). Une clé n'est affichée une seule fois.
| Clé | Préfixe | Usage | Permissions |
|---|---|---|---|
| Secrète | sk_live_ | Uniquement vos serveurs | Tout ce qu'un admin de l'espace de travail peut faire, sauf les actions d'identité et de propriété |
| Restreinte | rk_live_ | Serveurs, CI, outils d'automatisation | Uniquement les autorisations que vous cochez à sa création (jamais plus que les vôtres) |
Les clés d'API sont incluses avec Premium. Envoyez la clé en tant que Authorization: Bearer <key>. Les clés appartiennent à un seul espace de travail, et une clé ne peut jamais lire les données d'un autre espace de travail. Gardez les clés secrètes et restreintes hors des navigateurs, des applications mobiles et des dépôts. Si l'une d'elles fuite, révoquez-la dans le tableau de bord, et la toute prochaine requête qui l'utilise échoue.
Ressources
| Point de terminaison | Portée (autorisation) | Statut |
|---|---|---|
GET/POST /v1/agents, GET/PATCH/DELETE /v1/agents/:id | agents.read, agents.update, … | Available |
GET /v1/conversations?agent&status&created[gte], GET /v1/conversations/:id, GET /v1/conversations/:id/messages | conversations.read | Available |
POST /v1/conversations { agent } | conversations.write (clés uniquement) | Available |
POST /v1/conversations/:id/messages { content, stream? } | conversations.write | Available |
GET /v1/contacts?agent, GET /v1/contacts/:id | contacts.read | Available |
POST/DELETE /v1/mcp, /v1/mcp/agents/:agent | voir MCP | Available |
Les connaissances et l'utilisation se gèrent dans le tableau de bord.
Un contact appartient à un seul agent (agent, un identifiant agt_… ) : la même personne sur les sites de deux de vos agents compte comme deux contacts. ?agent=agt_… liste ceux d'un agent.
Les objets publics utilisent des champs en snake_case et des identifiants préfixés (les routes visiteur d'un chat personnalisé utilisent le camelCase, par exemple isAiGenerated ; le snake_case, is_ai_generated, n'existe que dans les formes /v1 ). Ils ne contiennent jamais de champs internes. Chaque objet message comporte is_ai_generated (true pour les réponses de l'agent, false pour celles de votre équipe), comme l'exige le règlement européen sur l'IA.
OpenAPI : https://api.onetype.ai/v1/openapi.json, généré à partir des mêmes schémas que ceux avec lesquels l'API valide.
Statuts de conversation
Les objets de conversation (dans /v1 et dans les webhooks conversation.* ) portent status et, une fois résolue, resolved_by:
status | Signification |
|---|---|
open | En cours |
escalated | Transmise à votre équipe ; seule une personne la ferme |
resolved | Fermée avec une réponse. resolved_by: ai (fermée automatiquement après une bonne réponse), member (une personne de votre équipe), visitor (le visiteur a confirmé), ou idle (conversations fermées avant le 2026-09-24) |
unresolved | Fermée automatiquement après que la dernière réponse de l'agent a indiqué qu'il ne savait pas, ou a été mal notée. Elle revient à open si le visiteur écrit à nouveau |
failed | N'a pas pu recevoir de réponse à cause d'une erreur, ou a été fermée par votre équipe comme non résolue (aussi après un passage à un humain) |
Une conversation que l'agent gère seul se ferme automatiquement 30 minutes après son dernier message. Les conversations avec un passage à un humain, prises en charge par votre équipe, ou en attente d'un message de visiteur resté sans réponse ne sont jamais fermées automatiquement. De nouvelles valeurs peuvent être ajoutées ; traitez les valeurs inconnues comme open.
Pagination
Les points de terminaison de liste utilisent des curseurs :
curl "https://api.onetype.ai/v1/conversations?limit=50" -H "Authorization: Bearer sk_live_…"{ "object": "list", "data": [ … ], "has_more": true, "next_cursor": "b3BhcXVl…" }Transmettez cursor=<next_cursor> pour la page suivante. limit vaut 20 par défaut, avec un maximum de 100. Les curseurs sont opaques et restent stables quand de nouveaux éléments arrivent pendant que vous paginez.
Idempotence
Envoyez Idempotency-Key: <any unique string> sur tout POST pour rendre les nouvelles tentatives sûres. Le premier résultat est conservé pendant 24 heures, et une nouvelle tentative avec la même clé le renvoie au lieu de refaire le travail.
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"}'- Une réponse rejouée porte
Idempotent-Replayed: true. - Les clés font de 1 à 255 caractères ASCII imprimables. Tout le reste donne
400 BAD_IDEMPOTENCY_KEY. - La même clé avec un corps différent donne
409 IDEMPOTENCY_KEY_REUSED. Utilisez une nouvelle clé pour une nouvelle requête. - Tant que la première requête avec une clé est encore en cours, une nouvelle tentative reçoit
409 IDEMPOTENCY_KEY_IN_USE. Attendez et réessayez. - Les erreurs de validation ne sont pas conservées (corrigez la requête et réessayez avec la même clé). Un refus produit par le travail lui-même (par exemple une limite d'offre) est conservé et rejoué.
- Les clés sont privées pour votre espace de travail et votre clé.
Erreurs
Chaque erreur a la même forme, plus un en-tête x-request-id . Indiquez l'identifiant de requête quand vous contactez le support.
{ "error": { "status": 422, "code": "VALIDATION_FAILED", "message": "content: required", "fields": { "content": "Required" } } }| Statut | Quand | Codes typiques |
|---|---|---|
| 400 | La requête est invalide | VALIDATION_FAILED (voir fields), BAD_IDEMPOTENCY_KEY |
| 401 | La clé est absente, erronée ou révoquée | UNAUTHENTICATED |
| 403 | La clé n'a pas l'autorisation | PERMISSION_DENIED |
| 404 | Introuvable dans votre espace de travail (les objets d'autres espaces de travail apparaissent comme inexistants) | NOT_FOUND |
| 409 | Conflits | IDEMPOTENCY_KEY_REUSED, IDEMPOTENCY_KEY_IN_USE, INVALID_TRANSITION |
| 402 / 422 | Limites d'offre et règles métier | QUOTA_EXCEEDED, REFUSED (le message en donne la raison) |
| 429 | Trop de requêtes | RATE_LIMITED |
| 5xx | Un problème de notre côté | toujours INTERNAL, avec l'identifiant de requête. Si cela persiste, écrivez à support@onetype.ai en indiquant l'identifiant de requête |
code : ces valeurs sont stables. Fondez votre gestion sur elles, et non sur message.
Limites de débit
Par clé : 100 requêtes toutes les 10 secondes, et 20 messages de chat toutes les 10 secondes. Des limites plus élevées accompagnent les offres supérieures. Chaque réponse comporte :
RateLimit-Limit: 100
RateLimit-Remaining: 87
RateLimit-Reset: 6Une réponse 429 comporte aussi Retry-After (secondes). Attendez ce délai, puis réessayez. Ne réessayez pas en boucle serrée.
L'échec d'authentification est limité par adresse réseau. Les requêtes avec une clé erronée ou révoquée comptent pour l'adresse d'où elles viennent. Si de nombreux clients partagent une même adresse publique (un NAT d'entreprise, un fournisseur de CI), un seul client mal configuré peut épuiser le quota, et alors même les requêtes avec une clé valide depuis cette adresse reçoivent 429 RATE_LIMITED jusqu'à la réinitialisation de la fenêtre. Traitez-le comme tout 429 : respectez Retry-After, puis corrigez le client qui envoie la mauvaise clé.
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);
}Discuter depuis votre backend
Créez une conversation pour un agent, puis envoyez-y des messages. Chaque réponse est rédigée, enregistrée et facturée exactement comme une réponse du 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": [ … ], … }Les parts de la réponse contiennent des parties text et une partie source-document pour chaque source citée (title et url pour les pages web).
Streaming
Envoyez "stream": true pour recevoir la réponse au fur et à mesure de sa rédaction, sous forme d'événements envoyés par le serveur, au format AI SDK UI Message Stream v1 ; la réponse porte x-vercel-ai-ui-message-stream: v1, et le champ data de chaque événement est une partie JSON : start, text-start, text-delta (avec delta), text-end, source-document, finish (avec messageMetadata.outcome), error ou abort. Le flux se termine par 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}`);
}
}Avec le Vercel AI SDK sur votre propre serveur, vous pouvez transmettre la réponse telle quelle à useChat, car c'est le même format.
- Se déconnecter n'annule pas la réponse. La réponse est tout de même rédigée, enregistrée et facturée.
- Relancer un flux terminé est sans risque. Réessayez avec le même
Idempotency-Keyet vous obtenez la réponse enregistrée en JSON (statut 200), pas une seconde réponse.
Gestion des versions
/v1 n'évolue que par ajout : nouveaux champs, nouveaux points de terminaison, nouveaux types d'événements. Votre code doit ignorer les champs qu'il ne connaît pas. Si un changement incompatible devient un jour nécessaire, il sera livré sous la forme d'une nouvelle version choisie par clé, avec un préavis.