aethexDocs

SDK TypeScript

SDK TypeScript officiel pour l'API Voice AethexAI. Créez et gérez des agents vocaux, passez des appels téléphoniques, synthétisez la parole, transcrivez l'audio et menez des conversations WebRTC en temps réel depuis Node.js, le navigateur et les runtimes edge.

Installation

Le SDK est publié sous le paquet aethexai sur npm et nécessite Node.js 20+ (pour les API globales fetch, Blob et File) ou tout navigateur / runtime edge moderne. Il fournit des builds ESM + CommonJS avec les types TypeScript. N'installez @roamhq/wrtc que si vous avez besoin du WebRTC temps réel depuis Node.js.

bash
npm install aethexai

Configuration rapide

Importez AethexAI et initialisez-le avec votre clé API. Le SDK utilise l'authentification par clé API pour les appels à l'API Voice ; la connexion par JWT développeur (DeveloperClient) ne sert qu'au compte et à la facturation. La clé peut aussi être lue depuis la variable d'environnement AETHEX_API_KEY.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." }); // or set AETHEX_API_KEY

// Verify the connection by listing available voices.
const voices = await client.listVoices({ limit: 5 });
for (const voice of voices) {
  console.log(voice.id, voice.name);
}

Promises, pas de sync/async

Chaque méthode renvoie une Promise — il n'y a pas de client synchrone et asynchrone séparés. Configurez le client avec baseURL, un timeout par requête en millisecondes et une implémentation fetch personnalisée optionnelle.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({
  apiKey: "ae_live_...",
  baseURL: "https://api.aethexai.com", // default
  timeout: 30_000,                      // ms
});

const page = await client.listAgents({ limit: 20 });
console.log(page.data);

Clients

Le paquet expose trois clients. AethexAI couvre toute la surface authentifiée par clé API (agents, appels, TTS, transcription, conversations, numéros de téléphone, comptes Twilio, usage, uploads, clés API). Kora est un client vocal ciblé. DeveloperClient est authentifié par JWT pour le compte et la facturation.

Kora

Kora est le client orienté voix : agents, appels sortants, voix, TTS, transcription et historique des conversations, sans la surface de gestion de compte. Son constructeur est positionnel — new Kora(baseURL, apiKey) — et createAgent / triggerCall prennent des arguments positionnels pour les champs les plus courants.

typescript
import { Kora } from "aethexai";
import { readFile } from "node:fs/promises";

const kora = new Kora("https://api.aethexai.com", "ae_live_...");

const voices = await kora.listVoices({ limit: 1 });
const agent = await kora.createAgent(
  "Support Agent",
  "You are a helpful customer support agent.",
  voices.at(0)!.id,
  { first_message: "Hi there! How can I help you today?", language: "english" },
);

const bytes = await readFile("recording.wav");
const result = await kora.transcribe(bytes, { language: "english" });
console.log(result.text);

Compte développeur et facturation

Les endpoints de facturation et de compte nécessitent un JWT développeur issu du flux de connexion du tableau de bord, pas une clé API. DeveloperClient porte le jeton bearer et, si un refresh token est fourni, le rafraîchit une fois de façon transparente sur un 401 puis réessaie. Les jetons peuvent être lus depuis AETHEX_DEVELOPER_ACCESS_TOKEN et AETHEX_DEVELOPER_REFRESH_TOKEN.

typescript
import { DeveloperClient } from "aethexai";

const developer = new DeveloperClient({
  accessToken: "eyJhbGciOi...",
  refreshToken: "eyJhbGciOi...", // optional; enables one retry after a 401 refresh
});

const balance = await developer.getBalance();
const plans = await developer.listPlans();
console.log(balance, plans);

Agents

Créez et gérez des agents vocaux, leurs outils et leur base de connaissances. Les méthodes d'écriture renvoient des modèles typés — lisez agent.id, pas agent['id'].

Lister les agents

Lister tous les agents de votre tenant. Retourne un résultat paginé avec .data, .total, .offset et .limit.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const page = await client.listAgents({ limit: 20, offset: 0 });
for (const agent of page) {
  console.log(agent.id, agent.name);
}

Créer un agent

Créer un nouvel agent vocal. Les méthodes d'écriture renvoient des modèles typés ; lisez agent.id, pas agent['id'].

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });
const voices = await client.listVoices({ language: "english", limit: 1 });

const agent = await client.createAgent({
  name: "Support Bot",
  system_prompt: "You are a helpful customer support agent.",
  first_message: "Hi there! How can I help you today?",
  voice_id: voices.at(0)!.id,
  language: "english",
});
console.log(agent.id);

Obtenir un agent

