SUB&SUB · Docs

Référence de l'API

SUB&SUB expose un relais multi-fournisseurs sur https://api.subnsub.com/v1. Les clients OpenAI appellent /v1/chat/completions ; les clients Anthropic appellent /v1/messages. La même clé sk-cf-... route les deux — choisis le modèle dans le corps de la requête et le relais choisit l'upstream.

Démarrage rapide

Trois choses dont tu as besoin :

  1. URL de base : https://api.subnsub.com/v1 (clients OpenAI) ou https://api.subnsub.com (clients Anthropic — le SDK ajoute lui-même /v1/messages)
  2. Clé API : sk-cf-... émise depuis la console
  3. Modèle : l'un des 21 modèles vérifiés — par ex. gpt-5.4-mini ou claude-haiku-4.5

Authentification

Chaque requête doit porter un en-tête Authorization: Bearer sk-cf-.... Les clés sont émises depuis la console et stockées sous forme de hachages SHA-256 — une fois que tu quittes l'écran de création, le texte clair est perdu pour toujours, alors enregistre-le immédiatement.

Astuce Génère une clé par intégration (chatbot, plugin d'IDE, traitement par lots). Révoquer une clé fuitée dans la console prend effet en quelques secondes.

Endpoints

POST /v1/chat/completions

POST/v1/chat/completions

Envoie une requête de complétion de chat. Le format de la requête correspond à l'API Chat Completions d'OpenAI — les SDK OpenAI fonctionnent sans modification.

ParamètreTypeDescription
modelstringL'un des ID de modèles vérifiés.
messagesarrayHistorique de la conversation. Chaque élément : {role, content} avec rolesystem / user / assistant.
streambooleanSi true, la réponse est envoyée sous forme de chunks SSE. Voir Streaming.
stream_optionsobjectOptionnel. Le relais force toujours {include_usage: true} vers l'upstream pour que le chunk final porte le bloc d'usage des tokens — le surcharger n'a aucun effet.
max_tokensintegerLimite la longueur de la complétion. Par défaut, le maximum du modèle.
temperaturenumber0 – 2. Plus élevé = plus aléatoire.

POST /v1/messages

POST/v1/messages

Endpoint Anthropic natif pour les modèles claude-* — le SDK Anthropic (anthropic-sdk-python, @anthropic-ai/sdk, claude-code) fonctionne sans modification sur ce chemin. Pointe ton URL de base vers https://api.subnsub.com et authentifie-toi via l'en-tête x-api-key (la forme Authorization-Bearer fonctionne aussi, si ton client la préfère).

ParamètreTypeDescription
modelstringUn ID de modèle claude-* (voir Modèles disponibles). Passer un modèle OpenAI ici renvoie 400 invalid_request_error.
max_tokensintegerRequis par Anthropic — limite la longueur de la réponse de l'assistant.
messagesarrayHistorique de la conversation, format Anthropic : {role, content} avec roleuser / assistant.
streambooleanSi true, renvoie la séquence d'événements SSE standard d'Anthropic : message_start, content_block_delta, message_delta, message_stop.
thinkingobjectTransmis tel quel. Associe-le à une variante de modèle -thinking pour activer le raisonnement étendu.
cache_controlobjectLe prompt-caching est pris en charge. Les tokens d'écriture de cache sont facturés à 1.25× et les tokens de lecture de cache à 0.10× du tarif d'entrée du tier.
À noter Chaque requête Claude porte un prompt système Kiro d'environ 4100 tokens vers l'upstream — il est facturé comme des tokens d'entrée ordinaires au tarif du tier du modèle. Les prompts courts qui seraient autrement peu coûteux subissent quand même ce plancher.

GET /v1/models

GET/v1/models

Liste les modèles que tu peux réellement appeler. Le relais fusionne les catalogues OpenAI et Anthropic de sub2api et les filtre pour ne garder que les 21 que nous avons testés de bout en bout sur le pool de comptes actuel — les ID fantômes qui renvoient 503 au moment du routage, ou un 400 upstream au premier token, sont masqués. Si tous les upstreams configurés sont injoignables, l'endpoint renvoie 502 models_unreachable plutôt qu'une liste vide trompeuse.

# sample response (truncated)
{
  "object": "list",
  "data": [
    { "id": "gpt-5.4-mini",      "type": "model", ... },
    { "id": "gpt-5.4",           "type": "model", ... },
    { "id": "claude-sonnet-4.5", "type": "model", ... },
    { "id": "claude-haiku-4.5",  "type": "model", ... },
    ...
  ]
}

Modèles disponibles

Deux familles d'upstream. Les 7 modèles OpenAI routent vers des comptes partagés de la gamme ChatGPT ; les 14 modèles Claude routent via un proxy inverse Kiro vers AWS CodeWhisperer. Les tarifs par token dépendent du tier (voir Tarifs) — la même clé fonctionne pour les deux.

OpenAI

ID du modèleFamilleTierNotes
gpt-5.4-mini GPT-5.4Mini Rapide & économique. Défaut recommandé pour le chat & le coding.
gpt-5.3-codex Codex Mini 5.3 optimisé pour le coding. Même prix que mini.
gpt-5.2 GPT-5.2Standard5.2 stable.
gpt-5.2-chat-latestGPT-5.2StandardSuit automatiquement le dernier réglage chat de 5.2 (mappé actuellement vers gpt-5.2 en upstream).
gpt-5.4 GPT-5.4StandardGPT-5.4 pleine taille — plus lent, raisonnement plus solide.
gpt-5.4-2026-03-05GPT-5.4StandardInstantané daté de gpt-5.4.
gpt-5.5 GPT-5.5Premium Nouveau modèle phare.

Anthropic

ID du modèleFamilleTierNotes
claude-haiku-4.5 Haiku 4.5 Mini Le plus petit Claude — même tarif par token que gpt-5.4-mini.
claude-haiku-4.5-thinking Haiku 4.5 Mini Variante à raisonnement étendu de haiku-4.5. Associe-la au champ de requête thinking.
claude-sonnet-4.5 Sonnet 4.5 StandardClaude de milieu de gamme — même tarif par token que gpt-5.4.
claude-sonnet-4.5-thinking Sonnet 4.5 StandardVariante à raisonnement étendu de sonnet-4.5.
claude-sonnet-4.6 Sonnet 4.6 StandardNouveau réglage de Sonnet — tier Standard, même tarif que sonnet-4.5.
claude-sonnet-4.6-thinking Sonnet 4.6 StandardVariante à raisonnement étendu de sonnet-4.6.
claude-opus-4.5 Opus 4.5 Ultra Claude de pointe. Facturé au tarif public d'Anthropic — sans marge (voir Tarifs).
claude-opus-4.5-thinking Opus 4.5 Ultra Variante à raisonnement étendu d'opus-4.5 (raisonnement adaptatif).
claude-opus-4.6 Opus 4.6 Ultra Nouveau réglage d'Opus.
claude-opus-4.6-thinking Opus 4.6 Ultra Variante à raisonnement étendu d'opus-4.6.
claude-opus-4.7 Opus 4.7 Ultra Instantané d'Opus précédent.
claude-opus-4.7-thinking Opus 4.7 Ultra Variante à raisonnement étendu d'opus-4.7.
claude-opus-4.8 Opus 4.8 Ultra Dernier instantané d'Opus.
claude-opus-4.8-thinking Opus 4.8 Ultra Variante à raisonnement étendu d'opus-4.8.
À noter Chaque requête Claude porte un prompt système Kiro d'environ 4100 tokens en entrée — inclus dans ta facture de tokens. Le prompt-caching Anthropic est pris en charge : les écritures de cache sont facturées à 1.25× et les lectures à 0.10× du tarif d'entrée du tier (voir Tarifs).
Non disponible Les variantes Pro (gpt-5.2-pro, gpt-5.2-pro-2025-12-11), gpt-4o, gpt-4o-mini, gpt-5, gpt-5-mini, les variantes image / audio / realtime, claude-haiku-4-6, et les ID upstream datés (par ex. claude-sonnet-4-5-20250929). Les appeler renvoie 400 model_not_available. Les modèles Pro sont hors menu parce que les comptes de gamme sociale sous-jacents du pool épuiseraient leurs minuscules quotas en une poignée de requêtes.

Effort de raisonnement

Chaque modèle OpenAI ci-dessus est un modèle de raisonnement — le backend peut dépenser plus ou moins de tokens de « réflexion » avant de produire une sortie visible. Définis reasoning_effort dans le corps de la requête OpenAI /v1/chat/completions pour contrôler le budget. Pour Claude, utilise le champ de requête Anthropic natif thinking (ou choisis une variante de modèle -thinking) — voir la section /v1/messages. Les modèles OpenAI acceptent les mêmes cinq valeurs d'effort :

ValeurComportement
none Aucune réflexion — directement à la réponse. Le moins cher et le plus rapide.
low Une courte passe de raisonnement.
medium Défaut si tu ne passes pas le champ. Équilibré.
high Raisonnement plus approfondi. Recommandé pour le coding non trivial / les problèmes à plusieurs étapes.
xhigh Effort maximal. Le plus lent et le plus coûteux ; réserve-le aux analyses difficiles où tu en as vraiment besoin.
# Two equivalent forms — pick whichever your SDK supports
{
  "model": "gpt-5.4-mini",
  "reasoning_effort": "high",
  "messages": [ ... ]
}

{
  "model": "gpt-5.5",
  "reasoning": { "effort": "xhigh" },
  "messages": [ ... ]
}
Coût Les tokens de réflexion comptent comme des tokens de sortie pour la facturation — plus d'effort = plus de tokens de sortie = une facture plus élevée sur le même prompt. Le tarif par token ne change pas.
À noter Le protocole OpenAI définit aussi 'minimal', mais les modèles de notre pool le rejettent : « 'minimal' is not supported with this model ». Tiens-t'en aux cinq valeurs ci-dessus.

Streaming

Définis "stream": true pour recevoir des Server-Sent Events. Le chunk final porte un bloc usage (nous forçons stream_options.include_usage en upstream pour que les comptes de tokens soient toujours émis), puis un data: [DONE] littéral ferme le flux.

# Streaming format (line by line)
data: {"id":"resp_...","choices":[{"delta":{"content":"Hi"}}]}

data: {"id":"resp_...","choices":[{"delta":{"content":"!"}}]}

data: {"id":"resp_...","choices":[],"usage":{"prompt_tokens":18,"completion_tokens":11,"total_tokens":29}}

data: [DONE]

Ajoute :online à n'importe quel ID de modèle pris en charge par l'endpoint et le relais lancera une recherche web avant de transmettre au modèle, en préfixant la conversation avec les résultats pour que la réponse s'appuie sur des données fraîches. Le suffixe fonctionne sur /v1/chat/completions et /v1/messages (ce dernier exige toujours une base claude-*) ; aucun champ de requête spécifique à la recherche n'est requis.

# Same call as before — just :online on the model
curl https://api.subnsub.com/v1/chat/completions \
  -H "Authorization: Bearer sk-cf-xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.4-mini:online",
    "messages": [
      {"role": "user", "content": "What did Anthropic ship this week?"}
    ]
  }'

