Documentation

Référence API

L'authentification, la surface d'endpoints compatible OpenAI, le streaming, le raisonnement et la taxonomie d'erreurs.

Authentification

Chaque requête vers /v1/* s'authentifie avec une clé virtuelle dans l'en-tête Authorization: Bearer. Générez des clés dans la Console ; le secret n'est affiché qu'une seule fois et seul son hash est stocké. Une clé porte ses propres limites de débit, son budget, ses tags, une liste d'autorisation de modèles facultative (vide = tout modèle) et des option_overrides épars qui dérogent à la politique de l'organisation (mode de protection des données, modèle NER, mode d'analyse d'injection).

Une requête dont le modèle ne figure pas sur la liste d'autorisation non vide de la clé est refusée avec un 403 permission_error scellé avant tout envoi ; le refus lui-même est inscrit dans la chaîne d'audit.

La création d'une clé de production requiert une adresse e-mail vérifiée.

curl https://api.sluis.ai/v1/models \
  -H "Authorization: Bearer $SLUIS_KEY"

# a model outside the key's allow-list never dispatches:
# → 403 permission_error · the refusal is sealed in the audit chain

Endpoints

Sluis expose la surface compatible OpenAI ci-dessous. Les endpoints sans gestionnaire de premier niveau sont relayés tels quels vers le fournisseur routé, streaming compris, afin que les upstreams compatibles OpenAI conservent une fidélité totale.

EndpointRôle
POST /v1/chat/completionsChat completions, la surface principale : routage, protection des données, mise en cache, streaming.
POST /v1/completionsText completions historiques.
POST /v1/embeddingsEmbeddings ; alimente aussi le cache sémantique.
POST /v1/moderationsClassification de modération.
POST /v1/responsesL'API OpenAI Responses.
POST /v1/ocrOCR de documents (Mistral, ou entièrement local avec le modèle sluis/ocr) · facturé à la page. Avec la politique dlp_documents active, les documents inline sont anonymisés avant de partir.
POST /v1/documents/anonymizeAnonymisation de documents · les PII deviennent des «MERGE_TAG»s, les images sont floutées · facturé par page/image.
POST /v1/documents/anonymize/jobsJobs d'anonymisation asynchrones · déposez les gros documents, suivez le statut, récupérez le résultat via une URL signée à durée limitée sans clé API.
GET /v1/modelsLes modèles que votre politique et vos identifiants peuvent réellement atteindre, rien d'hypothétique.
GET /v1/models/{id}Les métadonnées d'un modèle.
POST /v1/audio/*Transcription, traduction, synthèse vocale · relayé vers le fournisseur routé.
POST /v1/images/*Génération et retouche d'images · relayé.
POST /v1/video/generationsGénération de vidéo · relayé.
/v1/filesOpérations sur fichiers · relayé.
POST /v1/messagesEntrée native Anthropic Messages · pointez n'importe quel outil SDK Anthropic vers Sluis ; tout modèle connecté.
POST /v1/messages/count_tokensEstimation locale de tokens pour la gestion de contexte du SDK Anthropic ; rien n'est envoyé.
POST /v1beta/models/{model}:generateContentEntrée native Google Gemini · pointez un SDK Gemini vers Sluis (:streamGenerateContent diffuse en continu).
curl https://api.sluis.ai/v1/chat/completions \
  -H "Authorization: Bearer $SLUIS_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "model": "mistral/mistral-large-latest",
        "messages": [{ "role": "user", "content": "Say hi" }] }'
# Document OCR, billed per page. Returns pages[] markdown + usage_info.pages_processed.
# model "sluis/ocr" runs the gateway's own OCR engine: fully local, no provider egress (inline data: URLs only).
curl https://api.sluis.ai/v1/ocr \
  -H "Authorization: Bearer $SLUIS_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "model": "mistral/mistral-ocr-latest", "document": { "type": "document_url", "document_url": "https://example.com/invoice.pdf" } }'
# Document anonymization, billed per page/image. PII becomes «MERGE_TAG»s; images are blurred.
curl https://api.sluis.ai/v1/documents/anonymize \
  -H "Authorization: Bearer $SLUIS_KEY" \
  -F file=@contract.docx \
  -F 'options={ "entities": ["person_name", "email", "iban"], "include_mapping": true }'

Documents en entrée

Joignez un PDF, un document Word, une image ou un fichier texte à une requête chat comme part de contenu "type": "file" portant une URL file_data en base64. N'importe quel modèle routé l'accepte : les fournisseurs qui comprennent nativement les parts de fichier les reçoivent inchangées, et pour tous les autres la passerelle convertit le document avant l'envoi. Les références file_id côté fournisseur ne sont pas résolues ; insérez les octets en file_data.

Les modèles avec vision reçoivent chaque page du PDF rendue comme part image_url (budget de 48 pages par requête, partagé entre tous les documents joints) ; les modèles sans entrée image reçoivent le texte extractible du document inséré comme texte de prompt, que l'analyse de protection des données couvre ensuite comme tout autre texte. Les documents plus longs ou plus lourds passent par /v1/ocr. Avec la politique dlp_documents activée, le document est anonymisé ou refusé avant que quoi que ce soit ne quitte la passerelle. Si elle est désactivée et que le mode DLP de l'organisation est protecteur (tokenize, mask ou block), les documents qui voyageraient comme images non inspectables sont refusés ; en allow_log ils passent avec un marqueur explicite « non analysé » dans le journal d'audit.

# Attach a document as an OpenAI-style `file` content part. The gateway
# normalizes it for the routed provider, so this works on any model.
curl https://api.sluis.ai/v1/chat/completions \
  -H "Authorization: Bearer $SLUIS_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "model": "scaleway/gemma-4-26b-a4b-it",
        "messages": [{ "role": "user", "content": [
          { "type": "file",
            "file": { "filename": "drawing.pdf",
                      "file_data": "data:application/pdf;base64,'"$(base64 -w0 drawing.pdf)"'" } },
          { "type": "text", "text": "Which discipline does this drawing document?" }
        ] }] }'

Streaming

Définissez stream: true et la réponse arrive sous forme de server-sent events : chaque frame est un delta chat.completion.chunk et le flux se termine par data: [DONE]. Les flux ne sont jamais mis en tampon dans la passerelle : ils la traversent en dérivation, et le sceau d'audit ainsi que le comptage se produisent même si le client raccroche tôt.

Demandez stream_options.include_usage et le frame final porte l'usage exact en tokens, les mêmes chiffres que la passerelle compte et facture.

stream = client.chat.completions.create(
    model="mistral/mistral-large-latest",
    messages=[{"role": "user", "content": "Write a haiku"}],
    stream=True,
    stream_options={"include_usage": True},
)
for chunk in stream:
    print(chunk.choices[0].delta.content or "", end="")

Raisonnement

Passez le paramètre OpenAI reasoning_effort (minimal | low | medium | high) sur n'importe quel modèle capable de raisonnement. Sluis le traduit selon le fournisseur (le niveau de réflexion de Gemini, l'effort de réflexion adaptatif de Claude) et l'omet là où un modèle le rejetterait, de sorte qu'un seul paramètre fonctionne sur tout le catalogue.

resp = client.chat.completions.create(
    model="vertex/claude-opus-4-8",
    messages=[{"role": "user", "content": "Prove it step by step…"}],
    reasoning_effort="high",  # minimal | low | medium | high
)

Codes d'erreur

Les erreurs utilisent l'enveloppe d'erreur OpenAI ; la valeur error.type reflète le statut HTTP, si bien que la gestion d'erreurs de votre SDK continue de fonctionner sans changement.

CodeQuand
400 invalid_request_errorCorps de requête ou paramètres mal formés.
400 invalid_request_errorIdentifiant de modèle sans préfixe de fournisseur. Chaque identifiant appelable est provider/model, p. ex. mistral/mistral-large-latest ; le corps indique : model must be provider-prefixed.
400 invalid_request_errorLa requête porte l'en-tête x-sluis-dlp, supprimé. Les dérogations par requête ont été remplacées par les option overrides par clé ; configurez-les dans Console → API keys.
401 authentication_errorClé API manquante ou inconnue.
402 insufficient_quotaAucun forfait actif ou budget atteint. Activez un forfait ou relevez le budget ; la requête n'atteint jamais un fournisseur.
403 permission_errorLa clé n'a pas la permission, par exemple le modèle ne figure pas sur sa liste d'autorisation.
422 invalid_request_errorRefusée avant l'envoi, par exemple la protection des données en mode block a détecté la requête.
422 document_too_large_to_scanUne page du document dépasse le plafond de pixels de rendu même à la résolution minimale d'analyse. Les pages grand format (plans A0/A1) sont rendues réduites automatiquement ; ce code dédié permet au client de réduire la page et de la soumettre à nouveau.
429 rate_limit_errorLimite de débit atteinte. Appliquée à la passerelle ; la requête n'atteint jamais un fournisseur.
451 permission_errorBloquée par la politique de résidence : aucune juridiction autorisée ne sert la requête. Le corps inclut le motif.
5xx api_errorDéfaillance du fournisseur en amont après plusieurs tentatives ; le disjoncteur détourne le trafic des fournisseurs défaillants.
{
  "error": {
    "message": "model must be provider-prefixed, e.g. mistral/mistral-large-latest",
    "type": "invalid_request_error",
    "param": null,
    "code": "invalid_request"
  }
}