Récupérer un agent par son ID. Retourne un AgentResponse typé — utilisez l'accès par attribut (agent.id, agent.name).

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const agent = await client.getAgent("8a1b2c3d-4e5f-6789-abcd-ef0123456789");
console.log(agent.id, agent.name, agent.voice_id);

Mettre à jour un agent

Mettre à jour un agent existant. Ne passez que les champs que vous souhaitez modifier.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

await client.updateAgent("8a1b2c3d-4e5f-6789-abcd-ef0123456789", {
  name: "Updated Support Bot",
  first_message: "Welcome back!",
});

Supprimer un agent

Supprimer définitivement un agent par son ID.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

await client.deleteAgent("8a1b2c3d-4e5f-6789-abcd-ef0123456789");

Dupliquer un agent

Créer une copie exacte d'un agent existant. Retourne le nouvel agent sous forme d'objet typé.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const clone = await client.duplicateAgent("8a1b2c3d-4e5f-6789-abcd-ef0123456789");
console.log(clone.id);

Ajouter un outil d'agent

Attacher un outil de fonction à un agent. parameters est un objet JSON Schema complet envoyé au LLM. endpoint_url est appelé par le pipeline vocal lorsque le LLM invoque l'outil.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const tool = await client.addAgentTool("8a1b2c3d-4e5f-6789-abcd-ef0123456789", {
  name: "lookup_order",
  description: "Look up an order by ID",
  parameters: {
    type: "object",
    properties: { order_id: { type: "string" } },
    required: ["order_id"],
  },
  endpoint_url: "https://api.example.com/orders",
});
console.log(tool.id);

Lister les outils d'agent

Lister tous les outils attachés à un agent.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const tools = await client.listAgentTools("8a1b2c3d-4e5f-6789-abcd-ef0123456789");
for (const tool of tools) {
  console.log(tool.id, tool.name);
}

Mettre à jour un outil d'agent

Mettre à jour un outil attaché à un agent. Ne passez que les champs que vous souhaitez modifier.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

await client.updateAgentTool(
  "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
  "3c2d1e0f-9a8b-7c6d-5e4f-3a2b1c0d9e8f",
  { description: "Look up an order by its internal ID" },
);

Supprimer un outil d'agent

Supprimer un outil d'un agent.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

await client.deleteAgentTool(
  "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
  "3c2d1e0f-9a8b-7c6d-5e4f-3a2b1c0d9e8f",
);

Téléverser un document de base de connaissances

Téléverser un document directement dans la base de connaissances de l'agent en multipart/form-data.

typescript
import { AethexAI } from "aethexai";
import { readFile } from "node:fs/promises";

const client = new AethexAI({ apiKey: "ae_live_..." });

const bytes = await readFile("faq.pdf");
const doc = await client.uploadKnowledgeDoc("8a1b2c3d-4e5f-6789-abcd-ef0123456789", {
  file: bytes,
  fileName: "faq.pdf",
  mimeType: "application/pdf",
  filename: "faq.pdf", // stored document name
});
console.log(doc.id);

Téléverser un document via URL présignée

Téléversez un document de connaissances via une URL présignée. Appelez presignUpload pour obtenir une URL PUT signée, envoyez (PUT) les octets du fichier avec les en-têtes fournis, puis rattachez-le avec uploadKnowledgeDocByUpload.

typescript
import { AethexAI } from "aethexai";
import { readFile } from "node:fs/promises";

const client = new AethexAI({ apiKey: "ae_live_..." });

const upload = await client.presignUpload({
  kind: "doc/knowledge-base",
  filename: "faq.pdf",
  content_type: "application/pdf",
});
await fetch(upload.upload_url, {
  method: upload.method,
  body: await readFile("faq.pdf"),
  headers: upload.headers,
});

const doc = await client.uploadKnowledgeDocByUpload("8a1b2c3d-4e5f-6789-abcd-ef0123456789", {
  upload_id: upload.upload_id,
  filename: "faq.pdf",
});
console.log(doc.id);

Lister les documents de base de connaissances

Lister tous les documents dans la base de connaissances de l'agent.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const docs = await client.listKnowledgeDocs("8a1b2c3d-4e5f-6789-abcd-ef0123456789");
for (const doc of docs) {
  console.log(doc.id, doc.filename, doc.status);
}

Traiter un document de base de connaissances

Déclencher l'embedding et l'indexation d'un document précédemment téléversé. L'ingestion est asynchrone, donc queryKnowledgeBase peut retourner des résultats vides jusqu'à la fin du traitement.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

await client.processKnowledgeDoc(
  "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
  "b3c4d5e6-7f8a-9b0c-1d2e-3f4a5b6c7d8e",
);

Interroger la base de connaissances