Comment ça marche : le relais retire :online, prend le message utilisateur le plus récent comme requête (limité à 400 caractères), appelle Tavily pour un maximum de 3 résultats avec le texte de page extrait lorsqu'il est disponible, plus un résumé optionnel généré par Tavily, puis les préfixe à ce même tour utilisateur sous forme de bloc <search_results> clairement délimité avant d'envoyer la requête à l'upstream. L'appel de recherche a un délai d'expiration de 8 secondes. Les résultats sont délibérément injectés dans le rôle utilisateur — jamais dans le prompt système — afin que des extraits non fiables ne puissent pas être élevés au rang d'instructions de priorité système.

Le bloc <search_results> ressemble à ceci. Il est précédé d'une instruction sur une ligne indiquant au modèle de traiter le bloc comme des données externes non fiables et de citer les éléments numérotés en ligne :

<search_results query="What did Anthropic ship this week?" retrieved="2026-05-21">
Summary: <short LLM-generated synthesis of the result set>

[1] Anthropic launches Opus 4.8
URL: https://www.anthropic.com/news/opus-4-8
<extracted page text, or short snippet if extraction failed — up to ~2000 chars>

[2] ...
</search_results>
ComportementDétail
CoûtAucun supplément aujourd'hui — tu paies le tarif par token normal du modèle ; le relais absorbe l'appel de recherche. Le bloc <search_results> injecté compte bien comme des tokens d'entrée, alors attends-toi à une facture de tokens de prompt plus élevée que pour la même question sans :online.
Mode d'échecSouple. Si Tavily expire ou échoue, la requête continue vers le modèle sans contexte de recherche (tu obtiens quand même une réponse, simplement non étayée). Le seul échec dur est 503 search_unavailable lorsque la recherche n'est pas du tout configurée sur le relais.
count_tokens/v1/messages/count_tokens retire le suffixe mais n'appelle jamais Tavily — le compte reflète ton prompt original, pas le prompt augmenté.
Multi-toursSeul le dernier tour utilisateur est interrogé & augmenté ; les tours précédents restent intacts. Pour rechercher à nouveau, envoie un nouveau message utilisateur avec :online toujours sur le modèle.

