API — intégration native
Tout ce que fait l'interface web est une API HTTP + SSE ordinaire. Tout ce que vous pouvez faire en cliquant, vous pouvez le faire depuis votre propre code : lancer un agent, streamer sa réponse, interroger une base de connaissances, créer des agents, planifier des tâches, récupérer les résultats.
| URL de base | https://ai.syctra.com/api/v1 |
| Transport | HTTPS uniquement (HTTP redirigé). TLS 1.2+ |
| Encodage | JSON, UTF-8. Content-Type: application/json sur toute écriture |
| Streaming | Server-Sent Events (text/event-stream), reprenable |
| Authentification | Authorization: Bearer <access_token> |
| Versionnement | Le préfixe /v1 est stable. Des champs peuvent être ajoutés ; aucun n'est supprimé sans nouveau préfixe |
1. Authentification
Deux identifiants existent. Utilisez le bon :
| Clé API | E-mail + mot de passe | |
|---|---|---|
| Pour | Serveurs, scripts, intégrations, CI | Applications interactives où un humain se connecte |
| Obtention | Paramètres → 🔑 Clés API → Nouvelle clé | POST /auth/register puis /auth/login |
| Format | sk_live_… | Paire JWT (access + refresh) |
| Durée de vie | Jusqu'à révocation | Access 15 min · refresh 30 jours |
N'envoyez jamais une clé API dans un navigateur, une application mobile ou un dépôt public. Elle porte tous les droits du compte qui l'a créée. Tout ce qui tourne sur un appareil client doit passer par VOTRE backend, qui détient la clé.
1.1 Clé API → jeton d'accès
Une clé API n'est pas un jeton bearer : vous l'échangez contre un jeton d'accès de courte durée, puis vous appelez n'importe quel endpoint avec ce jeton.
export SYCTRA_API_KEY="sk_live_…"
TOKEN=$(curl -sS -X POST https://ai.syctra.com/api/v1/auth/token \
-H "X-API-Key: $SYCTRA_API_KEY" | jq -r .access_token)
POST /auth/token est le seul endpoint qui accepte la clé elle-même. Il la lit de trois façons —
X-API-Key: sk_live_…, Authorization: Bearer sk_live_…, ou {"api_key": "sk_live_…"} dans le
corps — et répond :
{ "access_token": "eyJhbGciOiJSUzI1NiIs…", "token_type": "Bearer", "expires_in": 900 }
Mettez le jeton en cache pendant expires_in (900 s) et ré-échangez à l'expiration. N'échangez
pas à chaque requête : l'endpoint est limité à 60 échanges par minute et par IP.
1.2 Gérer les clés
| Méthode | Chemin | Rôle |
|---|---|---|
POST | /api-keys | Créer une clé. {"name": "serveur-prod"}. Le secret n'apparaît que dans cette réponse |
GET | /api-keys | Lister les clés actives — id, nom, préfixe, created_at, last_used_at. Jamais le secret |
DELETE | /api-keys/{key_id} | Révoquer. Bloque immédiatement tout nouvel échange |
Jusqu'à 20 clés actives par utilisateur. Seul sha256(clé) est stocké : une clé perdue est
irrécupérable — révoquez-la et créez-en une autre. La révocation stoppe aussitôt les nouveaux
échanges ; un jeton déjà émis depuis cette clé reste valide jusqu'à son expiration (≤ 15 min),
exactement comme une déconnexion de navigateur.
1.3 E-mail + mot de passe (applications interactives)
curl -X POST https://ai.syctra.com/api/v1/auth/register \
-H 'content-type: application/json' \
-d '{"email":"dev@acme.com","password":"…"}' # → code à 6 chiffres par e-mail
curl -X POST https://ai.syctra.com/api/v1/auth/verify \
-H 'content-type: application/json' \
-d '{"email":"dev@acme.com","code":"123456"}'
curl -X POST https://ai.syctra.com/api/v1/auth/login \
-H 'content-type: application/json' \
-d '{"email":"dev@acme.com","password":"…"}' # → { access_token, refresh_token }
Renouvelez avec POST /auth/refresh {"refresh_token": "…"}. La connexion Google et
OIDC/SAML est disponible via /auth/google/start et /auth/oidc/start. La connexion est
limitée par compte après échecs répétés ; les inscriptions sont plafonnées par IP.
2. Démarrage — interroger un agent, streamer la réponse
Le schéma est toujours le même : démarrer un run, puis streamer ses événements. Un run est durable — si votre processus meurt, reconnectez-vous et rejouez depuis votre position.
# 1 — démarrer
RUN=$(curl -sS -X POST https://ai.syctra.com/api/v1/chat \
-H "Authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{"message":"Résume la tendance du CA 2024 et fais-en un graphique","app_name":"data_copilot"}')
RUN_ID=$(echo "$RUN" | jq -r .run_id)
# 2 — streamer (reprenable)
curl -N https://ai.syctra.com/api/v1/runs/$RUN_ID/events \
-H "Authorization: Bearer $TOKEN"
Python
import json, os, requests
BASE = "https://ai.syctra.com/api/v1"
token = requests.post(f"{BASE}/auth/token",
headers={"X-API-Key": os.environ["SYCTRA_API_KEY"]},
timeout=30).json()["access_token"]
H = {"Authorization": f"Bearer {token}"}
run = requests.post(f"{BASE}/chat", headers=H, timeout=30, json={
"message": "Rédige un NDA mutuel pour une SARL algérienne, puis exporte-le en DOCX",
"app_name": "legal_drafting_dz",
}).json()
reponse, cursor = [], 0
with requests.get(f"{BASE}/runs/{run['run_id']}/events", headers=H, stream=True) as r:
event = None
for line in r.iter_lines(decode_unicode=True):
if not line:
continue
if line.startswith("id:"):
cursor = int(line[3:].strip()) # à conserver : c'est votre point de reprise
elif line.startswith("event:"):
event = line[6:].strip()
elif line.startswith("data:"):
payload = json.loads(line[5:].strip())
if event == "token":
reponse.append(payload.get("text", ""))
elif event == "artifact":
print("fichier :", payload.get("artifact_id"), payload.get("filename"))
elif event in ("done", "error"):
break
print("".join(reponse))
Node
const BASE = 'https://ai.syctra.com/api/v1';
const { access_token } = await (await fetch(`${BASE}/auth/token`, {
method: 'POST', headers: { 'X-API-Key': process.env.SYCTRA_API_KEY },
})).json();
const { run_id } = await (await fetch(`${BASE}/chat`, {
method: 'POST',
headers: { authorization: `Bearer ${access_token}`, 'content-type': 'application/json' },
body: JSON.stringify({ message: 'Liste les risques de ce contrat', app_name: 'contract_review_dz' }),
})).json();
const res = await fetch(`${BASE}/runs/${run_id}/events`, {
headers: { authorization: `Bearer ${access_token}` },
});
for await (const chunk of res.body) process.stdout.write(Buffer.from(chunk).toString());
3. Conventions
Erreurs. Codes HTTP standard avec un corps JSON {"detail": "…"}.
| Code | Signification | Que faire |
|---|---|---|
400 | Requête malformée | Corrigez le payload ; le message nomme le champ |
401 | Jeton absent / expiré / invalide | Ré-échangez la clé |
402 | Crédits insuffisants | Rechargez ; le run n'a pas démarré et n'est pas facturé |
403 | Authentifié mais non autorisé | Mauvaise organisation, agent non accordé à votre équipe, ou compte suspendu |
404 | Inconnu ou pas à vous | Les identifiants sont cloisonnés par organisation |
409 | Conflit (session occupée…) | Lisez le corps ; une mise en file est signalée dans POST /chat |
429 | Débit dépassé | Backoff exponentiel, respectez Retry-After s'il est présent |
5xx | Côté serveur | Réessayez avec backoff ; les runs sont idempotents avec idempotency_key |
Idempotence. Envoyez idempotency_key sur POST /chat — rejouer la même clé renvoie le run
d'origine (resumed: true) au lieu d'en démarrer et d'en facturer un second.
Identifiants : UUID. Horodatages : ISO-8601 UTC. Envoyez client_tz (IANA, ex.
"Africa/Algiers") sur POST /chat pour que l'agent raisonne à votre heure locale.
Limites de débit.
| Surface | Limite |
|---|---|
POST /chat et runs | 20 req/s en régime, rafale 40, par utilisateur |
POST /auth/token | 60/min par IP cliente |
POST /auth/login | limité par compte après échecs répétés |
POST /auth/register | plafonné par IP et par heure |
| Corps de requête | 300 Mo (uploads base64 inclus) |
Concurrence. Les runs sont sérialisés par session : un second message envoyé pendant
qu'un run tourne est accepté, mis en file côté serveur et exécuté ensuite (status: "queued",
avec un queue_seq). Utilisez des session_id différents pour paralléliser.
4. Facturation
Chaque action IA débite des crédits du solde de votre organisation — le même solde que celui
affiché dans l'application, que le travail vienne d'un navigateur, d'un appel API, d'une tâche
planifiée ou d'un widget embarqué. Chaque run émet un événement usage avec ses compteurs de
jetons, et GET /balance renvoie le solde courant. Un run impayable est refusé en 402
avant tout travail.
5. Sécurité
Ce que la plateforme garantit :
- Clés stockées hachées (SHA-256). Le secret n'existe qu'une fois, dans la réponse de création.
- Jetons de courte durée. 15 minutes ; désactiver un compte ou incrémenter sa version de jeton invalide ses sessions et bloque tout nouvel échange.
- Rédaction des secrets. Les agents ne peuvent pas divulguer les secrets de la plateforme : clés API, mots de passe SMTP, chaînes de connexion et clés privées sont retirés des résultats d'outils, des erreurs d'outils et des réponses du modèle par un filtre déterministe — pas par une consigne de prompt qu'on peut contourner.
- Confinement des injections de prompt. Dès qu'un run ingère du contenu non fiable (fichier importé, page scrapée, résultat de recherche), les actions sortantes — envoi d'e-mail, publication, écriture en mémoire, HTTP arbitraire — sont bloquées tant que vous ne les confirmez pas explicitement.
- Exécution en bac à sable. Le code écrit par un agent tourne dans un conteneur gVisor à usage unique, sans secrets ni réseau direct : la sortie passe par un proxy avec filtre SSRF.
- Cloisonnement. Chaque identifiant est rattaché à votre organisation et revérifié côté serveur ; l'identité vient toujours du jeton, jamais d'un champ de la requête.
- Traçabilité. Chaque appel d'outil est enregistré avec son run, son organisation et son statut.
Ce qui vous revient :
- Gardez les clés côté serveur, dans un coffre ou une variable d'environnement — jamais dans un navigateur, un bundle mobile, un dépôt git ou un log de CI.
- Une clé par système, nommée d'après ce système, pour pouvoir la révoquer isolément.
- Faites tourner vos clés : créez la nouvelle, déployez, puis révoquez l'ancienne.
last_used_atvous dit quand une clé peut être retirée sans risque. - Toute clé apparue dans un log, une capture d'écran ou un ticket est compromise — révoquez-la.
- Si vous réexposez l'API à vos propres utilisateurs, appliquez votre propre autorisation : une clé plateforme ne connaît pas vos utilisateurs finaux.
Catalogue complet : Référence API.