Exécuter une requête de récupération hybride sur la base de connaissances de l'agent. Retourne des chunks classés par RRF ; score est la valeur de pertinence utilisée pour le filtrage, pas le score RRF.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const results = await client.queryKnowledgeBase("8a1b2c3d-4e5f-6789-abcd-ef0123456789", {
  query: "What is the refund policy?",
});
for (const r of results.results) {
  console.log(r.score, r.text);
}

Obtenir les textes de la base de connaissances

Récupérer le texte extrait pour chaque document de la base de connaissances.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const texts = await client.getKnowledgeTexts("8a1b2c3d-4e5f-6789-abcd-ef0123456789");
for (const doc of texts.documents) {
  console.log(doc.text.slice(0, 100), doc.filename);
}

Supprimer un document de base de connaissances

Supprimer un document de la base de connaissances de l'agent.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

await client.deleteKnowledgeDoc(
  "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
  "b3c4d5e6-7f8a-9b0c-1d2e-3f4a5b6c7d8e",
);

Appels

Déclenchez des appels sortants et consultez l'historique des appels. triggerCall passe un véritable appel téléphonique en utilisant le pipeline vocal configuré de l'agent ; le from_number doit être enregistré sur votre tenant.

Lister les appels

Lister tous les enregistrements d'appels de votre tenant avec pagination optionnelle.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const page = await client.listCalls({ limit: 10, offset: 0 });
for (const call of page) {
  console.log(call.id, call.status, call.direction);
}

Créer un enregistrement d'appel

Créer manuellement un enregistrement d'appel sans déclencher un vrai appel. Utile pour journaliser des appels externes.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const call = await client.createCallRecord({
  agent_id: "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
  direction: "inbound",
  from_number: "+14155551234",
  to_number: "+18005550000",
  metadata: { source: "ivr-callback" },
});
console.log(call.id);

Déclencher un appel

Passer un appel téléphonique sortant avec l'agent spécifié. Le from_number doit être enregistré sur votre tenant.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const call = await client.triggerCall({
  agent_id: "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
  to_number: "+14155551234",
  from_number: "+18005550000",
  metadata: { customer_id: "cu_42" },
});
console.log(call.id, call.status);

Appels en lot

Déclencher plusieurs appels sortants en une seule requête. Chaque destinataire peut avoir des variables individuelles pour l'interpolation des prompts.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const batch = await client.batchCalls({
  agent_id: "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
  recipients: [
    { to_number: "+14155551234", from_number: "+18005550000", variables: { customer_name: "Alice" } },
    { to_number: "+14155555678", from_number: "+18005550000", variables: { customer_name: "Bob" } },
  ],
  name: "Spring launch",
});
console.log(batch.batch_id, batch.status, batch.total);

Obtenir un lot d'appels

Récupérer le statut et la progression d'un job d'appels en lot.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const batch = await client.getCallBatch("5e6f7a8b-9c0d-1e2f-3a4b-5c6d7e8f9a0b");
console.log(batch.status, batch.completed, batch.failed, batch.total);

Obtenir un appel

Récupérer un enregistrement d'appel par son ID. Retourne un CallResponse typé.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const call = await client.getCall("c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f");
console.log(call.status, call.duration_seconds);

Obtenir le statut d'un appel

Interroger le statut en direct d'un appel par son ID. Retourne un CallStatusResponse typé.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const status = await client.getCallStatus("c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f");
console.log(status.status);

Conversation (WebRTC)

Signalisation bas niveau pour les sessions vocales WebRTC en direct. La plupart des applications devraient utiliser l'assistant Conversation (voir Conversations temps réel), qui effectue ce handshake connect → offer → ICE pour vous. N'utilisez ces méthodes directement que pour un transport personnalisé.

Connexion

Créer une nouvelle session WebRTC. Retourne session_id et la configuration ICE.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const session = await client.conversationConnect({ agent_id: "8a1b2c3d-4e5f-6789-abcd-ef0123456789" });
console.log(session.session_id, session.ice_config);

Envoyer une offre

Soumettre le SDP d'offre WebRTC. Retourne le SDP de réponse du serveur.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const answer = await client.sendOffer("3f2a7b1c-8d4e-4a5b-9c2d-1e0f3a4b5c6d", {
  sdp: "v=0\r\no=- ...\r\n",
  type: "offer",
});
console.log(answer.sdp, answer.pc_id); // pc_id identifies the peer connection for ICE

Envoyer un candidat ICE

Relayer les candidats ICE au serveur pour compléter la configuration de la connexion pair-à-pair.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

// pc_id is the peer-connection id returned by sendOffer, not the session id.
const answer = await client.sendOffer("3f2a7b1c-8d4e-4a5b-9c2d-1e0f3a4b5c6d", {
  sdp: "v=0\r\no=- ...\r\n",
  type: "offer",
});