Quand utiliser :online

Le relais effectue un seul appel Tavily par requête et injecte les résultats — ce n'est pas une boucle de recherche agentique. Le modèle ne décide pas de relancer une recherche en fonction de ce qu'il voit, comme le font Perplexity Sonar ou l'outil de navigation de ChatGPT. Planifie en tenant compte de cette limitation :

Bon usageMauvais usage
Faits sensibles au temps (actualités, prix, numéros de version, dates de sortie)Code privé ou collé qui n'est pas sur le web public — ajoute du bruit au prompt sans étayage
Localiser une doc ou une annonce officielleMaths, raisonnement, traduction, écriture créative — rien à étayer
Tout ce que tu vérifierais autrement avec une recherche GoogleConnaissances stables déjà présentes dans les données d'entraînement (« qu'est-ce qu'un arbre binaire »)

Formule le dernier message utilisateur comme une requête de recherche autonome. La recherche s'effectue sur le texte littéral de ton tour utilisateur le plus récent (limité à 400 caractères), donc des relances conversationnelles comme « et qu'en est-il de la dernière version ? » deviennent des requêtes inutiles sans contexte. Dans un chat multi-tours, redonne le sujet quand tu ajoutes :online — par ex. « dernière version du SDK Python Anthropic » plutôt que « la dernière ».

