Agentic Gateway en 10 minutes
Du premier curl à la première clé virtuelle émise pour un client.
1. Démarrage rapide
Lancez la stack de développement (gateway + Postgres) puis vérifiez la santé du service.
./scripts/run-stack.sh up # gateway :4101, Postgres :54100
curl localhost:4101/health # {"status":"ok"}Ouvrez ensuite la console opérateur et connectez-vous avec la master key (dev-master-key en dev).
2. Deux types de clés, deux mondes
Clé de l'opérateur. Donne accès à /admin/* : tenants, clés, guardrails, usage. Une seule par déploiement, saisie une fois dans la console.
Clé d'un client ou d'un agent, format sk-agentic-…. Donne accès à /v1/*. Hachée côté serveur, affichée en clair une seule fois à l'émission.
Les clés fournisseurs (OpenAI, Anthropic…) ne sortent jamais du gateway : ni l'API, ni la console ne les exposent.
3. Référence API v1 (virtual key)
Authorization: Bearer sk-agentic-…
Content-Type: application/json
{ "model": "openai/gpt-4o-mini",
"messages": [{ "role": "user", "content": "Bonjour" }],
"stream": false }
→ 200 { "id": "chatcmpl-…", "object": "chat.completion",
"choices": [{ "message": { "role": "assistant", "content": "…" }, "finish_reason": "stop" }],
"usage": { "prompt_tokens": 12, "completion_tokens": 8, "total_tokens": 20 } }Avec "stream": true, la réponse est un flux SSE de chunks chat.completion.chunk terminé par data: [DONE].
POST /v1/embeddings { "model": "text-embedding-3-small", "input": "hello" }
GET /v1/models → { "object": "list", "data": [{ "id": "openai/gpt-4o", "owned_by": "openai" }, …] }
GET /health → { "status": "ok" } (sans clé)4. API admin (master key)
| Méthode | Route | Corps | Réponse |
|---|---|---|---|
| GET | /admin/health | — | {"db":"ok","providers_configured":1,"version":"0.6.0"} |
| GET · POST | /admin/tenants | {"id":"acme","name":"Acme Corp"} | liste enrichie (nom, clés actives, coût) · création, 409 si existe |
| POST | /admin/tenants/rename | {"tenant_id","name"} | renommage |
| DELETE | /admin/tenants/remove?tenant_id= | — | suppression douce, 409 sur default |
| GET · POST | /admin/keys | {"tenant_id","label","budget_usd"} | liste avec dépense · émission, clé en clair une seule fois |
| POST | /admin/keys/patch · /admin/keys/revoke | {"key_id","label","budget_usd"} | modification · révocation |
| GET · POST · DELETE | /admin/guardrails | {"tenant_id","blocked_patterns","max_input_chars"} | lecture · écriture · réinitialisation |
| GET · POST | /admin/providers | {"id","api_key","base_url","extra"} | liste (jamais la clé) · ajout ou remplacement |
| POST · DELETE | /admin/providers/test · /remove?id= | — | test de la clé · retrait |
| GET | /admin/providers/catalog · /admin/models/catalog | — | providers connus · modèles, prix et capacités |
| GET | /admin/usage[/timeseries|/breakdown|/events] | — | totaux, série par jour, répartition par modèle, clé ou provider, journal |
Les erreurs suivent le format OpenAI : {"error":{"message":"…","type":"auth_error"}}, 401 si la clé est absente, invalide ou révoquée.
5. Utiliser le SDK OpenAI
import OpenAI from "openai";
const client = new OpenAI({ baseURL: "http://localhost:4101/v1", apiKey: process.env.AGENTIC_KEY });
const stream = await client.chat.completions.create({
model: "anthropic/claude-sonnet-4", stream: true,
messages: [{ role: "user", content: "Explique SSE en une phrase." }],
});
for await (const chunk of stream) process.stdout.write(chunk.choices[0]?.delta?.content ?? "");6. Auto-hébergement
services:
gateway:
image: ghcr.io/grantity/agentic-gateway:latest
environment:
GATEWAY_MASTER_KEY: ${GATEWAY_MASTER_KEY}
DATABASE_URL: postgres://gateway:gateway@db:5432/gateway
OPENAI_API_KEY: ${OPENAI_API_KEY}
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
ports: ["4101:4000"]
db:
image: postgres:16La console (ce site, dossier website/) se déploie à part et relaie les appels vers le gateway via la variable GATEWAY_URL.