await client.sendIceCandidate("3f2a7b1c-8d4e-4a5b-9c2d-1e0f3a4b5c6d", {
  pc_id: answer.pc_id,
  candidates: [
    { candidate: "candidate:842163049 1 udp 1677729535 ...", sdp_mid: "0", sdp_mline_index: 0 },
  ],
});

Obtenir le statut de la session

Interroger le statut et les métriques d'une session WebRTC active.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const status = await client.getConversationSessionStatus("3f2a7b1c-8d4e-4a5b-9c2d-1e0f3a4b5c6d");
console.log(status.status, status.duration_s, status.turn_count);

Terminer la session

Terminer une session de conversation WebRTC active.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

await client.endConversationSession("3f2a7b1c-8d4e-4a5b-9c2d-1e0f3a4b5c6d");

Envoyer le résultat d'un outil

Retourner le résultat d'un appel d'outil à l'agent pendant une session active.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

await client.sendToolResult("3f2a7b1c-8d4e-4a5b-9c2d-1e0f3a4b5c6d", {
  tool_call_id: "call_abc123",
  result: JSON.stringify({ order_status: "shipped" }),
});

Conversations

Consultez les enregistrements de conversations terminées : lister, rechercher, récupérer les transcriptions et télécharger ou diffuser l'audio.

Lister les conversations

Lister les enregistrements de conversations terminées avec pagination optionnelle.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const page = await client.listConversations({ limit: 10, offset: 0 });
for (const conv of page) {
  console.log(conv.id, conv.status, conv.total_duration_ms);
}

Rechercher des conversations

Recherche plein texte dans les transcriptions de conversations.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const response = await client.searchConversations("refund policy", { limit: 10 });
for (const hit of response.results) {
  console.log(hit.conversation_id, hit.text);
}

Obtenir une conversation

Récupérer un enregistrement de conversation. Retourne un ConversationResponse typé.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const conv = await client.getConversation("c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f");
console.log(conv.id, conv.status, conv.total_duration_ms);

Obtenir la transcription

Récupérer la transcription tour par tour d'une conversation. Retourne un tableau d'éléments ConversationTurnResponse typés.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const turns = await client.getTranscript("c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f");
for (const turn of turns) {
  console.log(`${turn.role}: ${turn.text}`);
}

Obtenir l'URL audio

Obtenir une URL signée de courte durée vers l'enregistrement audio de la conversation.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const audio = await client.getAudio("c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f");
console.log(audio.url, audio.format, audio.expires_in);

Obtenir les octets audio

Télécharger l'enregistrement audio de la conversation en octets bruts via le client Kora.

typescript
import { Kora } from "aethexai";
import { writeFile } from "node:fs/promises";

const kora = new Kora("https://api.aethexai.com", "ae_live_...");

const audio = await kora.getConversationAudio("c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f");
await writeFile("conversation.wav", audio); // Uint8Array

Révoquer le token audio

Révoquer un token de lecture audio précédemment émis pour empêcher tout accès ultérieur.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

// Mint a URL, then extract its token to revoke it.
const audio = await client.getAudio("c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f");
const token = new URL(audio.url).searchParams.get("token")!;

await client.revokeAudioToken("c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f", { token });

Soumettre un avis

Attacher une note de qualité et un commentaire optionnel à une conversation.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

await client.submitFeedback("c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f", {
  rating: 5,
  comment: "Resolved my issue quickly.",
});

Transcription

Transcrivez l'audio de façon synchrone ou en tâches asynchrones, en ligne ou depuis un upload présigné.

Transcrire (synchrone)

Transcrire l'audio de manière synchrone via le client Kora. Bloque jusqu'à ce que le résultat soit prêt.

typescript
import { Kora } from "aethexai";
import { readFile } from "node:fs/promises";

const kora = new Kora("https://api.aethexai.com", "ae_live_...");

const bytes = await readFile("recording.wav");
const result = await kora.transcribe(bytes, { language: "english" });
console.log(result.text);

Transcrire (asynchrone)

Soumettre l'audio pour une transcription asynchrone. Retourne un ID de job à interroger.

typescript
import { Kora } from "aethexai";
import { readFile } from "node:fs/promises";

const kora = new Kora("https://api.aethexai.com", "ae_live_...");

const bytes = await readFile("long_recording.wav");
const job = await kora.transcribeAsync(bytes, {
  language: "english",
  webhookUrl: "https://example.com/webhooks/transcription",
});
console.log(job.id, job.status);

Transcrire via upload

Transcrire de l'audio précédemment téléversé via une URL présignée. Synchrone.

typescript
import { AethexAI } from "aethexai";
import { readFile } from "node:fs/promises";

const client = new AethexAI({ apiKey: "ae_live_..." });