Pour les questions nécessitant une synthèse en plusieurs étapes (comparaison, recherche approfondie), décompose-les en plusieurs tours et ajoute :online à chacun. Le modèle lira les résultats frais de chaque tour ; tu orientes manuellement la requête suivante. Note que le bloc <search_results> injecté n'est envoyé qu'à l'upstream — il n'est pas renvoyé à ton client et n'est pas conservé pour la requête suivante, donc si un tour ultérieur dépend de détails de sources antérieures, demande au modèle de les résumer dans sa réponse visible. Le mode recherche en une seule fois n'est pas pris en charge.

Astuce Combine avec un effort de raisonnement élevé (reasoning_effort: "high") pour que le modèle pèse réellement les sources retournées plutôt que de se reposer sur le premier résultat. L'instruction injectée demande au modèle de citer les sources numérotées sous la forme [1], [2] en ligne, donc la sortie portera généralement de telles citations — bien que le modèle ne soit pas strictement tenu de respecter ce format.

Erreurs

L'enveloppe dépend de l'endpoint que tu as appelé — le relais renvoie les erreurs dans le protocole correspondant au SDK de l'appelant, et les erreurs upstream sont transmises telles quelles.

Chemins OpenAI (/v1/chat/completions, /v1/responses, /v1/models) — enveloppe OpenAI :

{ "error": { "message": "...", "type": "...", "code": "..." } }

Chemins Anthropic (/v1/messages, /v1/messages/count_tokens) — enveloppe Anthropic :

{ "type": "error", "error": { "type": "...", "message": "..." } }

L'enveloppe Anthropic utilise un format différent — pas de champ code, et le discriminateur type: "error" est au niveau racine (avec l'error.type interne donnant la catégorie, par ex. authentication_error, invalid_request_error, permission_error, api_error). Les SDK Anthropic analysent déjà ce format ; les gestionnaires d'erreurs du SDK OpenAI standard ne le feront pas, alors appelle /v1/messages avec un SDK Anthropic (ou fais du HTTP brut).

