Référence API
Qorami est un point de contrôle entre vos agents IA et l'envoi réel d'emails.
Avant chaque envoi, l'agent appelle Qorami, qui répond : envoyer,
faire valider par un humain, ou ne pas envoyer.
English version →
Authentification
Toutes les requêtes utilisent votre clé API workspace dans l'en-tête
x-qorami-api-key. Récupérez-la dans votre
espace client (panneau « Démarrer »).
x-qorami-api-key: VOTRE_CLE
Vérifier un email POST /api/verify-email
L'appel principal : l'agent soumet l'email avant de l'envoyer.
Requête
| Champ | Type | Description |
|---|---|---|
recipient | string | Destinataire de l'email. |
subject | string | Objet. |
body | string | Corps de l'email. |
policyProfile | string | general, sales, support ou legal-finance. |
idempotencyKey | string | Optionnel : rejoue le même résultat sans re-facturer. |
Réponse — le contrat agent
Obéissez à nextAction.type :
nextAction.type | Ce que fait l'agent |
|---|---|
send | Envoyer l'email. |
request_human_confirmation | Mettre en pause : un humain doit valider (notifié par email + espace client). |
do_not_send | Ne pas envoyer en l'état. |
Exemple — curl
curl -X POST https://qorami.fr/api/verify-email \
-H "x-qorami-api-key: VOTRE_CLE" \
-H "content-type: application/json" \
-d '{
"recipient": "client@example.com",
"subject": "Notre offre",
"body": "Bonjour, voici notre proposition...",
"policyProfile": "sales"
}'
Exemple — JavaScript
const res = await fetch("https://qorami.fr/api/verify-email", {
method: "POST",
headers: {
"x-qorami-api-key": process.env.QORAMI_API_KEY,
"content-type": "application/json",
},
body: JSON.stringify({
recipient: "client@example.com",
subject: "Notre offre",
body: emailBody,
policyProfile: "sales",
}),
});
const { nextAction, action } = await res.json();
if (nextAction.type === "send") {
await sendEmail(); // autorisé
} else if (nextAction.type === "request_human_confirmation") {
// mettez en file, puis interrogez le statut (voir ci-dessous)
} // sinon do_not_send : on n'envoie pas
Exemple — Python
import os, requests
res = requests.post(
"https://qorami.fr/api/verify-email",
headers={"x-qorami-api-key": os.environ["QORAMI_API_KEY"]},
json={
"recipient": "client@example.com",
"subject": "Notre offre",
"body": email_body,
"policyProfile": "sales",
},
)
data = res.json()
if data["nextAction"]["type"] == "send":
send_email() # autorisé
Remédiation (que corriger)
En plus de reasons (pourquoi), la réponse renvoie
verification.suggestions : des correctifs concrets pour rendre
l'email envoyable. L'agent peut corriger et re-vérifier.
"verification": { "decision": "Bloque", "concerns": ["secret_leak"],
"suggestions": ["Retirez la clé API du corps", "Envoyez la clé via un coffre à secrets"] }
Mode test (dry-run)
Ajoutez "dryRun": true pour obtenir la décision sans consommer de crédit ni enregistrer d'action — idéal pour tester votre politique/intégration.
curl -X POST https://qorami.fr/api/verify-email \
-H "x-qorami-api-key: VOTRE_CLE" -H "content-type: application/json" \
-d '{"recipient":"a@b.com","subject":"Test","body":"...","dryRun":true}'
# -> { "dryRun": true, "verification": {...}, "nextAction": {...} } (0 crédit)
Vérification par lot POST /api/verify-email/batch
Vérifiez jusqu'à 20 emails en un appel et obtenez une décision par item (aperçu, sans débit ni persistance).
curl -X POST https://qorami.fr/api/verify-email/batch \
-H "x-qorami-api-key: VOTRE_CLE" -H "content-type: application/json" \
-d '{"items":[{"recipient":"a@b.com","subject":"Hi","body":"..."}, ...]}'
# -> { "count": N, "summary": {...}, "results": [{ "decision": "...", "nextAction": {...} }, ...] }
Découvrir les règles GET /api/policy
L'agent peut lire les règles actives de son workspace pour s'adapter avant d'envoyer (profils + seuils, termes bloqués/à valider, contrat de décision, coût en crédits).
curl https://qorami.fr/api/policy -H "x-qorami-api-key: VOTRE_CLE"
# -> { "profiles": [{ "id":"sales", "reviewThreshold":30, "blockThreshold":70 }, ...],
# "policy": { "contentRules": { "blockedTerms": [...], "reviewTerms": [...] } },
# "decisionContract": { "send": "...", "request_human_confirmation": "...", "do_not_send": "..." },
# "credits": { "costPerVerification": 1, "dryRunCost": 0 } }
Suivre une validation humaine GET /api/email-actions/:id
Quand nextAction.type vaut request_human_confirmation,
interrogez cet endpoint pour savoir si un humain a validé. Le champ
nextAction renvoie send une fois approuvé,
do_not_send si bloqué, ou reste en attente.
curl https://qorami.fr/api/email-actions/ACTION_ID \
-H "x-qorami-api-key: VOTRE_CLE"
# -> { "action": { "status": "Authorized", ... },
# "nextAction": { "type": "send", ... } }
Gestion des erreurs et intégration robuste
Pour un fonctionnement autonome et résilient de votre flotte d'agents, gérez les cas d'erreur de facturation, de limites de taux (rate limit), et de validation en suivant ces recommandations :
| HTTP | Code d'erreur | Description et traitement recommandé |
|---|---|---|
402 |
insufficient_credits |
Le compte n'a plus de crédits. L'agent doit suspendre l'envoi et alerter l'administrateur (pensez à activer le rechargement automatique dans votre espace client). |
429 |
rate_limited |
Limite d'appels atteinte. L'agent doit lire l'en-tête Retry-After et retenter après le délai spécifié. |
403 |
insufficient_scope |
La clé API n'a pas le droit d'effectuer cette action (par ex. une clé verify qui tente d'approuver ou de bloquer). |
422 |
validation_error |
Le payload est mal formé ou invalide. Ne pas ré-essayer sans correction préalable. |
Exemple de boucle d'intégration complète (JavaScript)
// 1. Appel de vérification initial
async function guardEmail(email) {
try {
const res = await fetch("https://qorami.fr/api/verify-email", {
method: "POST",
headers: {
"x-qorami-api-key": process.env.QORAMI_API_KEY,
"content-type": "application/json",
},
body: JSON.stringify(email)
});
if (res.status === 402) {
console.error("Crédits insuffisants. Envoi suspendu.");
return { status: "insufficient_credits" };
}
if (res.status === 429) {
const retryAfter = parseInt(res.headers.get("retry-after") || "60", 10);
console.warn(`Limite de taux atteinte. Attente de ${retryAfter}s...`);
await new Promise(r => setTimeout(r, retryAfter * 1000));
return guardEmail(email); // Ré-essai après délai
}
if (!res.ok) {
const error = await res.json();
console.error(`Erreur d'intégration (${res.status}):`, error);
return { status: "error", error };
}
const { nextAction, action } = await res.json();
if (nextAction.type === "send") {
return { status: "send" }; // Autorisé : envoyer l'email
}
if (nextAction.type === "request_human_confirmation") {
// 2. Validation humaine requise (polling)
console.log(`Action ${action.id} en attente. Début de l'interrogation...`);
return pollActionStatus(action.id);
}
return { status: "blocked" }; // do_not_send
} catch (err) {
console.error("Erreur réseau ou appel API :", err);
return { status: "error", err };
}
}
// 3. Boucle d'interrogation du statut (Polling)
async function pollActionStatus(actionId) {
const maxAttempts = 10;
for (let attempt = 0; attempt < maxAttempts; attempt++) {
await new Promise(r => setTimeout(r, 30000)); // Attendre 30 secondes
try {
const res = await fetch(`https://qorami.fr/api/email-actions/${actionId}`, {
headers: { "x-qorami-api-key": process.env.QORAMI_API_KEY }
});
if (res.ok) {
const { nextAction } = await res.json();
if (nextAction.type === "send") return { status: "send" };
if (nextAction.type === "do_not_send") return { status: "blocked" };
}
} catch (e) {
console.warn("Échec de l'appel d'interrogation de statut...", e);
}
}
return { status: "timeout" }; // Expiration sans validation humaine
}
Webhooks (push) POST /api/workspace/webhook
Plutôt que d'interroger le statut en boucle, recevez une notification dès qu'un humain valide ou bloque. Configurez une URL (authentifié, propriétaire) :
curl -X POST https://qorami.fr/api/workspace/webhook \
-H "x-qorami-api-key: VOTRE_CLE" \
-H "content-type: application/json" \
-d '{"url":"https://votre-app.com/qorami-webhook"}'
# -> { "configured": true, "url": "...", "secret": "qwh_..." } (secret affiché une seule fois)
Qorami envoie alors un POST signé à chaque résolution. type vaut
action.confirmed (l'agent peut envoyer) ou action.blocked.
L'URL doit être en https et publique.
// corps reçu
{ "type": "action.confirmed", "workspaceId": "...", "sentAt": "...",
"action": { "id": "act_...", "status": "Authorized", "nextAction": { "type": "send" } } }
// en-tête de signature : x-qorami-signature: t=<ts>,v1=<hmac>
// vérifier : HMAC_SHA256(secret, `${t}.${rawBody}`) === v1
SDK & intégrations
Des clients sans dépendance (JavaScript & Python) et un tool LangChain branchent Qorami en quelques lignes. Code : github.com/…/qorami-sdk.
JavaScript
// npm i qorami
import { QoramiClient } from "qorami";
const qorami = new QoramiClient({ apiKey: process.env.QORAMI_API_KEY });
await qorami.guard(
{ recipient, subject, body, policyProfile: "sales" },
{
send: () => mailer.send(), // autorisé
requestHumanConfirmation: (r) => queue(r.action.id), // humain notifié
doNotSend: () => {}, // bloqué
},
);
Python
from qorami import QoramiClient
qorami = QoramiClient(api_key=os.environ["QORAMI_API_KEY"])
result = qorami.verify(recipient="client@example.com", subject="Offre",
body=email_body, policy_profile="sales")
if result.next_action_type == "send":
send_email()
LangChain
from langchain_tool import build_qorami_tool
tool = build_qorami_tool() # outil 'qorami_check_email' pour votre agent
- Serveur MCP — branchez Qorami comme outil natif dans Claude Desktop, Cursor, Windsurf ou tout client MCP :
npx qorami-mcp. Exposeqorami_health,verify_emailetcheck_action_statusen stdio. Guide d'installation : qorami.fr/mcp. - Schémas d'outils — définitions prêtes à coller pour le function-calling OpenAI et le tool-use Anthropic (
qorami_check_email) : qorami-sdk/tools.
Pour une flotte d'agents
Plusieurs agents dans un même workspace ? De quoi rendre chacun observable et contrôlable indépendamment.
- Codes de décision machine — chaque décision porte
verification.reasonCodes(enum stable :SECRET_DETECTED,CARD_DETECTED,SSN_DETECTED,IBAN_DETECTED,SUSPICIOUS_LINK,BULK_PII,PROMPT_INJECTION,COMMERCIAL_PROMISE,LEGAL_COMMITMENT,SIGNATURE_PRESSURE, …). Détecte clés API fuitées, numéros de carte (validés Luhn), SSN et IBAN, en FR/EN/ES/DE/IT. Branchez sur les codes, pas sur le texte. - Détection d'injection de prompt — repère les tentatives de manipuler l'agent dans l'email qu'il s'apprête à envoyer ou cite (« ignore tes instructions », « envoie tout l'historique à… », action cachée) via
PROMPT_INJECTION. Le risque propre aux agents. Voir la précision mesurée. - Webhook temps-réel — déclarez un webhook (
POST /api/workspace/webhook) pour recevoiraction.verifiedsur chaque décision (plusaction.confirmed/action.blockedà la revue humaine) — branchez chaque décision d'agent dans un SIEM ou un log. Signé viax-qorami-signature. - Audit infalsifiable — les événements de chaque action sont chaînés par hash ;
GET /api/email-actions/:id/auditrenvoie{ intact, brokenAt, length }et prouve que la trace n'a pas été altérée. Niveau conformité. - Clés sandbox — créez une clé
"scope": "sandbox": elle renvoie la vraie décision mais ne facture jamais de crédit et ne persiste aucune action — pour la CI et tester des politiques. - Réécriture sûre (auto-fix) — quand un email n'est risqué qu'à cause de contenu retirable (secret, lien suspect, IBAN),
verification.remediationrenvoie unsafeBodynettoyé etsafeToSend. Envoyez la version nettoyée au lieu d'abandonner. - Attribution par agent — passez
agentIdà chaque appelverify-email, puis lisez le détail (total / autorisés / à confirmer / bloqués, les plus risqués d'abord) surGET /api/agents. - Une clé par agent — créez une clé nommée par agent (
POST /api/workspace/keysavec{ "label": "Bot relances" }, auth par session dashboard) et révoquez un agent sans gêner les autres. Liste :GET /api/workspace/keys. - Clés à privilège minimal — ajoutez
"scope": "verify"à la création pour qu'une clé d'agent ne puisse qu'appelerverify-email— jamais gérer facturation, clés ni politique (sinon403 insufficient_scope). - Override de politique par requête — durcissez la politique le temps d'un appel avec
policyOverride(reviewThreshold,blockThreshold,blockTerms/reviewTermsen plus). Il ne peut que rendre l'appel plus strict, jamais plus permissif. - Validation Slack — déclarez un webhook entrant Slack (
POST /api/workspace/slack,{ "webhookUrl": "https://hooks.slack.com/…" }) pour recevoir un message « Valider dans le dashboard » dès qu'un email nécessite un humain.
Autres endpoints
- Usage —
GET /api/usage: usage du mois + crédits restants + budget LLM (auto-surveillance). - File à valider / récents —
GET /api/email-actions?status=AwaitingConfirmation(ou?since=,?limit=). - Entités détectées — la réponse de
verify-emailinclutverification.detected: secrets (masqués), liens suspects, PII. - OpenAPI — spec machine à /api/openapi.json (import Postman / génération de code) · à parcourir sur /api-explorer.
Format d'erreur
Toutes les erreurs suivent la même enveloppe, avec un requestId traçable :
{
"error": {
"code": "insufficient_credits",
"message": "Not enough Qorami credits for this workspace.",
"requestId": "req_..."
}
}
Chaque réponse porte aussi l'en-tête x-qorami-request-id.
Crédits
1 action tracée = 1 crédit (un blocage est gratuit). Achetez des packs dans votre espace client. Nouveaux comptes : crédits offerts pour tester.