const upload = await client.presignUpload({ kind: "audio/transcribe", filename: "recording.wav", content_type: "audio/wav" });
await fetch(upload.upload_url, { method: upload.method, body: await readFile("recording.wav"), headers: upload.headers });

const result = await client.transcribeAudioByUpload({ upload_id: upload.upload_id, language: "english" });
console.log(result.text);

Transcrire async via upload

Soumettre un audio téléversé via URL présignée pour une transcription asynchrone avec livraison par webhook.

typescript
import { AethexAI } from "aethexai";
import { readFile } from "node:fs/promises";

const client = new AethexAI({ apiKey: "ae_live_..." });

const upload = await client.presignUpload({ kind: "audio/transcribe", filename: "long_recording.wav", content_type: "audio/wav" });
await fetch(upload.upload_url, { method: upload.method, body: await readFile("long_recording.wav"), headers: upload.headers });

const job = await client.transcribeAudioAsyncByUpload({
  upload_id: upload.upload_id,
  language: "english",
  webhook_url: "https://example.com/webhooks/transcription",
});
console.log(job.id, job.status);

Obtenir un job de transcription

Interroger le statut d'un job de transcription asynchrone. Retourne le résultat quand le statut est completed.

typescript
import { Kora } from "aethexai";

const kora = new Kora("https://api.aethexai.com", "ae_live_...");

const job = await kora.getTranscribeJob("a1c4e7d2-5b9f-4e83-8c1a-7e0b9d4f2a16");
console.log(job.status, job.status === "completed" ? job.text : job.error_message);

Annuler un job de transcription

Annuler un job de transcription asynchrone en attente ou en cours.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

await client.cancelTranscriptionJob("a1c4e7d2-5b9f-4e83-8c1a-7e0b9d4f2a16");

Synthèse vocale

Synthétisez la parole en octets audio, diffusez-la morceau par morceau ou soumettez des lots.

Synthétiser la parole

Convertir jusqu'à 650 caractères de texte en fichier audio WAV complet. Le header est inclus, donc le fichier est lisible tel quel.

typescript
import { AethexAI } from "aethexai";
import { writeFile } from "node:fs/promises";

const client = new AethexAI({ apiKey: "ae_live_..." });
const voices = await client.listVoices({ language: "english", limit: 1 });

const audio = await client.synthesizeSpeech({
  text: "Hello, welcome to AethexAI!",
  voice_id: voices.at(0)!.id,
  language: "english",
});
await writeFile("output.wav", audio); // Uint8Array

Streamer la parole

Streamer jusqu'à 650 caractères de parole en chunks PCM mono 16 bits bruts à 24 kHz pour un temps jusqu'au premier octet réduit.

typescript
import { AethexAI } from "aethexai";
import { createWriteStream } from "node:fs";

const client = new AethexAI({ apiKey: "ae_live_..." });
const voices = await client.listVoices({ language: "english", limit: 1 });

const out = createWriteStream("output.pcm");
for await (const chunk of client.streamSpeech({
  text: "Streaming hello.",
  voice_id: voices.at(0)!.id,
  language: "english",
})) {
  out.write(chunk); // PCM16 @ 24kHz (Uint8Array)
}
out.end();

Synthèse en lot

Soumettre une liste de textes pour une synthèse vocale asynchrone avec livraison par webhook. Chaque élément peut contenir jusqu'à 3000 caractères ; la plateforme découpe les éléments longs en chunks backend sûrs et retourne un WAV par élément.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const batch = await client.batchSynthesize({
  language: "english",
  items: [{ text: "First message." }, { text: "Second message." }],
  webhook_url: "https://example.com/webhooks/tts",
});
console.log(batch.batch_id, batch.status, batch.total);

Obtenir un lot TTS

Récupérer le statut et les résultats par élément d'un job de lot TTS.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const batch = await client.getTtsBatch("8e7d6c5b-4a3b-2c1d-0e9f-8a7b6c5d4e3f");
console.log(batch.status, batch.completed, batch.failed, batch.total);
for (const item of batch.results) {
  console.log(item.index, item.status, item.audio_url);
}

Voix

Parcourez le catalogue de voix et générez de courts aperçus.

Lister les voix

Lister toutes les voix disponibles pour votre tenant avec filtre de langue optionnel et pagination.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const voices = await client.listVoices({ language: "english", limit: 20 });
for (const v of voices) {
  console.log(v.id, v.name, v.language);
}

Obtenir une voix

Récupérer une voix par son ID ou son nom.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });
const voices = await client.listVoices({ language: "english", limit: 1 });

const voice = await client.getVoice(voices.at(0)!.id);
console.log(voice.id, voice.name, voice.supports_dialect_style);

Prévisualiser une voix

Générer un court clip audio pour prévisualiser une voix.

