Hyperouter API
Cette documentation est disponible en Markdown pour les assistants IA. Commencez par /llms.txt, ou récupérez /llms-full.txt pour avoir toutes les pages dans un seul fichier. Cette page est /docs.md.
Hyperouter est une API HTTP unique devant de nombreux éditeurs de modèles. Vous envoyez une requête qui nomme un modèle. Hyperouter choisit un fournisseur capable de la servir, lui transmet la requête et débite votre solde au tarif public de ce fournisseur.
Chaque endpoint suit les formats de requête et de réponse d’OpenAI. Les OpenAI SDK fonctionnent dès que vous changez l’URL de base et la clé API. Hyperouter ajoute quelques champs aux corps d’OpenAI. Ils sont signalés comme ajouts dans cette référence.
| Endpoint | Rôle | Auth |
|---|---|---|
GET /v1/models | Lister les modèles que votre compte peut appeler. | Clé API |
POST /v1/chat/completions | Chat completion, avec streaming optionnel. | Clé API |
POST /v1/images/generations | Texte vers image. | Clé API |
POST /v1/images/edits | Modifier des images. | Clé API |
POST /v1/videos | Créer une vidéo à partir d’un prompt, avec une image facultative. | Clé API |
POST /v1/videos/edits | Modifier ou agrandir une vidéo. | Clé API |
POST /v1/videos/extensions | Prolonger une vidéo. | Clé API |
POST /v1/videos/{id}/remix | Produire une nouvelle version d’une vidéo avec un nouveau prompt. | Clé API |
GET /v1/videos, GET /v1/videos/{id}, GET /v1/videos/{id}/content, DELETE /v1/videos/{id} | Lister, lire, télécharger et supprimer des vidéos. | Clé API |
GET /v1/generations/{id} | Lire l’enregistrement de n’importe quelle requête : statut, consommation et coût. | Clé API |
GET /v1/credits | Votre solde, ce que bloquent les requêtes ouvertes, et ce qu’il reste à dépenser (balance_usd, held_usd, available_usd, chaînes décimales en USD). | Clé API |
Connectez-vous sur dash.hyperouter.app avec Google ou GitHub pour créer une clé API. GET /v1/models renvoie les modèles que vous pouvez appeler au moment de la requête.
Démarrage rapide
- Connectez-vous et créez une clé API. Les clés commencent par
sk-hr-v1-et ne sont affichées qu’une seule fois. - Stockez-la dans une variable d’environnement, par exemple
HYPEROUTER_API_KEY. - Ajoutez des crédits : ouvrez une demande de recharge dans le tableau de bord. Notre équipe crédite votre solde une fois le paiement confirmé.
- Pointez n’importe quel OpenAI SDK vers l’URL de base ci-dessus et choisissez un modèle.
curl https://api.hyperouter.app/v1/chat/completions \ -H "Authorization: Bearer $HYPEROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "x-ai/grok-4.7", "messages": [{"role": "user", "content": "Hello"}] }'
import OpenAI from "openai"; const client = new OpenAI({ baseURL: "https://api.hyperouter.app/v1", apiKey: process.env.HYPEROUTER_API_KEY, }); const res = await client.chat.completions.create({ model: "x-ai/grok-4.7", messages: [{ role: "user", content: "Hello" }], }); console.log(res.choices[0].message.content);
import os from openai import OpenAI client = OpenAI( base_url="https://api.hyperouter.app/v1", api_key=os.environ["HYPEROUTER_API_KEY"], ) res = client.chat.completions.create( model="x-ai/grok-4.7", messages=[{"role": "user", "content": "Hello"}], ) print(res.choices[0].message.content)
Authentification
Envoyez votre clé API comme bearer token dans chaque requête.
Authorization: Bearer sk-hr-v1-...
Les clés donnent accès à votre solde. Gardez-les côté serveur. Ne les mettez jamais dans du code navigateur ou mobile. Hyperouter ne stocke que le hash de chaque clé : une clé perdue ne peut donc pas être affichée de nouveau, il faut en créer une nouvelle.
Dans le tableau de bord, vous pouvez nommer chaque clé, lui fixer une limite de crédit et la désactiver. Une clé désactivée cesse de fonctionner immédiatement. Une requête qui ferait dépasser sa limite à une clé est refusée avec 402 insufficient_credits.
Erreurs d’authentification
| Statut | type | code | Quand | message |
|---|---|---|---|---|
401 | authentication_error | invalid_api_key | L’en-tête est absent, n’est pas de type Bearer, ou la clé ne commence pas par sk-hr-v1-. | The API key is missing or malformed. Send Authorization: Bearer sk-hr-v1-… |
401 | authentication_error | invalid_api_key | La clé est inconnue ou désactivée. | The API key is not valid. |
403 | permission_error | account_suspended | Le compte est suspendu. La vérification est faite à chaque requête. | This account is suspended. Open a support ticket. |
429 | rate_limit_error | too_many_auth_failures | Plus de 30 requêtes provenant de votre adresse en une minute ont utilisé une clé absente ou invalide. Toutes les requêtes /v1 de cette adresse sont refusées pendant 15 minutes, même avec une clé valide. Retry-After indique les secondes restantes. | Too many failed API key checks from this address. Try again after the time in Retry-After. |
500 | server_error | internal | Hyperouter n’a pas pu vérifier la clé. | An internal error occurred. Try again. |
curl https://api.hyperouter.app/v1/generations/0194f2c4-7a1e-7b3c-9d02-5f6a1c0e8b21 \
-H "Authorization: Bearer $HYPEROUTER_API_KEY"
{ "error": { "message": "The API key is not valid.", "type": "authentication_error", "code": "invalid_api_key", "param": null } }
Erreurs
Chaque erreur utilise l’objet d’erreur d’OpenAI et un statut HTTP correspondant.
{
"error": {
"message": "n must be an integer from 1 to 128",
"type": "invalid_request_error",
"code": "invalid_body",
"param": "n"
}
}
| Champ | Type | Description |
|---|---|---|
message | string | Une phrase qui dit ce qui ne va pas. Ne l’analysez pas. |
type | string | La classe d’erreur. Voir la liste ci-dessous. |
code | string | Un identifiant stable de la cause. Fiez-vous à ce champ. |
param | string | null | Le champ de la requête en cause, ou null. |
Types et statuts
| Statut | type | Signification |
|---|---|---|
400 | invalid_request_error | La requête est invalide. code désigne la cause et param le champ. |
401 | authentication_error | La clé API est absente ou invalide. |
402 | insufficient_credits | Votre solde, ou la limite de la clé, ne peut pas couvrir le coût maximal de la requête. |
403 | permission_error | Le compte est suspendu. |
404 | not_found | Cet id n’existe pas, l’id appartient à un autre compte, ou une vidéo a dépassé son expires_at. |
409 | conflict | L’objet n’est pas dans un état qui autorise l’appel (video_not_finished), ou conflit d’Idempotency-Key (voir Nouvelles tentatives et idempotence). |
422 | invalid_request_error | La requête était valide, mais sa réponse a été refusée (expansion_refused). Non facturé. |
429 | rate_limit_error | Tous les fournisseurs du modèle sont saturés, votre compte dépasse ses limites de débit, ou trop de vérifications de clé API depuis votre adresse ont échoué. Réessayez après le délai indiqué dans l’en-tête Retry-After. |
500, 501 | server_error | Hyperouter a échoué, ou l’endpoint n’est pas implémenté. Non facturé. |
503 | upstream_error | Un fournisseur a échoué ou n’a pas répondu à temps : code indique lequel (all_venues_failed, upstream_error ou timeout). L’en-tête X-Upstream-Status contient 502 (échec) ou 504 (délai dépassé). |
Hyperouter ne répond jamais 502 ni 504 : ils vous parviendraient sous forme de page brute de notre réseau en périphérie, sans le corps d’erreur. Là où une passerelle répondrait ces statuts, vous recevez 503 avec le corps ci-dessous et le statut de la passerelle dans X-Upstream-Status.
Codes possibles
| code | Statut | Quand |
|---|---|---|
invalid_body | 400 | Un champ du corps ou un paramètre de requête ne peut pas être analysé, est du mauvais type, ou sort de ses valeurs autorisées. param le désigne. |
unsupported_content_type | 400 | /v1/images/generations a reçu un corps multipart/form-data. Envoyez du JSON. param vaut null. |
request_too_large | 413 | Un envoi multipart/form-data dépasse 50 MiB. Envoyez les médias volumineux sous forme d’URL https. |
unknown_model | 400 | Le modèle n’existe pas pour cet endpoint, ou aucun fournisseur ne peut le servir avec vos préférences provider. |
unsupported_parameter | 400 | Un paramètre qui existe pour d’autres modèles n’est pas disponible sur ce modèle. Voir Paramètres propres à chaque modèle. |
invalid_combination | 400 | L’éditeur n’autorise pas ces paramètres ensemble, par exemple des médias de référence avec des images clés. |
invalid_size | 400 | size n’est pas de la forme WIDTHxHEIGHT, ou n’est pas autorisé pour le modèle. |
too_many_images | 400 | n ou le nombre d’images en entrée dépasse la limite. |
invalid_image, invalid_video | 400 | L’URL d’une image ou d’une vidéo n’est pas en https vers un hôte public : une URL data:, une URL http://, une adresse IP ou un nom interne. param désigne le champ. |
image_required | 400 | Le modèle exige une image en entrée et vous n’en avez envoyé aucune (ou il ne fait que modifier, et vous avez appelé generations). |
invalid_seconds | 400 | seconds n’est pas autorisé pour le modèle, ou est absent pour une vidéo donnée par URL. |
unsupported_operation | 400 | Le modèle ne prend pas en charge l’opération (modifier, prolonger ou remixer, ou modifier une image). |
video_not_ready | 400 | La vidéo source n’est pas terminée. |
context_length_exceeded | 400 | Le prompt de chat et max_tokens ne tiennent pas dans le contexte du modèle. |
content_rejected | 400 | Le filtre de sécurité de l’éditeur a refusé l’entrée. |
vendor_rejected | 400 | Le modèle a refusé la requête comme invalide. Vérifiez ses paramètres et ses entrées. |
clip_too_long | 400 | Un clip de référence et les seconds demandées dépassent la limite du modèle (30 s). Non facturé. |
prompt_rejected | 400 | Le prompt demande au modèle d’expansion du prompt ses instructions. Non facturé. Voir Expansion du prompt. |
expansion_refused | 422 | La réécriture du modèle d’expansion du prompt a été refusée ou est revenue vide. Non facturé. Voir Expansion du prompt. |
invalid_api_key | 401 | Voir Authentification. |
insufficient_credits | 402 | Voir Facturation et limites. |
account_suspended | 403 | Le compte est suspendu. |
moderation_not_enabled | 403 | moderation: "low" n’est pas activé pour le compte. Voir Modération. |
feature_not_enabled | 403 | prompt_expand n’est pas activé pour le compte, sur un modèle qui le propose. Ouvrez un ticket de support pour en demander l’accès. Rien n’est réservé ni envoyé au fournisseur. Voir Expansion du prompt. |
model_not_enabled | 403 | Le modèle exige un accès accordé à votre compte. Ouvrez un ticket de support pour le demander. Rien n’est bloqué ni envoyé au fournisseur. |
not_found | 404 | Cet objet n’existe pas. |
video_not_finished | 409 | Vous avez supprimé une vidéo encore en cours de création. |
venue_busy | 429 | Tous les fournisseurs du modèle de chat ont dépassé leur budget de débit. |
rate_limited | 429 | Votre compte dépasse ses requêtes par minute ou ses requêtes simultanées. Voir Limites de débit. |
too_many_auth_failures | 429 | Plus de 30 requêtes provenant de votre adresse en une minute ont utilisé une clé API invalide. Voir Limites de débit. |
all_venues_failed | 503 | Aucun fournisseur n’est en bonne santé, ou tous ont échoué. |
upstream_error | 503 | Une tâche d’image ou de vidéo a échoué au niveau du modèle. Vous n’êtes pas facturé. |
internal, server_error, no_price | 500 | Hyperouter a échoué (no_price : le modèle ne peut pas être tarifé pour le moment). Non facturé. |
not_implemented | 501 | This endpoint is not implemented yet. |
invalid_idempotency_key | 400 | L’en-tête Idempotency-Key dépasse 255 caractères ou n’est pas en ASCII imprimable. Voir Nouvelles tentatives et idempotence. |
idempotency_key_reused | 409 | L’Idempotency-Key a déjà été utilisée avec une requête différente. |
idempotency_key_in_use | 409 | Une requête avec cette Idempotency-Key est encore en cours de démarrage. Réessayez avec la même clé. |
idempotency_key_replayed | 409 | Une chat completion avec cette Idempotency-Key a déjà été exécutée. error.generation_id en est l’id. |
timeout | 503 | Une image synchrone n’était pas prête au bout de 90 secondes. Elle est toujours en cours de création : error.generation_id est l’id à interroger. |
Nouvelles tentatives et idempotence
Une erreur réseau ou un délai dépassé ne vous dit pas si Hyperouter a reçu la requête. Si vous la renvoyez, vous pouvez démarrer une seconde tâche et payer deux fois. Une Idempotency-Key rend la répétition sûre : Hyperouter reconnaît la répétition, ne démarre pas de seconde tâche, ne bloque pas de second montant, et répond à partir de la première requête.
Envoyez-en une sur chaque requête qui coûte de l’argent. Générez une nouvelle valeur aléatoire, par exemple un UUID v4, pour chaque nouvelle requête. Conservez-la avec la requête et envoyez la même valeur chaque fois que vous renvoyez cette requête.
Envoyer une clé
L’en-tête est accepté sur ces endpoints :
| Endpoint | Une répétition renvoie |
|---|---|
POST /v1/images/generations, POST /v1/images/edits | l’image de la première requête, ou son 202 avec le même id sous Prefer: respond-async |
POST /v1/videos, /v1/videos/edits, /v1/videos/extensions, /v1/videos/{id}/remix | l’objet Video de la première requête, dans son état actuel |
POST /v1/chat/completions | 409 idempotency_key_replayed avec l’id de la première requête (voir Chat completions) |
Les OpenAI SDK n’envoient pas cet en-tête d’eux-mêmes. Passez-le comme en-tête supplémentaire ; les SDK le renvoient alors inchangé lors de leurs nouvelles tentatives automatiques.
curl https://api.hyperouter.app/v1/images/generations \ -H "Authorization: Bearer $HYPEROUTER_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7" \ -d '{"model": "x-ai/grok-imagine-image", "prompt": "A lighthouse at dusk", "n": 1}'
import uuid key = str(uuid.uuid4()) # one per request; reuse it when you retry this request img = client.images.generate( model="x-ai/grok-imagine-image", prompt="A lighthouse at dusk", extra_headers={"Idempotency-Key": key}, )
import { randomUUID } from "node:crypto"; const key = randomUUID(); // one per request; reuse it when you retry this request const img = await client.images.generate( { model: "x-ai/grok-imagine-image", prompt: "A lighthouse at dusk" }, { headers: { "Idempotency-Key": key } }, );
Ce que renvoie une répétition
| Vous envoyez | Hyperouter répond |
|---|---|
| Une nouvelle clé | Exécute la requête normalement. |
| La même clé et la même requête, après acceptation de la première | Le résultat de la première requête, comme dans le tableau ci-dessus. Pas de seconde tâche, pas de second blocage, pas de second débit. |
| La même clé et la même requête, alors que la première est encore en cours d’acceptation | Attend la première, puis répond comme ci-dessus. Si la première n’a pas démarré sa tâche au bout de 60 secondes : 409 idempotency_key_in_use. Réessayez avec la même clé. |
| La même clé et une requête différente | 409 idempotency_key_reused. Rien ne s’exécute. Utilisez une nouvelle clé. |
La même clé, après que la première a été refusée avant le démarrage de toute tâche (un 400, un 402, ou un 5xx envoyé sans x-should-retry: false) | Exécute la requête comme une nouvelle, ce qui vous permet de la corriger et de la renvoyer avec la même clé. |
| La même clé, plus de 30 minutes après la première requête | Exécute la requête comme une nouvelle. |
| Une clé de plus de 255 caractères, ou qui n’est pas en ASCII imprimable | 400 invalid_idempotency_key. Rien ne s’exécute. |
Règles
- Portée. Une clé appartient à la clé API qui l’a envoyée. Deux clés API peuvent utiliser la même valeur sans s’influencer.
- Fenêtre. Une clé est honorée pendant 30 minutes après la première requête. Réessayez dans ce délai.
- Même requête. Deux requêtes sont identiques lorsque la méthode, le chemin et le corps correspondent. Le JSON est comparé après analyse : l’ordre des champs et les espaces n’ont pas d’importance. Une image ou une vidéo est une URL dans le corps : c’est l’URL qui est comparée, jamais les octets qu’elle sert.
- Facturation. Une requête effectuée sous une clé est facturée au plus une fois, quel que soit le nombre de répétitions. Une répétition servie à partir de la première requête ne coûte rien.
- Garantie. Une clé ne démarre jamais plus d’une tâche, y compris lorsque deux répétitions arrivent en même temps.
Chat completions
Les réponses de chat ne sont pas rejouées. Une répétition avec la même clé répond 409 avec le code idempotency_key_replayed, et error.generation_id est l’id de la première requête. La requête n’est ni réexécutée ni refacturée. Retrouvez la première requête avec GET /v1/generations/{id} pour voir son statut, sa consommation et son coût. Si la première chat completion a échoué et n’a pas été facturée, sa clé est libérée et une répétition s’exécute comme une nouvelle requête.
{
"error": {
"message": "A request with this Idempotency-Key already ran as generation 019a1f3c-5b7e-7d21-9c4a-2e8f6b0d3a17. Chat replies are not replayed: GET /v1/generations/019a1f3c-5b7e-7d21-9c4a-2e8f6b0d3a17 for its record.",
"type": "conflict",
"code": "idempotency_key_replayed",
"param": null,
"generation_id": "019a1f3c-5b7e-7d21-9c4a-2e8f6b0d3a17"
}
}
Nouvelles tentatives automatiques dans les OpenAI SDK
Les OpenAI SDK réessaient deux fois par défaut une réponse 408, 409, 429 ou 5xx, sauf si la réponse porte l’en-tête x-should-retry: false. Hyperouter envoie x-should-retry: false sur toute réponse pour laquelle une nouvelle tentative démarrerait une seconde tâche ou un second débit :
- le
503timeoutd’une image synchrone, dont la tâche continue et est facturée si elle réussit ; interrogez GET /v1/generations/{id} avec songeneration_id; - un
500après la création de la tâche, par exemple lorsqu’une image terminée ne peut pas être relue ; 409idempotency_key_reusedetidempotency_key_replayed, qu’une nouvelle tentative ne peut pas changer.
Il ne l’envoie jamais sur un 429, sur un 409 idempotency_key_in_use, ni sur un 5xx survenu avant l’existence de toute tâche. Dans ces cas, réessayer est sans risque. Avec une Idempotency-Key, chaque nouvelle tentative est sûre.
Modèles
Liste tous les modèles que votre compte peut appeler à l’instant, avec leurs prix et ce qu’ils prennent en charge. Un modèle sans fournisseur activé n’est pas listé. Certains modèles exigent un accès accordé à votre compte : ils sont listés dès qu’il l’est. Cet endpoint exige une clé API et liste les modèles que le compte de cette clé peut appeler. La réponse peut être mise en cache pendant 60 secondes, par votre client uniquement.
Paramètres
Aucun.
Réponse
{
"data": [{
"id": "x-ai/grok-4.7",
"name": "Grok 4.7",
"kind": "chat",
"context_length": 500000,
"architecture": { "input_modalities": ["text", "image"], "output_modalities": ["text"] },
"pricing": {
"prompt": "0.000002", "completion": "0.000006", "input_cache_read": "0.0000005",
"request": "0", "image": "0", "video_second": "0"
},
"top_provider": { "context_length": 500000, "max_completion_tokens": 32768 },
"response_modes": ["sync", "stream"],
"supported_parameters": ["max_tokens", "temperature", "top_p", "stop", "stream", "tools", "tool_choice", "response_format", "seed", "frequency_penalty", "presence_penalty"],
"extra_parameters": {}
}]
}
| Champ | Type | Description |
|---|---|---|
id | string | L’id du modèle, <provider>/<name>, par exemple x-ai/grok-4.7 ou qwen/qwen-image-2.0. Envoyez-le comme model. Un modèle renommé continue de répondre à son ancien id. |
response_modes | string[] | La manière dont le modèle répond : sync (une réponse retenue), async (envoyez Prefer: respond-async, recevez 202, puis interrogez) et stream ("stream": true). Un modèle qui ne liste que async exige l’en-tête Prefer, et stream ne fonctionne que là où il est listé. La vidéo est toujours asynchrone via la Videos API, avec ou sans l’en-tête. |
name | string | Nom d’affichage. |
kind | string | chat, image ou video. |
context_length | integer | Fenêtre de contexte en tokens. 0 pour les modèles d’image et de vidéo. |
architecture | object | input_modalities et output_modalities. La sortie est ["text"], ["image"] ou ["video"]. |
pricing | object of strings | USD par unité, en chaînes décimales, au palier de base : prompt et completion (par token), input_cache_read (par token en cache), request, image (par image), video_second (par seconde de vidéo). Une vidéo tarifée selon la résolution affiche le prix le plus bas. Une unité qui ne s’applique pas vaut "0". |
top_provider | object | context_length et max_completion_tokens. |
supported_parameters | string[] | Pour le chat, les paramètres OpenAI que le modèle accepte. Pour l’image et la vidéo, les fonctionnalités communes qu’il accepte (resolution, ratio, audio, seed, negative_prompt, first_frame, last_frame, reference_images, reference_videos, prompt_extend). |
operations | string[] | Modèles vidéo uniquement : edit, extend et remix, pour chacune des opérations que le modèle prend en charge. Absent lorsque le modèle n’en prend aucune. |
extra_parameters | object | Les champs de premier niveau propres au modèle, par nom. Chacun a type, values (valeurs autorisées ; vide signifie n’importe laquelle), price_condition (le champ modifie le prix) et description. Voir Paramètres propres à chaque modèle. |
curl https://api.hyperouter.app/v1/models \
-H "Authorization: Bearer $HYPEROUTER_API_KEY"
Erreurs
Aucune propre à cet endpoint.
Modèles de chat
Prix par million de tokens : entrée / entrée en cache / sortie.
| Modèle | Contexte | Prix |
|---|---|---|
x-ai/grok-4.7 | 500K | $2.00 / $0.50 / $6.00 |
x-ai/grok-4.6 | 500K | $2.00 / $0.50 / $6.00 |
x-ai/grok-4.5 | 500K | $2.00 / $0.30 / $6.00 |
x-ai/grok-4.3 | 1M | $1.25 / $0.20 / $2.50 |
x-ai/grok-build-0.1 | 256K | $1.00 / $0.20 / $2.00 |
deepseek/deepseek-v4.1-flash | 1M | $0.15 / $0.003 / $0.60 |
deepseek/deepseek-v4.1-flash-1017 | 1M | $0.15 / $0.003 / $0.60 |
openai/gpt-6-astra | 272K | $10.00 / $1.00 / $50.00 |
openai/gpt-6.1-sol | 272K | $2.00 / $0.10 / $10.00 |
z-ai/glm-5.3 | 1M | $1.40 / $0.26 / $4.40 |
lumina/face-detect | 4K | $0.0013 par requête |
Sur les modèles x-ai/, une requête de 200 000 tokens de prompt ou plus est facturée intégralement aux tarifs de long contexte, qui sont le double de ceux-ci. Les modèles deepseek/ ont un seul tarif quelle que soit la longueur du prompt, raisonnent avant de répondre par défaut (reasoning_effort: "none" le désactive), et comptent leur raisonnement dans max_tokens, au plus 384 000. z-ai/glm-5.3 raisonne toujours : reasoning_effort vaut low, high ou max, et none est refusé. Les modèles openai/ raisonnent aussi et acceptent des prompts de 272 000 tokens au plus.
Chat completions
Crée une réponse de modèle pour une conversation. Le corps est la requête Chat Completions d’OpenAI. Hyperouter ajoute models, provider et moderation.
Paramètres
| Nom | Type | Requis | Valeurs autorisées | Défaut | Description |
|---|---|---|---|---|---|
model | string | Oui | Un id de modèle de chat issu de GET /v1/models | Le modèle à utiliser, par exemple x-ai/grok-4.7. | |
messages | object[] | Oui | Non vide. Rôles system, user, assistant, tool | La conversation jusqu’ici. Les images (parties image_url) sont acceptées lorsque le modèle prend en charge les images. | |
models | string[] | Non | Au plus 5 ids de modèle | Ajout. Modèles de repli, essayés dans l’ordre lorsque tous les fournisseurs de model ont échoué. | |
provider | object | Non | Voir ci-dessous | Ajout. Préférences de routage. | |
moderation | string | Non | auto, low | auto | Ajout. Voir Modération. |
stream | boolean | Non | false | Renvoyer des server-sent events. | |
stream_options | object | Non | {"include_usage": true} | Avec include_usage, le flux se termine par un chunk qui porte usage. | |
max_tokens, max_completion_tokens | integer | Non | 1 ou plus | Le maximum de sortie du modèle | Borne supérieure des tokens générés. Elle fixe aussi le coût maximal d’une requête, qu’Hyperouter bloque avant l’appel (voir Facturation). |
n | integer | Non | 1 à 128 | 1 | Nombre de choix. |
temperature, top_p, seed, frequency_penalty, presence_penalty, logit_bias | number / integer / object | Non | Comme OpenAI | Contrôles d’échantillonnage, transmis au fournisseur. | |
stop | string | string[] | Non | Séquences qui mettent fin à la génération. | ||
tools, tool_choice, parallel_tool_calls | object[], string | object, boolean | Non | Format d’appel de fonctions d’OpenAI | Appel de fonctions. Uniquement des outils de type function : tout autre type est refusé avec 400 unsupported_parameter. | |
response_format | object | Non | {"type":"json_object"} ou un schéma JSON | Sortie structurée. | |
reasoning_effort, logprobs, top_logprobs, user | comme OpenAI | Non | Transmis au fournisseur lorsque le modèle les accepte. |
Les autres champs sont ignorés. supported_parameters de chaque modèle dans GET /v1/models liste exactement ce qu’il accepte. Grok 4.20 et les versions plus récentes ignorent logprobs et top_logprobs, qui ne sont donc pas listés.
L’objet provider
Par défaut, Hyperouter envoie chaque requête de chat au fournisseur en bonne santé dont le prix est le plus bas pour ce modèle, et départage les égalités par le plus court temps récent jusqu’au premier token. Un fournisseur qui renvoie des erreurs à répétition est ignoré jusqu’à son rétablissement. L’objet provider suit le format de requête d’OpenRouter.
| Nom | Type | Requis | Valeurs autorisées | Défaut | Description |
|---|---|---|---|---|---|
sort | string | Non | price, latency, throughput | price | La manière de classer les fournisseurs. |
order | string[] | Non | Noms de fournisseurs | Fournisseurs à essayer en premier, dans l’ordre, par exemple ["xai"]. Un nom de fournisseur est son nom public, quelle que soit la casse (xAI, Qwen), ou la première partie de ses ids de modèle (x-ai, qwen). | |
only | string[] | Non | Noms de fournisseurs | Router uniquement vers ces fournisseurs. | |
ignore | string[] | Non | Noms de fournisseurs | Ne jamais router vers ces fournisseurs. |
Réponse
La chat completion d’OpenAI. L’id est l’id de la requête : retrouvez-la avec GET /v1/generations/{id}. Hyperouter ajoute provider (le nom public du fournisseur qui a exécuté la requête, par exemple xAI) et usage.cost (le coût, en USD, sous forme de nombre JSON).
{
"id": "0194f2c4-7a1e-7b3c-9d02-5f6a1c0e8b21",
"object": "chat.completion",
"model": "x-ai/grok-4.7",
"provider": "xAI",
"choices": [{
"index": 0,
"message": { "role": "assistant", "content": "Hello! How can I help?" },
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 9,
"completion_tokens": 8,
"total_tokens": 17,
"prompt_tokens_details": { "cached_tokens": 0 },
"cost": 0.000066
}
}
Un modèle de réécriture de prompt répond avec un seul choix, un usage de zéro token et un cost fixe par requête.
Streaming
Avec "stream": true, la réponse est un flux de server-sent events au format de chunk d’OpenAI. Il se termine par data: [DONE]. Lorsque vous définissez stream_options.include_usage, le dernier chunk avant [DONE] a un tableau choices vide, un objet usage qui inclut cost, et un champ provider. La consommation est toujours collectée pour la facturation, que vous demandiez ou non ce chunk.
Tant que le premier token n’est pas arrivé, le flux envoie la ligne de commentaire : processing toutes les 15 secondes pour garder la connexion ouverte. Les clients SSE ignorent les commentaires.
Le repli vers un autre fournisseur n’a lieu qu’avant l’envoi du premier token. Si un fournisseur échoue en cours de flux, le flux se termine par data: {"error": {...}} suivi de data: [DONE], et vous êtes facturé pour les tokens déjà produits.
Vous êtes facturé pour les tokens que le fournisseur produit, que vous les lisiez ou non. Un flux que vous interrompez, ou une réponse que vous cessez d’attendre, n’est pas arrêté chez le fournisseur, qui continue et facture sa réponse entière : Hyperouter la lit jusqu’au bout (pendant 5 minutes au plus) et la facture.
Un fournisseur qui a accepté une requête peut être en train de l’exécuter. S’il cesse ensuite de répondre (5 minutes sans token sur un flux, ou plus longtemps que ne prend une réponse de max_tokens) ou si sa réponse s’interrompt avant le premier token, la requête n’est pas envoyée à un autre fournisseur : elle répond 503 avec le code timeout ou upstream_error et error.generation_id, et est facturée sur son montant bloqué, avec usage_estimated: true sur son enregistrement.
Exemple
curl https://api.hyperouter.app/v1/chat/completions \
-H "Authorization: Bearer $HYPEROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "x-ai/grok-4.7",
"models": ["x-ai/grok-4.6"],
"provider": { "sort": "latency" },
"messages": [{ "role": "user", "content": "Hello" }]
}'
Erreurs
| Statut | type | code | param | Quand |
|---|---|---|---|---|
400 | invalid_request_error | invalid_body | le champ | Le corps n’est pas du JSON valide ou dépasse 32 MiB ; model est absent ; models a plus de 5 entrées ; n est hors de 1 à 128 ; max_tokens n’est pas positif ; provider.sort n’est pas autorisé ; moderation n’est ni auto ni low (moderation must be auto or low.) ; messages est vide. Aussi lorsque tous les fournisseurs ont refusé la requête comme invalide. |
400 | invalid_request_error | unknown_model | model ou models | Le modèle n’est pas un modèle de chat, ou n’a aucun fournisseur activé. |
400 | invalid_request_error | unsupported_parameter | tools, response_format, messages ou max_tokens | Le modèle n’accepte pas les outils, un format de réponse ou les images ; un outil n’est pas de type function ; ou aucun fournisseur du modèle ne peut borner sa sortie. |
400 | invalid_request_error | context_length_exceeded | messages | Le prompt et max_tokens dépassent le contexte du modèle. |
402 | insufficient_credits | insufficient_credits | max_tokens | Le solde ou la limite de la clé ne peut pas couvrir le coût maximal de la requête. Le message indique combien de tokens vous pouvez vous permettre. |
429 | rate_limit_error | venue_busy | Tous les fournisseurs du modèle ont dépassé leur budget de débit. | |
429 | rate_limit_error | rate_limited | Votre compte dépasse ses requêtes par minute ou ses requêtes simultanées (voir Limites de débit). Rien n’est bloqué ni transmis. | |
409 | conflict | idempotency_key_replayed, idempotency_key_reused, idempotency_key_in_use | Voir Nouvelles tentatives et idempotence. | |
503 | upstream_error | all_venues_failed | Aucun fournisseur n’est en bonne santé, ou tous ont échoué. Non facturé. | |
503 | upstream_error | upstream_error | Le fournisseur a accepté la requête et sa réponse s’est interrompue avant le premier token. Facturé sur le montant bloqué (voir Streaming). | |
503 | upstream_error | timeout | Le fournisseur a accepté la requête et ne l’a pas terminée à temps. Facturé sur le montant bloqué (voir Streaming). | |
401, 403, 500 | Voir Authentification. | |||
Images
Les deux suivent l’Images API d’OpenAI et prennent un corps JSON. /v1/images/edits prend la forme JSON d’OpenAI : les images sont images, de 1 à 5 URL https. Le images.edit des OpenAI SDK envoie les fichiers d’image en multipart/form-data, et cela fonctionne aussi : l’edge d’Hyperouter conserve chaque fichier (PNG, JPEG ou WebP, 20 MiB chacun, 50 MiB par requête) pendant 3 jours à une URL https://api.hyperouter.app/u/... impossible à deviner, que le fournisseur récupère, puis exécute la requête comme du JSON. Un fichier vidéo est refusé (400 invalid_video) : envoyez une vidéo sous forme d’URL https. Les deux acceptent les fonctionnalités communes ci-dessous et tous les paramètres propres au modèle comme champs de premier niveau.
Paramètres
| Nom | Type | Requis | Valeurs autorisées | Défaut | Description |
|---|---|---|---|---|---|
model | string | Oui | Un id de modèle d’image | Le modèle à utiliser. | |
prompt | string | Generations : oui. Edits : selon le modèle | Texte non vide | Ce qu’il faut produire. | |
images | object[] | Edits : oui | 1 à 5 objets {"image_url": "https://..."}, autant que le modèle en prend. Chaque URL est en https vers un hôte public, jamais une URL data:, une adresse IP ni un nom interne. file_id n’est pas accepté. | Les images à modifier. Chaque URL est transmise telle quelle au fournisseur, qui doit donc pouvoir la récupérer ; une URL qu’il ne peut pas récupérer ou lire fait échouer la tâche avec vendor_rejected, sans aucun débit. Un modèle qui les prend dans un ordre précis l’indique dans ses notes de la référence des modèles. | |
n | integer | Non | 1 à 10, et au plus la limite du modèle | 1 | Nombre d’images. |
size | string | Non | WIDTHxHEIGHT, par exemple 1024x1024 ; le modèle peut autoriser moins de tailles | 1024x1024 | Taille de sortie. |
quality | string | Non | Selon le modèle | Transmis au modèle. | |
response_format | string | Non | url | url | La manière dont l’image est renvoyée : toujours une URL. b64_json est refusé avec 400 unsupported_parameter. |
seed | integer | Non | Si le modèle liste seed | Seed pour une sortie reproductible. | |
negative_prompt | string | Non | Si le modèle le liste | Ce qu’il faut éviter. | |
prompt_extend | boolean | Non | Si le modèle le liste | Désactivé sauf demande | Laisser le modèle enrichir le prompt. |
prompt_expand | boolean | Non | Si le modèle le liste | false | Ajout. Hyperouter réécrit le prompt pour le modèle avant le rendu. Voir Expansion du prompt. |
prompt_expand_model | string | Non | Le slug d’un modèle de chat que votre compte peut appeler | x-ai/grok-4.6 | Ajout. Avec prompt_expand : le modèle qui écrit la réécriture. Sans prompt_expand: true, c’est 400 invalid_body. Voir Expansion du prompt. |
locale | string | Non | Une balise BCP 47, par exemple zh-CN | Anglais | Ajout. Avec prompt_expand : la langue des répliques, si le modèle la parle. |
ratio | string | Non | Si le modèle le liste | Format d’image. | |
resolution | string | Non | 480p, 720p, 1080p, 2K, 4K, selon le modèle | Résolution de sortie. | |
models | string[] | Non | Ids de modèles d’image | Ajout. Modèles de repli. | |
provider | object | Non | only, ignore, order (tableaux de noms de fournisseurs) | Ajout. Préférences de routage. | |
moderation | string | Non | auto, low | auto | Ajout. Voir Modération. |
| champs propres au modèle | comme déclaré | Comme déclaré | Comme déclaré | Voir Paramètres propres à chaque modèle. |
Une fonctionnalité commune que le modèle ne liste pas, comme seed sur un modèle qui ne l’a pas, est refusée avec 400 unsupported_parameter. Elle n’est jamais ignorée en silence, car cela changerait la sortie et le prix.
Réponse
{
"created": 1730000000,
"data": [{ "url": "https://..." }],
"usage": { "cost": 0.02 },
"id": "0194f2c4-7a1e-7b3c-9d02-5f6a1c0e8b21"
}
| Champ | Type | Description |
|---|---|---|
created | integer | Heure Unix de la requête. |
data[].url | string | Avec response_format: "url" : un lien signé, valable 24 heures. GET /v1/generations/{id} en signe un nouveau. |
usage.cost | number | Le coût en USD, sous forme de nombre JSON. |
id | string | L’id de la requête. Utilisez-le avec GET /v1/generations/{id}. |
expanded_prompt | string | null | Ajout. Avec prompt_expand : le prompt qui a servi au rendu. null si rien n’a été réécrit. |
Hyperouter stocke chaque résultat pendant 30 jours, de sorte qu’un lien ne pointe jamais vers un éditeur. Au-delà de 30 jours, l’enregistrement subsiste mais son outputs est vide.
Attendre le résultat
- Sur un modèle dont les
response_modesincluentsync, la requête attend l’image jusqu’à 90 secondes et répond avec son véritable statut :200avec les images, ou l’erreur. Les erreurs de validation, de solde et de capacité passent en premier, avec leur propre statut. - Une image qui n’est pas prête au bout de 90 secondes répond
503avec le codetimeoutet l’en-tête de réponsex-should-retry: false, de sorte que les OpenAI SDK ne la réessaient pas et ne démarrent pas une seconde image. La tâche continue, et l’erreur porte son id dansgeneration_id: interrogez GET /v1/generations/{id} pour obtenir le résultat. Vous n’êtes facturé que si elle réussit. Pour réessayer vous-même en toute sécurité, envoyez une Idempotency-Key : une nouvelle tentative avec la même clé attend la même tâche. - Un modèle dont les
response_modesne contiennent queasyncexigePrefer: respond-async. Sans cet en-tête, la réponse est400avec le codeasync_required. Pour éviter une connexion maintenue sur tout modèle qui liste
async, envoyezPrefer: respond-async(RFC 7240). L’en-tête peut être répété et porter d’autres préférences, par exemplePrefer: wait=10, respond-async. Vous recevez aussitôt202avec l’en-tête de réponsePreference-Applied: respond-async:{ "id": "0194f2c4-7a1e-7b3c-9d02-5f6a1c0e8b21", "status": "queued" }Interrogez GET /v1/generations/{id}, ou recevez un webhook
image.completedouimage.failed. Les webhooks ne se déclenchent pour les images que pour les tâches envoyées avec cet en-tête.
Exemples
curl https://api.hyperouter.app/v1/images/generations \
-H "Authorization: Bearer $HYPEROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "x-ai/grok-imagine-image", "prompt": "A lighthouse at dusk", "n": 1}'
curl https://api.hyperouter.app/v1/images/edits \
-H "Authorization: Bearer $HYPEROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "x-ai/grok-imagine-image", "prompt": "make it night",
"images": [{"image_url": "https://example.com/photo.png"}]}'
Erreurs
| Statut | code | param | Quand |
|---|---|---|---|
400 | unsupported_content_type | Le corps est du multipart/form-data : Send a JSON body; pictures and videos are https URLs. | |
400 | invalid_body | le champ | Le corps n’est pas du JSON valide ; images n’est pas un tableau d’objets avec image_url ; prompt est absent sur generations ; n est inférieur à 1 ; response_format n’est pas url (response_format must be url. ; b64_json est unsupported_parameter) ; resolution n’est pas autorisée ; un champ typé a le mauvais type ; moderation n’est ni auto ni low. |
400 | unknown_model | model | Le modèle n’existe pas pour les images, ou aucun fournisseur ne correspond à vos préférences provider. |
400 | invalid_size | size | size ne ressemble pas à 1024x1024, ou le modèle ne l’autorise pas. |
400 | too_many_images | n ou images | n dépasse 10 ou la limite du modèle ; plus de 5 images ; plus d’images que le modèle n’en accepte. |
400 | image_required | images | Un edit a moins d’images que le modèle n’en exige, ou vous avez appelé generations sur un modèle qui ne fait que modifier (utilisez /v1/images/edits). |
400 | unsupported_operation | images | Le modèle ne modifie pas les images. |
400 | unsupported_parameter | le champ | Le modèle ne prend pas en charge ce champ ; images[i].file_id. |
400 | invalid_combination | le champ | L’éditeur n’autorise pas ces champs ensemble. |
400 | async_required | Le modèle ne répond que de façon asynchrone : envoyez Prefer: respond-async. | |
400 | unsupported_parameter | stream | "stream": true sur un modèle dont les response_modes n’incluent pas stream. |
400 | invalid_image | images[i].image_url | L’URL n’est pas en https vers un hôte public : images[i].image_url must be an https URL. pour une URL data: ou http://. |
400 | content_rejected | Le filtre de sécurité de l’éditeur a refusé l’entrée : The request was rejected by a content safety filter. | |
400 | vendor_rejected | The request was refused by the model. Check its parameters and inputs. | |
400 | invalid_idempotency_key | Voir Nouvelles tentatives et idempotence. | |
402 | insufficient_credits | Le solde ou la limite de la clé ne peut pas couvrir le coût maximal de la requête. | |
409 | idempotency_key_reused, idempotency_key_in_use | Voir Nouvelles tentatives et idempotence. | |
429 | rate_limit_error | Tous les fournisseurs sont saturés (pas de code), ou votre compte dépasse ses requêtes par minute ou ses requêtes simultanées (code: rate_limited, voir Limites de débit). | |
503 | upstream_error | The model failed to produce a result. You were not charged. | |
503 | provider_busy | Le fournisseur est resté à pleine capacité pendant environ deux minutes et n’a pas accepté la tâche. Réessayez plus tard. Rien ne vous a été facturé. | |
500 | server_error, no_price | Hyperouter a échoué, ou le modèle ne peut pas être tarifé pour le moment. Un 500 survenu après la création de l’image porte x-should-retry: false. | |
503 | timeout | L’image n’était pas prête au bout de 90 secondes. Elle est toujours en cours de création : error.generation_id est l’id à interroger. Porte x-should-retry: false. |
Le message d’une tâche échouée se termine par la raison donnée par le fournisseur, s’il en a donné une, après Provider:, afin de distinguer un prompt refusé, un fournisseur saturé et une panne. Les URL qu’elle contient sont remplacées par <url>.
Modèles d’image
| Modèle | Fonction | Prix |
|---|---|---|
x-ai/grok-imagine-image | Générer et modifier. Jusqu’à 10 images, jusqu’à 5 images en entrée. | $0.02 par image |
x-ai/grok-imagine-image-2.0 | Générer et modifier, comme ci-dessus. | À partir de $0.04 par image |
qwen/qwen-image-2.0 | Générer et modifier (1 à 3 images en entrée). n de 1 à 6. | $0.035 par image |
bytedance/seedream-5.0-flash | Générer et modifier (1 à 10 images en entrée). Une image 2K par requête, sans filigrane. | $0.018 par image |
bytedance/seedream-5.0-lite | Générer et modifier, comme ci-dessus. | $0.035 par image |
Certains modèles exigent un accès accordé à votre compte. La référence des modèles du tableau de bord liste tous les modèles que votre compte peut appeler, avec leurs paramètres, leurs prix et leurs notes.
Vidéos
La vidéo suit la Videos API d’OpenAI. Une vidéo est une tâche. Un appel de création, de modification, de prolongation ou de remix répond aussitôt 200 avec l’objet Video au statut queued. Vous interrogez GET /v1/videos/{id} jusqu’à ce que le statut soit completed, ou vous recevez un webhook. Prefer ne change rien ici : les vidéos sont toujours asynchrones.
| Endpoint | Fonction |
|---|---|
POST /v1/videos | Créer une vidéo à partir d’un prompt, avec un input_reference facultatif. |
POST /v1/videos/edits | Modifier ou agrandir une vidéo terminée. Uniquement les modèles qui listent edit dans operations. |
POST /v1/videos/extensions | Prolonger une vidéo terminée. Uniquement les modèles qui listent extend. |
POST /v1/videos/{id}/remix | Nouveau prompt sur une vidéo terminée, même modèle. Uniquement les modèles qui listent remix. |
GET /v1/videos | Lister vos vidéos. |
GET /v1/videos/{id} | L’objet Video. |
GET /v1/videos/{id}/content | Le MP4 ou la miniature. |
DELETE /v1/videos/{id} | Supprimer une vidéo. |
Créer une vidéo
Le corps est du JSON, sur tous les endpoints vidéo ; le videos.create des OpenAI SDK avec un fichier d’image input_reference est aussi accepté, le fichier étant traité comme pour les modifications d’images. Chaque image et chaque vidéo est une URL https vers un hôte public, transmise telle quelle au fournisseur : il doit pouvoir la récupérer, et une URL qu’il ne peut pas récupérer ou lire fait échouer la vidéo avec vendor_rejected, sans aucun débit. Une URL data:, une URL http://, une adresse IP ou un nom interne est refusé avec 400 invalid_image ou 400 invalid_video. Un corps multipart/form-data est refusé avec 400 unsupported_content_type.
| Nom | Type | Requis | Valeurs autorisées | Défaut | Description |
|---|---|---|---|---|---|
model | string | Oui | Un id de modèle vidéo | Le modèle à utiliser. | |
prompt | string | Oui | Texte non vide | Ce qu’il faut produire. | |
seconds | string | integer | Non | Selon le modèle | La première valeur autorisée du modèle, sinon 4 s (ou le maximum du modèle s’il est inférieur) | Durée de la vidéo. "8" et 8 sont équivalents. |
size | string | Non | WIDTHxHEIGHT | La hauteur détermine la résolution, sauf si vous envoyez resolution : jusqu’à 480 donne 480p, jusqu’à 720 donne 720p, jusqu’à 1080 donne 1080p, jusqu’à 1440 donne 2K, au-delà 4K. Le modèle doit autoriser cette résolution. | |
input_reference | object | Si le modèle exige une image | {"image_url": "https://..."}, une URL https | La première image de la vidéo. file_id n’est pas accepté. | |
resolution | string | Non | 480p, 720p, 1080p, 2K, 4K, selon le modèle | La première résolution du modèle | Résolution de sortie. Elle modifie le prix. |
ratio | string | Non | Si le modèle le liste | Format d’image. | |
audio | boolean | Non | Si le modèle produit du son | false | Produire du son. |
seed | integer | Non | Si le modèle le liste | Seed pour une sortie reproductible. | |
negative_prompt | string | Non | Si le modèle le liste | Ce qu’il faut éviter. | |
prompt_extend | boolean | Non | Si le modèle le liste | Désactivé sauf demande | Laisser le modèle enrichir le prompt. |
prompt_expand, locale | boolean, string | Non | Comme pour les images | false | Ajout. Voir Expansion du prompt. |
prompt_expand_model | string | Non | Comme pour les images | x-ai/grok-4.6 | Ajout. Avec prompt_expand : le modèle qui écrit la réécriture. Voir Expansion du prompt. |
first_frame, last_frame | string | Non | Une URL https d’une image | Images clés. | |
reference_images, reference_videos | string[] | Non | URL https | Médias de référence. Ils ne peuvent pas être combinés avec des images clés, selon la règle de l’éditeur. | |
models, provider | string[], object | Non | Comme pour les images | Ajout. Modèles de repli et préférences de routage. | |
moderation | string | Non | auto, low | auto | Ajout. Voir Modération. |
| champs propres au modèle | comme déclaré | Comme déclaré | Comme déclaré | Voir Paramètres propres à chaque modèle. |
Modifier, prolonger et remixer
| Endpoint | Corps (JSON) |
|---|---|
POST /v1/videos/edits | model, video (requis), prompt, resolution et les fonctionnalités communes. video est {"id": "<your video id>"} (une vidéo terminée qui vous appartient) ou {"url": "https://..."}. model prend par défaut le modèle de la vidéo source lorsque vous envoyez un id. |
POST /v1/videos/extensions | model, video (requis), prompt, seconds. Les nouvelles secondes suivent les mêmes règles qu’une création. |
POST /v1/videos/{id}/remix | prompt (requis). Le modèle est celui de la vidéo source. |
La vidéo source doit être terminée. Une vidéo donnée par URL est une URL https, transmise telle quelle au fournisseur, comme une image. Si vous donnez une vidéo par URL, seconds est requis sur les modèles qui n’ont pas de maximum fixe.
Lister, lire, télécharger, supprimer
| Endpoint | Paramètres | Réponse |
|---|---|---|
GET /v1/videos | Query : after (un id de vidéo), limit (1 à 100, 20 par défaut), order (desc par défaut, ou asc) | {"object":"list","data":[Video],"first_id","last_id","has_more"}. Les vidéos ayant dépassé leur expires_at sont exclues. |
GET /v1/videos/{id} | L’objet Video. | |
GET /v1/videos/{id}/content | Query : variant (video par défaut, ou thumbnail) | 302 Found vers un lien signé donnant les octets (video/mp4, ou le type de la miniature), valable 15 minutes. Les clients HTTP et les OpenAI SDK le suivent. 404 not_found avant la fin ou lorsqu’il n’y a pas de miniature. |
DELETE /v1/videos/{id} | {"id","object":"video.deleted","deleted":true}. Répond 409 video_not_finished tant que la tâche s’exécute. Une vidéo supprimée répond 404. | |
L’objet Video
{
"id": "0194f2c4-7a1e-7b3c-9d02-5f6a1c0e8b21",
"object": "video",
"model": "x-ai/grok-imagine-video",
"status": "completed",
"progress": 100,
"prompt": null,
"seconds": "8",
"size": "",
"created_at": 1730000000,
"completed_at": 1730000137,
"expires_at": 1732592000,
"error": null,
"remixed_from_video_id": null,
"usage": { "cost": 0.4, "seconds": 8 }
}
| Champ | Type | Description |
|---|---|---|
status | string | queued, in_progress, completed ou failed. |
progress | integer | 0 à 100. |
prompt | string | null | Le prompt n’est renvoyé que pendant l’exécution de la tâche. L’objet terminé renvoie null. |
seconds | string | Durée de la vidéo, sous forme de chaîne, comme chez OpenAI. |
size | string | Le size que vous avez envoyé, le cas échéant. |
expires_at | integer | Heure Unix : created_at plus 30 jours. Passé ce délai, GET /v1/videos/{id} et /content répondent 404 not_found et la vidéo est exclue de la liste. Téléchargez ce que vous voulez conserver avant. |
error | object | null | Pour une tâche échouée : {"code", "message"}, par exemple content_rejected. |
remixed_from_video_id | string | null | La vidéo source d’une modification, d’une prolongation ou d’un remix. |
usage | object | null | Renseigné une fois la tâche réglée : cost (USD, un nombre JSON) et seconds (entier). |
expanded_prompt | string | null | Ajout. Avec prompt_expand : le prompt qui a servi au rendu, une fois la tâche soumise. Conservé 30 jours, puis null. |
Une vidéo est facturée sur les secondes que vous demandez. Le montant est bloqué à l’avance, puis libéré intégralement si la tâche échoue.
Exemple : x-ai/grok-imagine-video
Le modèle x-ai/grok-imagine-video produit une vidéo à partir d’un prompt, avec une image de départ facultative. seconds va de 1 à 15. Prix : $0.050 par seconde.
curl https://api.hyperouter.app/v1/videos \
-H "Authorization: Bearer $HYPEROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "x-ai/grok-imagine-video",
"prompt": "She turns to the camera and smiles",
"input_reference": { "image_url": "https://example.com/portrait.png" },
"seconds": 8
}'
{
"id": "0194f2c4-7a1e-7b3c-9d02-5f6a1c0e8b21",
"object": "video",
"model": "x-ai/grok-imagine-video",
"status": "queued",
"progress": 0,
"prompt": "She turns to the camera and smiles",
"seconds": "8",
"size": "",
"created_at": 1730000000,
"completed_at": null,
"expires_at": 1732592000,
"error": null,
"remixed_from_video_id": null,
"usage": null
}
Cette tâche est facturée 8 × $0.050 = $0.40, de sorte que l’objet réglé affiche "usage": {"cost": 0.4, "seconds": 8}.
Erreurs
| Statut | code | param | Quand |
|---|---|---|---|
400 | unsupported_content_type | Le corps est du multipart/form-data : Send a JSON body; pictures and videos are https URLs. | |
400 | invalid_body | le champ | Le corps n’est pas du JSON valide ; prompt est vide ; video n’est pas un objet avec id ou url ; input_reference n’est pas un objet avec image_url ; limit, after ou variant n’est pas valide ; un champ typé a le mauvais type ; resolution n’est pas autorisée ; moderation n’est ni auto ni low. |
400 | unknown_model | model | Le modèle n’existe pas pour les vidéos. |
400 | invalid_seconds | seconds | seconds n’est pas autorisé pour le modèle (le message liste les valeurs autorisées), ou est requis pour une vidéo donnée par URL. |
400 | invalid_size | size | size ne ressemble pas à 1280x720. |
400 | unsupported_parameter | le champ | Le modèle ne prend pas en charge ce champ ; la résolution n’est pas disponible (resolution ou size) ; audio sur un modèle sans son ; input_reference.file_id. |
400 | unsupported_operation | model | Le modèle ne liste pas l’opération (modifier, prolonger ou remixer). |
400 | invalid_combination | le champ | Des médias de référence avec des images clés, selon la règle de l’éditeur. |
400 | image_required | input_reference | This model needs an input_reference picture. |
400 | video_not_ready | video | La vidéo source n’est pas terminée. |
400 | invalid_image, invalid_video | le champ | L’URL d’une image (invalid_image) ou d’une vidéo (invalid_video : reference_videos[i], video.url) n’est pas en https vers un hôte public, par exemple une URL data: ou http:// : <field> must be an https URL. param est le champ, par exemple input_reference.image_url, first_frame ou reference_images[1]. Une URL est transmise telle quelle au fournisseur : une URL que le fournisseur ne peut pas récupérer ou lire fait échouer la vidéo avec vendor_rejected, sans aucun débit. |
400 | clip_too_long | Le clip de référence et les seconds demandées dépassent la limite du modèle : The reference clip plus the requested seconds run past the model's limit of 30 s. Send a shorter clip or fewer seconds. You were not charged. Il figure dans error.code de l’objet Video. | |
400 | content_rejected, vendor_rejected | La tâche a échoué chez l’éditeur. Cela apparaît dans error.code de l’objet Video. | |
402 | insufficient_credits | Le solde ou la limite de la clé ne peut pas couvrir le montant bloqué. | |
404 | not_found | Cette vidéo n’existe pas, ne vous appartient pas, a été supprimée ou a dépassé expires_at ; ou le contenu n’est pas prêt. | |
409 | video_not_finished | Vous avez supprimé une vidéo encore en cours de création. | |
409 | idempotency_key_reused, idempotency_key_in_use | Voir Nouvelles tentatives et idempotence. | |
429, 503, 500 | Comme pour les images. Un 500 survenu après la création de la vidéo porte x-should-retry: false. | ||
Modèles vidéo
| Modèle | Prix par seconde de vidéo | Notes |
|---|---|---|
x-ai/grok-imagine-video | À partir de $0.050 | Entrée texte, image ou vidéo. 15 s au plus. Prend en charge edit. |
x-ai/grok-imagine-video-1.5 | À partir de $0.080 | Entrée texte, image ou référence. 15 s au plus. |
x-ai/grok-imagine-video-1.5-lite | À partir de $0.020 | Comme ci-dessus, plus petit et moins cher. |
bytedance/seedance-2.0 | À partir de $0.0431892 | Entrée texte, première et dernière image, ou images de référence, audio facultatif. 4 à 15 s. 480p, 720p, 1080p ou 4K ; le tarif indiqué est celui du 480p. |
bytedance/seedance-2.0-fast | À partir de $0.0331452 | Entrée texte, première et dernière image, ou images de référence, audio facultatif. 4 à 15 s. 480p ou 720p ; le tarif indiqué est celui du 480p. |
bytedance/seedance-2.0-mini | À partir de $0.0210924 | Entrée texte, première et dernière image, ou images de référence, audio facultatif. 4 à 15 s. 480p ou 720p ; le tarif indiqué est celui du 480p. |
bytedance/seedance-2.5 | À partir de $0.0642816 | Entrée texte, première et dernière image, ou images de référence, audio facultatif. 4 à 15 s. 480p, 720p ou 1080p ; le tarif indiqué est celui du 480p. |
lumina/berry-1.0 | À partir de $0.050 | Entrée texte, image ou référence, audio facultatif. 30 s au plus. 480p, 720p ou 1080p ; le tarif indiqué est celui du 480p. |
minimax/minimax-h3 | À partir de $0.080 | Entrée texte, première et dernière image, ou images de référence, sans audio. 4 à 15 s, en 768p ou 2K. |
alibaba/wan3.0 | À partir de $0.050 | Entrée texte, image ou référence, audio facultatif. 30 s au plus. 480p, 720p ou 1080p ; le tarif indiqué est celui du 480p. |
La référence des modèles du tableau de bord liste tous les modèles vidéo que votre compte peut appeler.
Generations
Renvoie l’enregistrement de l’une de vos requêtes, de n’importe quel type : son statut, sa consommation, son coût, ses durées et, pour les images et les vidéos, des liens signés vers les sorties. Utilisez-le pour interroger une requête d’image envoyée avec Prefer: respond-async et pour rapprocher vos dépenses. Le texte des prompts et des completions ne figure jamais dans l’enregistrement. Hyperouter les conserve chiffrés pendant 180 jours uniquement pour respecter ses obligations légales, et aucune API ni page du tableau de bord ne les renvoie (Politique de confidentialité).
Paramètres
| Nom | Dans | Type | Requis | Description |
|---|---|---|---|---|
id | path | string (UUID) | Oui | L’id d’une chat completion, d’une réponse d’image ou d’un objet Video. |
Réponse
{
"data": {
"id": "0194f2c4-7a1e-7b3c-9d02-5f6a1c0e8b21",
"kind": "chat",
"model": "x-ai/grok-4.7",
"provider_name": "xAI",
"status": "done",
"created_at": "2026-10-24T08:12:00Z",
"finished_at": "2026-10-24T08:12:02Z",
"usage": {
"input_tokens": 120, "output_tokens": 300, "cache_read_tokens": 0,
"image": 0, "video_seconds": 0, "cost": 0.00204
},
"usage_estimated": false,
"ttft_ms": 320,
"latency_ms": 2100,
"error": null,
"outputs": []
}
}
| Champ | Type | Description |
|---|---|---|
kind | string | chat, image ou video. |
provider_name | string | null | Le fournisseur qui a servi une requête de chat terminée. null pour les images et les vidéos. |
status | string | queued, submitting, running, done ou failed. |
created_at, finished_at | string | null | RFC 3339 UTC. finished_at vaut null tant que la requête n’est pas terminée. |
usage | object | input_tokens, output_tokens, cache_read_tokens, image, video_seconds et cost. cost est le coût en USD, un nombre JSON. Les compteurs valent 0 tant que la requête n’est pas terminée. |
usage_estimated | boolean | true lorsque le fournisseur n’a envoyé aucun décompte de tokens et qu’Hyperouter les a comptés. |
ttft_ms, latency_ms | integer | null | Temps jusqu’au premier token et temps total, en millisecondes. |
error | object | null | {"code", "message"} lorsque la requête a échoué. |
outputs | object[] | Pour les images et les vidéos : [{"url", "expires_at"}], des liens signés valables 24 heures. Disponibles pendant 30 jours après la requête ; ensuite outputs est vide et l’enregistrement subsiste. Toujours vide pour le chat. |
expanded_prompt | string | null | Pour les images et les vidéos envoyées avec prompt_expand : le prompt qui a servi au rendu. Conservé 30 jours après la requête, puis null. |
curl https://api.hyperouter.app/v1/generations/0194f2c4-7a1e-7b3c-9d02-5f6a1c0e8b21 \
-H "Authorization: Bearer $HYPEROUTER_API_KEY"
Erreurs
| Statut | type | code | param | Quand |
|---|---|---|---|---|
404 | not_found | not_found | id | No generation with that id. L’id n’est pas un UUID, n’existe pas, appartient à un autre compte ou a été supprimé. |
500 | server_error | server_error | Hyperouter n’a pas pu lire ou signer l’enregistrement. | |
401, 403 | Voir Authentification. | |||
Paramètres propres à chaque modèle
Certains modèles ont des champs que d’autres n’ont pas. Ce sont les paramètres supplémentaires. Vous les envoyez comme champs de premier niveau du corps de la requête, comme n’importe quel autre champ. Tous les OpenAI SDK peuvent les envoyer (extra_body en Python, propriétés supplémentaires en JavaScript).
GET /v1/models liste les paramètres supplémentaires de chaque modèle dans extra_parameters. Chaque entrée comporte :
| Champ | Type | Description |
|---|---|---|
type | string | L’un de string, integer, number, boolean, array, object. |
values | array | Les valeurs autorisées. Vide signifie n’importe quelle valeur du type. |
price_condition | boolean | true lorsque le champ modifie le prix. |
description | string | Ce que fait le champ. |
La référence des modèles du tableau de bord décrit les paramètres supplémentaires de chaque modèle que votre compte peut appeler.
Règles
- Un paramètre connu que le modèle n’a pas est refusé :
400 invalid_request_erroravec le codeunsupported_parameter,paramdéfini sur le nom du champ (par exempleloras) et le messageThis model does not support "loras".Un paramètre est connu lorsqu’un modèle du catalogue le déclare. La même règle s’applique aux fonctionnalités communes (resolution,ratio,audio,seed,negative_prompt,first_frame,last_frame,reference_images,reference_videos,prompt_extend). Rien n’est ignoré en silence, car cela changerait la sortie et le prix. - Une valeur du mauvais type est refusée avec
400 invalid_body,paramdéfini sur le nom et un message tel queloras must be of type array. - Une valeur hors de
valuesest refusée avec400 invalid_bodyet le message<name> must be one of [...]. - Un champ qu’aucun modèle ne déclare est ignoré, comme l’API d’OpenAI ignore les champs inconnus.
- Chaque modèle vérifie ses paramètres selon son propre schéma : valeurs autorisées, minimum et maximum, champs requis et longueurs de listes. Une valeur hors schéma répond
400 invalid_bodyavecparamdésignant le champ, par exempleseconds must be one of 5, 8. - Une combinaison qu’un éditeur n’autorise pas, comme des médias de référence avec des images clés, répond
400 invalid_combinationavec la raison. Les vérifications s’exécutent avant tout débit. - Les champs qui modifient le prix, comme
resolutionetaudio, sont inclus dans le montant bloqué à l’avance, qui est donc exact.
Fonctionnalités communes
Ces champs portent le même nom sur tous les modèles qui les ont. Un modèle liste ceux qu’il accepte dans supported_parameters.
| Champ | Signification |
|---|---|
resolution | 480p, 720p, 1080p, 2K ou 4K, selon le modèle. |
ratio, seed, negative_prompt, prompt_extend, audio | Comme leur nom l’indique. audio et prompt_extend sont désactivés sauf demande. |
first_frame, last_frame | Images clés pour la vidéo. |
reference_images, reference_videos | Médias de référence pour la vidéo et la modification d’images. |
Expansion du prompt
Avec "prompt_expand": true, Hyperouter réécrit votre prompt pour le modèle avant le rendu : une description plus complète pour une image, un script seconde par seconde pour une vidéo. Elle est désactivée par défaut : le prompt part tel quel. Seul un modèle dont supported_parameters liste prompt_expand l’accepte, et uniquement pour créer une image ou une vidéo ; sur tout autre modèle, et pour une modification, une extension ou un remix de vidéo, elle est refusée avec 400 unsupported_parameter. Elle ne peut pas non plus être combinée avec prompt_extend: true (400 invalid_body).
L’expansion du prompt est disponible pour un compte une fois que Hyperouter l’a activée ; ouvrez un ticket de support pour en demander l’accès. D’ici là, GET /v1/models ne liste prompt_expand pour aucun modèle, et une requête avec prompt_expand: true sur un modèle qui le propose répond 403 permission_error, code feature_not_enabled, param prompt_expand, sans rien réserver ni envoyer au fournisseur.
- Ce qui a servi au rendu. La réponse image, l’objet vidéo et
GET /v1/generations/{id}contiennentexpanded_prompt, le prompt reçu par le modèle. Il est conservé 30 jours après la requête, puis renvoyé ànull.promptreste votre propre texte. - Modèle rédacteur.
prompt_expand_modeldésigne le modèle de chat qui écrit la réécriture ; par défaut,x-ai/grok-4.6. Il n’est valide qu’avecprompt_expand: true(sinon400 invalid_body). Un modèle inexistant ou qui n’est pas un modèle de chat donne400 unknown_model, et un modèle que votre compte ne peut pas appeler donne403 model_not_enabled, tous deux avant tout blocage. Un rédacteur qui lit les images reçoit celles de la requête ; sinon il écrit à partir du texte seul. - Prix. La réécriture est facturée sur la même requête, aux prix par token du modèle qui l’a écrite (
prompt_expand_model, sinonx-ai/grok-4.6) pour les tokens utilisés, et son montant maximal est bloqué d’avance avec le rendu. La référence des modèles détaille chaque modèle. - Quand elle ne s’exécute pas. Si la réécriture échoue, expire ou ne peut pas être utilisée, le rendu se fait avec votre prompt tel quel,
expanded_promptvautnullet rien n’est facturé. - Langue. Les répliques d’une vidéo suivent
locale(sinon l’anglais) lorsque le modèle parle cette langue.
La réécriture comme modèle de chat
Un compte doté de l’expansion du prompt dispose aussi d’un modèle de chat qui renvoie la réécriture au lieu de la rendre ; votre référence des modèles le nomme. Appelez-le sur POST /v1/chat/completions avec exactement un message user : son texte est le prompt, et ses parties image_url (URL https, 5 au plus) sont les images ; une URL data: ou http:// renvoie 400 invalid_image avec param valant messages. target_model est obligatoire : un modèle qui liste prompt_expand. seconds, locale et negative_prompt sont facultatifs. Une cible vidéo accompagnée d’une image est écrite à partir de cette première image. Il ne diffuse pas en streaming (stream: true renvoie 400 unsupported_parameter), et tout autre message, message system compris, renvoie 400 invalid_body.
Ce modèle de chat utilise toujours x-ai/grok-4.6 ; il n’accepte pas prompt_expand_model. choices[0].message.content est une chaîne JSON, {"prompt": "...", "negative_prompt": "..."}, plus "beats" (une ligne par seconde) pour une cible vidéo. Il est facturé aux prix par token de x-ai/grok-4.6, indiqués dans usage. Un prompt qui demande les instructions du modèle renvoie 400 prompt_rejected ; une réécriture refusée ou vide renvoie 422 expansion_refused, et une réécriture en échec 503 upstream_error. Aucun de ces cas n’est facturé.
Modération
Le champ moderation est celui d’OpenAI. Il fonctionne sur /v1/chat/completions, /v1/images/generations, /v1/images/edits et /v1/videos avec ses appels de modification, de prolongation et de remix.
| Valeur | Signification |
|---|---|
auto (par défaut) | Le filtrage propre à l’éditeur s’applique. Hyperouter n’envoie rien de plus. |
low | Hyperouter envoie la désactivation du filtrage prévue par le fournisseur, sur les modèles où le fournisseur en propose une. Sur les autres modèles, low est ignoré sans erreur, comme le fait OpenAI. L’entrée de chaque modèle dans votre référence des modèles indique s’il en propose une. Envoyez moderation dans le corps : un en-tête ou un champ de filtrage propre au fournisseur n’est pas transmis sur ces endpoints. |
Toute autre valeur est refusée : 400 invalid_request_error, code invalid_body, param moderation, message moderation must be auto or low.
low est disponible pour un compte une fois qu’Hyperouter l’a activé ; ouvrez un ticket de support pour le demander. D’ici là, une requête avec low répond 403 permission_error, code moderation_not_enabled, param moderation, et n’est pas envoyée au fournisseur.
{
"model": "qwen/qwen-image-2.0",
"prompt": "...",
"moderation": "low"
}
La réponse n’indique pas si la désactivation a été utilisée. Les politiques des Conditions d’utilisation continuent de s’appliquer. Une requête que le filtre de l’éditeur refuse échoue avec 400 content_rejected et n’est pas facturée.
Webhooks
Au lieu d’interroger, un de vos endpoints peut recevoir une requête lorsqu’une tâche se termine. Ajoutez des endpoints dans le tableau de bord. Le format est celui des webhooks d’OpenAI, signé selon le schéma Standard Webhooks, de sorte que les OpenAI SDK les vérifient.
| Événement | Envoyé quand |
|---|---|
video.completed, video.failed | Une tâche vidéo se termine. |
image.completed, image.failed | Une tâche d’image que vous avez envoyée avec Prefer: respond-async se termine. |
raw.completed, raw.failed | La tâche d’un appel brut se termine (comptes dotés des appels bruts) : facturée, ou son blocage libéré. Un appel brut qui répond directement n’en envoie aucun. |
Le payload porte un id, jamais un résultat, un prompt ou un coût. Récupérez l’objet avec votre clé API : data.id est l’id que prennent GET /v1/videos/{id} et GET /v1/generations/{id}. Pour une tâche brute, c’est le X-Generation-Id renvoyé par la création.
{
"id": "evt_0194f2c4-7a1e-7b3c-9d02-5f6a1c0e8b21",
"object": "event",
"type": "video.completed",
"created_at": 1761300000,
"data": { "id": "0194f2c4-7a1e-7b3c-9d02-5f6a1c0e8b21" }
}
En-têtes et vérification
Chaque livraison est un POST avec content-type: application/json et ces en-têtes :
webhook-id: l’id de l’événement. Il est identique à chaque nouvelle tentative : utilisez-le pour dédupliquer.webhook-timestamp: secondes Unix.webhook-signature:v1,suivi du HMAC-SHA256 en base64 deid.timestamp.body, avec le secret de l’endpoint comme clé.
Le secret de signature commence par whsec_. Il n’est affiché qu’une fois, à la création de l’endpoint et lors de sa rotation. Vérifiez le corps brut de la requête, avant de l’analyser :
// Node, with the OpenAI SDK
const event = client.webhooks.unwrap(rawBody, req.headers, process.env.HYPEROUTER_WEBHOOK_SECRET);
if (event.type === "video.completed") {
const video = await client.videos.retrieve(event.data.id);
}
unwrap lève une exception lorsque la signature ne se vérifie pas ; répondez à une telle requête par un statut d’erreur. L’appel suivant utilise la même URL de base que le reste de cette API.
Endpoints, nouvelles tentatives et limites
- Un endpoint doit être en
httpssur le port 443 (ou sans port) et un nom d’hôte, pas une adresse IP. L’hôte doit se résoudre en une adresse publique ; Hyperouter vérifie à nouveau lors de la connexion. Les redirections ne sont pas suivies. - Un compte a au plus 10 endpoints. Chaque endpoint choisit les types d’événements qu’il souhaite.
- Un
2xxen moins de 10 secondes est un succès. Tout le reste est retenté après environ 5 secondes, 1 minute, 5 minutes, 30 minutes, 2 heures, 5 heures, 10 heures et 10 heures, puis la livraison est marquée comme échouée. - Un endpoint dont toutes les livraisons échouent pendant 3 jours est désactivé, et le tableau de bord en indique la raison. Réactivez-le après avoir corrigé le récepteur.
- Le tableau de bord liste les livraisons de chaque endpoint avec leur statut, le nombre de tentatives, le dernier statut HTTP et la dernière erreur. Il propose Renvoyer (même id d’événement) et Envoyer un événement de test, qui livre un événement
webhook.testdontdata.idest l’id de l’endpoint.
Serveur MCP
Un assistant IA peut travailler avec votre compte Hyperouter via le Model Context Protocol (MCP). Le serveur gère le tableau de bord : clés API, activité, crédits, tickets, webhooks et liste des modèles. Il n’exécute pas de modèles. Les appels aux modèles continuent d’aller vers /v1 avec une clé API.
Le serveur parle Streamable HTTP et JSON-RPC 2.0. Il prend en charge les révisions MCP 2025-11-25 et 2025-06-18. Il est sans état : il n’y a pas de sessions, et GET /mcp répond 405.
Jetons d’accès
Un client MCP s’authentifie avec un jeton d’accès du tableau de bord, pas avec une clé API.
- Créez un jeton dans le tableau de bord. Donnez-lui un nom, une portée et, facultativement, une expiration.
- Un jeton commence par
hr_dt_. Il n’est affiché qu’une fois. Hyperouter n’en stocke que le hash. - Un utilisateur du compte peut détenir au plus 25 jetons non expirés et non révoqués. Révoquez un jeton dans le tableau de bord pour l’arrêter immédiatement.
- Un jeton ne fonctionne pas sur
/v1, et une clé API ne fonctionne pas sur/mcp. - Un jeton agit comme l’utilisateur qui l’a créé, avec les permissions de cet utilisateur. Les permissions sont vérifiées à chaque message : un changement de rôle s’applique donc dès l’appel suivant.
| Portée | Outils que le jeton peut appeler |
|---|---|
read | Les outils qui ne font que lire des données. |
write | Tous les outils que l’utilisateur a la permission d’utiliser. |
Envoyez le jeton comme bearer token :
Authorization: Bearer hr_dt_...
Protocole
| Méthode | Réponse |
|---|---|
initialize | La version du protocole (celle du client, si elle est prise en charge ; sinon 2025-11-25), la capacité tools et les informations du serveur. |
ping | Un résultat vide. |
tools/list | Les outils que l’utilisateur et la portée du jeton autorisent. |
tools/call | Le résultat d’un outil. |
Une notification, ou une réponse adressée au serveur, répond 202 sans corps. Un lot JSON-RPC est refusé avec l’erreur -32600. Un message ne doit pas dépasser 1 MiB. Un en-tête MCP-Protocol-Version inconnu répond 400. Une requête de navigateur doit provenir de https://dash.hyperouter.app ; un client qui n’envoie pas d’en-tête Origin n’est pas concerné.
curl https://api.hyperouter.app/mcp \
-H "Authorization: Bearer $HYPEROUTER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}'
Outils
tools/list renvoie l’ensemble actuel des outils. Chaque outil correspond à une route du tableau de bord et porte un JSON Schema pour ses arguments. Les outils couvrent :
- Compte et clés :
get_me,list_api_keys,create_api_key,update_api_key. - Activité et crédits :
list_activity,get_activity,get_activity_summary,get_credits,get_topup_fee. - Tickets :
list_tickets,create_ticket,get_ticket,reply_to_ticket,close_ticket. - Webhooks :
list_webhooks,create_webhook,update_webhook,rotate_webhook_secret,delete_webhook,list_webhook_deliveries,resend_webhook_delivery,send_test_webhook. - Modèles :
list_models. - Les outils du personnel, avec le préfixe
admin_, n’apparaissent que pour les utilisateurs qui détiennent la permission du personnel.
Un outil répond avec un seul élément de contenu texte qui contient le corps JSON de la route. Lorsque la route échoue, le résultat porte isError: true et le texte <message> (<code>, HTTP <status>). Un outil inconnu, ou que votre jeton ne peut pas voir, donne l’erreur JSON-RPC -32602.
Approbations
Une écriture sensible, comme créditer un compte, n’est pas exécutée immédiatement. L’outil ne l’exécute pas. Il répond avec status défini sur approval_required et une approval_url sur le tableau de bord. L’utilisateur ouvre le lien, confirme avec un second facteur et approuve l’action. Une approbation expire au bout de 24 heures. L’utilisateur peut aussi la rejeter.
Facturation et limites
- Les requêtes sont payées sur un solde prépayé en USD, facturées au tarif public du fournisseur qui les a servies, sans aucune majoration.
- Bloquer, puis régler. Avant l’exécution d’une requête, Hyperouter bloque le maximum qu’elle peut coûter : votre entrée plus
max_tokenspour le chat, le nombre demandé pour les images et les secondes pour la vidéo. À la fin, vous êtes débité de ce qui a été utilisé et le reste du montant bloqué est libéré. Le solde ne devient jamais négatif. - Une requête échouée, ou une tâche d’image ou de vidéo échouée, ne coûte rien. Une tentative de repli qui échoue ne coûte rien.
- Chaque réponse porte son coût dans
usage.cost, un nombre JSON en USD : sur le chat, sur les images, sur une vidéo réglée, et dansGET /v1/generations/{id}. Le tableau de bord affiche chaque requête et vos dépenses par jour, par modèle et par clé. - Les montants sont exacts : l’argent est compté en milliardièmes de dollar et jamais arrondi via un flottant. Les prix de
GET /v1/modelssont des chaînes décimales. - Les recharges sont manuelles pour l’instant. Ouvrez une demande de recharge dans le tableau de bord avec le montant, la référence du paiement et une capture d’écran du paiement. Notre équipe vérifie le paiement, crédite votre solde et répond dans le même ticket.
- Frais de recharge. Chaque recharge supporte des frais de 5,5 % du montant payé, avec un minimum de 0,80 $, déduits lorsque la recharge est créditée : un paiement de 100 $ crédite 94,50 $, et un paiement de 10 $ crédite 9,20 $. Les frais en vigueur sont affichés sur la page Crédits avant que vous ne demandiez une recharge, et chaque recharge de votre historique indique le montant payé et les frais. Les requêtes elles-mêmes ne supportent aucuns frais.
Limites de débit
Chaque compte a une limite de requêtes par minute et de requêtes en cours simultanément. Les deux comptent ensemble toutes les clés API du compte, et s’appliquent à chaque requête qui démarre un travail : chat completions, créations d’images et de vidéos, et créations brutes. Lire un résultat (GET /v1/generations/{id}, GET /v1/videos…, une interrogation de tâche brute) ne compte pas ; les interrogations brutes sont comptées à part, par fournisseur, avec la même limite de requêtes par minute.
Votre palier dépend du total que vous avez rechargé, avant déduction des frais de recharge :
| Palier | Rechargé | Requêtes par minute | Requêtes simultanées |
|---|---|---|---|
| 1 | Moins de $10 | 60 | 10 |
| 2 | $10 ou plus | 300 | 30 |
| 3 | $100 ou plus | 1,200 | 100 |
| 4 | $1,000 ou plus | 6,000 | 300 |
Vos limites actuelles figurent sur la page Crédits. Ce sont les valeurs par défaut ; notre équipe peut les modifier pour la plateforme ou pour un compte, et un changement s’applique en moins d’une minute.
Au-delà de l’une ou l’autre limite, la requête est refusée avant que quoi que ce soit ne soit bloqué ou transmis, avec 429, type: rate_limit_error, code: rate_limited et un en-tête Retry-After en secondes. Le message nomme la limite atteinte. Une requête compte pour la minute même lorsqu’elle est refusée. Une requête en cours, flux compris, compte jusqu’à sa fin.
Pour se protéger contre la devinette de clés, Hyperouter compte les vérifications de clé API échouées par adresse client. Plus de 30 en une minute bloquent cette adresse sur toutes les routes /v1 pendant 15 minutes : 429, rate_limit_error, too_many_auth_failures, avec Retry-After. Une clé valide ne lève pas le blocage.
Support
Ouvrez un ticket dans le tableau de bord pour la facturation, les recharges et les questions sur l’API ; notre équipe répond dans le même fil. Vous pouvez aussi écrire à [email protected]. Veuillez indiquer l’id de la réponse lorsque vous signalez une requête précise.