Les codes de statut sont les codes HTTP canoniques dans les deux protocoles :

StatutOpenAI code / Anthropic error.typeSignification
401invalid_api_key / authentication_errorClé sk-cf-... manquante ou inconnue.
402insufficient_balance / permission_errorLe solde du compte est négatif. Recharge dans l'onglet facturation de la console.
403key_revoked / permission_errorLa clé a été révoquée.
400model_not_available / invalid_request_errorLe model que tu as envoyé n'est pas dans le catalogue vérifié, ou est incorrect pour l'endpoint (par ex. un modèle OpenAI sur /v1/messages) — vérifie Modèles disponibles.
503Aucun compte upstream ne sert actuellement la requête — généralement une fenêtre de limitation de débit à l'échelle du pool, pas un problème de configuration.
503search_unavailable / api_errorTu as utilisé :online mais la recherche web n'est pas configurée sur ce relais. Voir Recherche web.
502upstream_unreachable / api_errorLe relais n'a pas pu atteindre le backend. Réessaie après un court délai.

Tarifs & facturation

Paiement à l'usage, facturé par token en microdollars (1 micro = $0.000001 = 1/10,000 de cent) pour que les requêtes inférieures au cent soient suivies précisément. Les tarifs sont par 1M tokens, par tier — voir le tableau des modèles pour savoir à quel tier chaque modèle correspond.

TierModèlesEntrée / 1MSortie / 1M
Mini gpt-5.4-mini, gpt-5.3-codex, claude-haiku-4.5, claude-haiku-4.5-thinking $0.20$1.60
Standardgpt-5.2, gpt-5.2-chat-latest, gpt-5.4, gpt-5.4-2026-03-05, claude-sonnet-4.5, claude-sonnet-4.5-thinking, claude-sonnet-4.6, claude-sonnet-4.6-thinking$0.75$6.00
Premium gpt-5.5 $1.10$8.80
Ultra claude-opus-4.5, claude-opus-4.5-thinking, claude-opus-4.6, claude-opus-4.6-thinking, claude-opus-4.7, claude-opus-4.7-thinking, claude-opus-4.8, claude-opus-4.8-thinking$5.00$25.00

Les tarifs du tier Ultra correspondent au tarif public d'Opus publié par Anthropic — répercussion directe, sans marge. Les autres tiers tournent en dessous de leurs tarifs upstream grâce au socle d'abonnements mutualisés.

Les tokens de raisonnement (quand tu définis reasoning_effort sur OpenAI, ou utilises une variante Claude -thinking) comptent comme des tokens de sortie au tarif du tier du modèle — il n'y a pas de supplément distinct pour un effort élevé, mais une requête à réflexion approfondie peut facilement émettre 10–50× plus de tokens de sortie qu'une requête sans effort, donc la facture en dollars évolue en conséquence.

Le prompt-caching Anthropic est facturé comme une ligne distincte : écritures de cache à 1.25× et lectures de cache à 0.10× du tarif d'entrée du tier. Ainsi, un cache hit haiku-4.5 coûte 0.20 × 0.10 = $0.02 per 1M tokens, et un cache hit sonnet-4.5 coûte 0.75 × 0.10 = $0.075 per 1M tokens. Les colonnes de cache sont enregistrées sur chaque ligne de règlement pour que la console puisse afficher le détail.

Le solde est déduit en temps réel à mesure que chaque requête se termine — pour les requêtes en streaming, le règlement s'exécute après l'arrivée du chunk [DONE]. Consulte ton solde en direct et les règlements par requête sur /console#billing.

Recharge La console prend en charge Stripe Checkout — carte, Link, Alipay, WeChat Pay (selon ce qui est activé sur le compte Stripe). Les crédits n'expirent jamais.

Limites de débit

Pas de limites de débit par clé aujourd'hui. La concurrence du pool de comptes upstream & le throttling côté serveur d'OpenAI s'appliquent ; si tu les atteins, le relais renvoie 429 avec un en-tête retry-after. Les limites RPM / TPM par clé arriveront après le MVP.