typescript
import { AethexAI } from "aethexai";
import { writeFile } from "node:fs/promises";

const client = new AethexAI({ apiKey: "ae_live_..." });
const voices = await client.listVoices({ language: "english", limit: 1 });

const preview = await client.previewVoice({
  voice_id: voices.at(0)!.id,
  text: "Welcome to Aethex AI.",
});
await writeFile("preview.wav", preview); // Uint8Array

Numéros de téléphone

Provisionnez et configurez des numéros de téléphone via Twilio ou SIP, et définissez le routage entrant.

Lister les numéros de téléphone

Lister tous les numéros de téléphone enregistrés sur votre tenant.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const page = await client.listPhoneNumbers({ limit: 20, offset: 0 });
for (const number of page) {
  console.log(number.id, number.phone_number, number.provider);
}

Enregistrer un numéro Twilio

Lier un numéro de téléphone Twilio à un agent pour les appels entrants et sortants.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const number = await client.registerTwilioPhoneNumber({
  twilio_account_id: "0a1b2c3d-4e5f-6789-abcd-ef0123456789",
  phone_number: "+18005550000",
  agent_id: "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
  friendly_name: "Sales line",
});
console.log(number.id);

Enregistrer un numéro SIP

Lier un numéro de téléphone de trunk SIP à un agent.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const number = await client.registerSipPhoneNumber({
  phone_number: "+18005550000",
  trunk_id: "2a4b6c8d-1e3f-5a7b-9c0d-2e4f6a8b0c1d",
  agent_id: "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
  friendly_name: "Inbound support",
});
console.log(number.id);

Obtenir un numéro de téléphone

Récupérer un enregistrement de numéro de téléphone par son ID.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const number = await client.getPhoneNumber("9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d");
console.log(number);

Mettre à jour un numéro de téléphone

Mettre à jour l'agent assigné ou la configuration d'un numéro de téléphone enregistré.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

await client.updatePhoneNumber("9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d", {
  agent_id: "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
});

Libérer un numéro de téléphone

Supprimer un numéro de téléphone enregistré de votre tenant.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

await client.releasePhoneNumber("9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d");

Définir le routage d'un numéro

Configurer le routage de secours pour un numéro de téléphone (ex. transfert en cas de non-réponse).

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

await client.setPhoneNumberRouting("9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d", {
  fallback_action: "forward",
  fallback_number: "+18005550000",
  max_ring_seconds: 30,
});

Comptes Twilio

Connectez et gérez vos propres comptes Twilio (Bring-Your-Own).

Enregistrer un compte Twilio

Connecter un compte Twilio à votre tenant AethexAI en utilisant un Account SID et un Auth Token.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const account = await client.registerTwilioAccount({
  account_sid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  auth_token: "your_twilio_auth_token",
  friendly_name: "Production Twilio",
});
console.log(account.id);

Lister les comptes Twilio

Lister tous les comptes Twilio enregistrés sur votre tenant.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const page = await client.listTwilioAccounts({ limit: 20, offset: 0 });
for (const acct of page) {
  console.log(acct.id, acct.friendly_name);
}

Obtenir un compte Twilio

Récupérer un enregistrement de compte Twilio par son ID.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const account = await client.getTwilioAccount("0a1b2c3d-4e5f-6789-abcd-ef0123456789");
console.log(account);

Libérer un compte Twilio

Déconnecter un compte Twilio de votre tenant.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

await client.releaseTwilioAccount("0a1b2c3d-4e5f-6789-abcd-ef0123456789");

Enregistrements

Listez, récupérez, téléchargez et supprimez les enregistrements d'appels.

Lister les enregistrements

Lister tous les enregistrements de votre tenant avec pagination optionnelle.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const page = await client.listRecordings({ limit: 10, offset: 0 });
for (const rec of page) {
  console.log(rec.id, rec.duration_seconds);
}

Obtenir un enregistrement

Récupérer un enregistrement par son ID.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const rec = await client.getRecording("5e4f3a2b-1c0d-9e8f-7a6b-5c4d3e2f1a0b");
console.log(rec);

Obtenir l'audio d'un enregistrement

Obtenir une URL signée vers l'audio de l'enregistrement et le télécharger.

typescript
import { AethexAI } from "aethexai";
import { writeFile } from "node:fs/promises";

const client = new AethexAI({ apiKey: "ae_live_..." });

const result = await client.getRecordingAudio("5e4f3a2b-1c0d-9e8f-7a6b-5c4d3e2f1a0b");
const audio = new Uint8Array(await (await fetch(result.url)).arrayBuffer());
await writeFile("recording.wav", audio);

Supprimer un enregistrement

Supprimer définitivement un enregistrement.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

await client.deleteRecording("5e4f3a2b-1c0d-9e8f-7a6b-5c4d3e2f1a0b");

Modèles

Listez les modèles LLM et vocaux disponibles pour votre tenant.

Lister les modèles

Lister tous les modèles, avec une option includeUnavailable.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const models = await client.listModels({ includeUnavailable: false });
for (const model of models) {
  console.log(model.id, model.provider, model.available);
}

Téléversements

Demandez des URL présignées pour téléverser directement des fichiers (documents de base de connaissances, audio à transcrire).

Présigner un upload

Demandez une URL présignée pour téléverser un fichier. Envoyez (PUT) les octets vers upload_url avec les en-têtes fournis, puis passez upload_id à l'endpoint by-upload qui le consomme.

typescript
import { AethexAI } from "aethexai";
import { readFile } from "node:fs/promises";

const client = new AethexAI({ apiKey: "ae_live_..." });

const upload = await client.presignUpload({
  kind: "doc/knowledge-base",
  filename: "faq.pdf",
  content_type: "application/pdf",
});

await fetch(upload.upload_url, {
  method: upload.method,
  body: await readFile("faq.pdf"),
  headers: upload.headers,
});
console.log(upload.upload_id);

Utilisation et facturation

Consultez l'usage et les résumés de période de facturation, et gérez les déclencheurs d'usage (abonnements webhook) et leurs livraisons.

Obtenir l'utilisation

Récupérer les compteurs d'utilisation bruts de votre tenant.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const usage = await client.getUsage();
console.log(usage);

Obtenir le résumé d'utilisation

Récupérer le résumé d'utilisation agrégé pour la période de facturation en cours.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const summary = await client.getUsageSummary();
console.log(summary);

Obtenir l'utilisation quotidienne

Récupérer l'utilisation jour par jour pour les N derniers jours.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

for (const day of await client.getDailyUsage({ days: 30 })) {
  console.log(day.date, day.count, day.total_tokens, day.voice_seconds);
}

Obtenir l'utilisation mensuelle

Récupérer l'historique d'utilisation mois par mois.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

for (const month of await client.getMonthlyUsage()) {
  console.log(month.month, month.count, month.total_tokens, month.voice_seconds);
}

Créer un déclencheur

Configurer un déclencheur de seuil d'utilisation qui envoie un webhook quand le seuil est dépassé.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const trigger = await client.createTrigger({
  resource_type: "voice_call",
  threshold_value: "180000", // string preserves precision; server parses to Decimal
  threshold_type: "count",
  period: "monthly",
  event_callback_url: "https://example.com/webhooks/usage",
});
console.log(trigger.id);

Lister les déclencheurs

Lister tous les déclencheurs de seuil d'utilisation de votre tenant.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

for (const trigger of await client.listTriggers()) {
  console.log(trigger.id, trigger.resource_type, trigger.threshold_value, trigger.is_active);
}

Mettre à jour un déclencheur

Mettre à jour le seuil ou la configuration d'un déclencheur existant.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

await client.updateTrigger("4d5e6f7a-8b9c-0d1e-2f3a-4b5c6d7e8f9a", {
  threshold_value: "250000",
});

Faire pivoter le secret webhook

Faire pivoter le secret webhook partagé pour la livraison des déclencheurs. L'appel SDK fait pivoter le secret mais ne retourne pas sa valeur ; si vous avez besoin de récupérer le nouveau secret, envoyez plutôt la requête HTTP brute, qui le retourne dans la réponse. Chaque appel fait pivoter et révoque le secret précédent, utilisez donc l'une ou l'autre approche.

Lister les déclenchements

Récupérer l'historique de livraison d'un déclencheur.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

const firings = await client.listTriggerFirings("4d5e6f7a-8b9c-0d1e-2f3a-4b5c6d7e8f9a", { limit: 50 });
for (const firing of firings) {
  console.log(firing.id, firing.fired_at, firing.delivery_status, firing.attempt_count);
}

Relancer un déclenchement

Réessayer la livraison d'un déclenchement précédemment échoué.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

await client.redeliverFiring(
  "4d5e6f7a-8b9c-0d1e-2f3a-4b5c6d7e8f9a",
  "7c6d5e4f-3a2b-1c0d-9e8f-7a6b5c4d3e2f",
);

Pagination

Les méthodes de liste renvoient une page unique PaginatedResponse. Elle est itérable, possède un .length, prend en charge .at(i) et expose .hasMore — bouclez tant que .hasMore pour parcourir toutes les pages.

typescript
import { AethexAI } from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

let offset = 0;
const limit = 50;
for (;;) {
  const page = await client.listCalls({ offset, limit });
  for (const call of page) console.log(call.id);
  if (!page.hasMore) break;
  offset += limit;
}

Conversations temps réel

Conversations WebRTC full-duplex avec le même pipeline vocal que vos utilisateurs obtiennent depuis le tableau de bord. L'assistant Conversation orienté navigateur (aethexai/realtime) effectue tout le handshake connect → offer → ICE, capture le microphone, joue l'audio de l'agent et expose les transcriptions et les appels d'outils sous forme d'événements typés.

Attention
N'envoyez jamais une clé API de tenant (ae_live...) à un navigateur non fiable. N'importe qui peut la lire depuis votre page et appeler l'API en votre nom. Pour les applications web publiques, faites transiter la signalisation connect et offer par votre propre backend (comme le montre le démarrage rapide WebRTC) afin que la clé reste côté serveur ; la clé en ligne ci-dessous ne sert qu'à un usage interne (first-party) ou côté serveur. L'assistant Conversation exécute la signalisation WebRTC pour vous, vous n'appelez donc jamais conversationConnect, sendOffer ni sendIceCandidate vous-même. Dans un navigateur il utilise le WebRTC natif ; en Node.js, passez l'adaptateur @roamhq/wrtc (voir ci-dessous). Le microphone nécessite un contexte sécurisé (https ou localhost) et une interaction utilisateur.
typescript
import { AethexAI } from "aethexai";
import { Conversation } from "aethexai/realtime";

// In an untrusted browser, never embed ae_live directly: configure the client
// with a custom fetch that proxies signalling through your backend (see Quickstart).
const client = new AethexAI({ apiKey: "ae_live_..." });
const convo = new Conversation(client, { agentId: "8a1b2c3d-4e5f-6789-abcd-ef0123456789" });

convo.on("agentText", (text) => console.log("agent:", text));
convo.on("userTranscript", (text) => console.log("user:", text));
convo.on("statusChange", (status) => console.log(status)); // connecting → connected → closed
convo.on("toolCall", async (call) => {
  await convo.sendToolResult(call.id, JSON.stringify({ ok: true }));
});

await convo.start(); // prompts for mic, runs the WebRTC handshake, resolves when connected
// ... the agent's audio plays automatically ...
await convo.end();

Temps réel en Node.js

Node n'a pas de WebRTC natif : installez la dépendance pair optionnelle @roamhq/wrtc et reliez-la avec createNodeWebRTC. Par défaut elle attache un microphone silencieux (pour qu'un appel se connecte lors d'un test de connectivité) ; envoyez du vrai PCM avec node.pushPcm et recevez les trames audio de l'agent avec createAudioSink.

typescript
import { AethexAI } from "aethexai";
import { Conversation } from "aethexai/realtime";
import { createNodeWebRTC, createAudioSink } from "aethexai/realtime/node";

const client = new AethexAI({ apiKey: "ae_live_..." });
const node = await createNodeWebRTC(); // synthetic mic (silence by default)
const convo = new Conversation(client, {
  agentId: "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
  ...node.conversationOptions,
});

convo.on("agentText", (t) => console.log("agent:", t));
convo.on("track", async (track) => {
  await createAudioSink(track, (frame) => {
    /* frame.samples is Int16 PCM at frame.sampleRate */
  });
});

await convo.start();
// node.pushPcm(int16Frame) to stream real mic audio (10ms frames at the sample rate)
await convo.end();
node.close();

Types TypeScript

Les types de modèles de requête et de réponse générés sont exportés sous l'espace de noms Aethex pour un typage avancé.

typescript
import type { Aethex } from "aethexai";

function summarize(agent: Aethex.AgentResponse): string {
  return `${agent.name} (${agent.id})`;
}

Gestion des erreurs

Les réponses non-2xx rejettent avec des erreurs typées ; les échecs de transport et de timeout sont mappés sur APIConnectionError / APITimeoutError. Toutes les erreurs héritent de AethexError, et les erreurs dérivées du statut étendent APIStatusError qui porte message, code, statusCode, response et headers. RateLimitError expose retryAfter.

typescript
import {
  AethexAI,
  AethexError,
  APIStatusError,
  AuthenticationError,
  NotFoundError,
  RateLimitError,
  ValidationError,
} from "aethexai";

const client = new AethexAI({ apiKey: "ae_live_..." });

try {
  const agent = await client.getAgent("00000000-0000-0000-0000-000000000000");
} catch (err) {
  if (err instanceof NotFoundError) console.log("Agent not found");
  else if (err instanceof AuthenticationError) console.log("Invalid API key");
  else if (err instanceof RateLimitError) console.log(`Rate limited. Retry after ${err.retryAfter}s`);
  else if (err instanceof ValidationError) console.log("Invalid request:", err.message);
  else if (err instanceof APIStatusError) console.log(`API error ${err.statusCode}: ${err.message}`);
  else if (err instanceof AethexError) console.log("SDK error:", err.message);
  else throw err;
}