HiAPI
Blog

Tutoriel

Comment utiliser grok-4.7 via l'API HiAPI : curl, Python et une requête qui fonctionne

Guide pratique, de la première requête à la validation de la réponse

Nov 3, 2026
HiAPI 博客教程封面图:多层半透明玻璃平面在浅色背景上折射出克制的冷蓝色带。

Ce qu'il faut préparer avant la première requête

Avant d'envoyer quoi que ce soit à l'API, assurez-vous que quatre éléments sont en place. En omettre un seul est la cause la plus fréquente d'un premier appel échoué, et la raison de l'échec n'a souvent rien à voir avec le modèle lui-même.

Un compte HiAPI

Vous avez besoin d'un compte HiAPI.ai valide. Connectez-vous au tableau de bord pour gérer vos projets, vos clés et votre consommation. Toutes les opérations de ce tutoriel passent par la même interface API unifiée ; la clé que vous créez ici fonctionne donc pour les différents modèles proposés par la plateforme.

Une clé API

Créez une clé API dans le tableau de bord et conservez-la en lieu sûr : une variable d'environnement du shell pour les tests, un gestionnaire de secrets pour tout ce qui partira en production. Ne validez jamais une clé dans un dépôt de code et ne la collez pas dans une application cliente.

Pour les tests locaux, exportez-la une fois par session de shell :

export HIAPI_API_KEY="your-api-key-here"

L'URL de base

L'URL de base est l'adresse racine de l'API HiAPI. Toutes les requêtes de ce tutoriel sont relatives à elle. Consultez votre tableau de bord pour confirmer l'URL de base exacte à utiliser avec votre compte, et stockez-la dans une variable afin que vos scripts et votre code applicatif référencent la même valeur :

export HIAPI_BASE_URL="https://api.hiapi.ai"

L'identifiant du modèle

L'identifiant de modèle utilisé dans ce tutoriel est grok-4.7. Il est transmis comme une simple chaîne dans le corps de la requête. Si l'identifiant est erroné, vous recevez généralement une erreur explicite plutôt qu'un repli silencieux ; une faute de frappe est donc facile à repérer.

Une fois ces quatre éléments — compte, clé, URL de base, ID de modèle — réunis, vous avez tout ce qu'il faut pour construire la requête. La méthode curl ne nécessite l'installation d'aucun SDK, et la méthode Python ne demande qu'un client HTTP que vous possédez probablement déjà.

Vérification rapide de l'environnement

Vérifiez que la clé et l'URL de base sont bien visibles depuis le shell que vous allez utiliser :

[ -n "$HIAPI_API_KEY" ] && echo "key set"
[ -n "$HIAPI_BASE_URL" ] && echo "base url set"

Si les deux lignes s'affichent, vous pouvez passer à la section suivante.

La forme d'une requête grok-4.7 sur HiAPI

Chaque requête de ce tutoriel partage les mêmes quatre éléments : le point de terminaison, l'en-tête d'authentification, le champ model et le tableau messages. Les comprendre séparément rendra bien plus facile la compréhension du streaming et de l'appel d'outils plus loin, car ces fonctionnalités ne modifient qu'une partie de cette forme.

Le point de terminaison

L'appel est une requête POST vers le point de terminaison de complétion de chat sous l'URL de base. Dans ce tutoriel, nous le représentons ainsi :

POST {HIAPI_BASE_URL}/v1/chat/completions

Si votre tableau de bord affiche un chemin différent, utilisez celui du tableau de bord ; dans tous les cas, le corps de la requête reste identique.

L'en-tête d'authentification

L'authentification se fait par un jeton bearer dans l'en-tête Authorization :

Authorization: Bearer $HIAPI_API_KEY

Comme il s'agit d'un en-tête et non d'un paramètre de requête, la clé n'apparaît jamais dans l'URL, les journaux d'accès ou l'historique du navigateur.

Le type de contenu

Le corps de la requête est du JSON, envoyez donc Content-Type: application/json. curl et n'importe quel client HTTP Python peuvent le définir pour vous, mais il vaut la peine de l'écrire explicitement afin que l'ensemble des en-têtes ne prête à aucune ambiguïté.

Le corps de la requête : model et messages

Le corps de la requête est un objet JSON contenant au moins deux champs :

  • model — la chaîne d'identifiant du modèle, ici grok-4.7.
  • messages — un tableau ordonné d'objets message. Chaque objet possède role et content. Les rôles courants sont : system pour les instructions qui cadrent la conversation, user pour la demande elle-même, assistant pour fournir un tour précédent du modèle lorsque vous poursuivez la conversation.

Un corps de requête minimal ressemble à ceci :

{
  "model": "grok-4.7",
  "messages": [
    { "role": "system", "content": "You are a concise technical assistant." },
    { "role": "user", "content": "Explain what an idempotent HTTP method is in two sentences." }
  ]
}

C'est tout le contrat d'un appel de base. Tout le reste — streaming, définitions d'outils — consiste en champs supplémentaires sur le même objet, et c'est précisément pourquoi les sections précédentes comptent : une fois cette forme correcte, le reste n'est qu'ajout.

À quoi ressemble la réponse

La réponse est un objet JSON. La partie qui vous intéresse presque toujours se trouve sous choices, qui est un tableau ; chaque entrée possède un message contenant role et content. S'y ajoutent des métadonnées, comme le modèle ayant traité la requête et un bloc usage décrivant le nombre de tokens. Lisez choices[0].message.content et vous obtenez le texte de la réponse. Les autres champs sont utiles pour la journalisation et le suivi des coûts, mais ne sont pas nécessaires pour débuter.

Une requête curl qui fonctionne

Une fois la clé exportée et la forme de la requête comprise, l'appel curl est court. C'est la version à copier lorsque vous voulez isoler le problème de votre code applicatif.

curl -sS "$HIAPI_BASE_URL/v1/chat/completions" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "grok-4.7",
    "messages": [
      { "role": "system", "content": "You are a concise technical assistant." },
      { "role": "user", "content": "In one sentence, what is a bearer token?" }
    ]
  }'

Le rôle de chaque option

  • -sS garde la sortie silencieuse tout en affichant les erreurs. Sans cela, une requête échouée peut ressembler à une réponse vide.
  • L'URL est composée de la variable d'URL de base et du chemin de complétion de chat, de sorte que vous n'avez jamais à coder en dur l'hôte dans un script.
  • -H "Authorization: ..." envoie le jeton bearer. La variable est développée par le shell, d'où l'importance de l'avoir exportée plus tôt.
  • -H "Content-Type: application/json" indique au serveur que le corps de la requête est du JSON.
  • -d '...' est le corps de la requête. Les guillemets simples autour du JSON empêchent le shell d'interpréter les accolades et les guillemets qu'il contient.

Si vous préférez placer le corps dans un fichier, écrivez-le dans body.json et remplacez l'argument -d par -d @body.json. C'est généralement plus lisible dès que le tableau messages s'allonge.

Lire le JSON brut

La réponse arrive sur la sortie standard sous forme d'objet JSON. Lorsque vous voulez l'inspecter à l'œil, passez-la dans un outil de mise en forme :

curl -sS "$HIAPI_BASE_URL/v1/chat/completions" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d @body.json | python -m json.tool

Vous devriez voir un tableau choices dont le premier élément contient un objet message avec une chaîne content — cette chaîne est la réponse du modèle. À côté se trouvent généralement l'identifiant de la réponse, le nom du modèle renvoyé et un objet usage contenant le décompte des tokens de prompt et de complétion. Enregistrez dès maintenant une réponse réussie : c'est la référence à laquelle vous comparerez lorsque vous validez le client Python.

Échecs courants à ce stade

Un 401 signifie presque toujours que le jeton bearer est absent, mal formé ou n'a pas réellement été exporté dans le shell courant. Un 400 accompagné d'un message sur le corps de la requête signifie généralement un JSON mal formé — une virgule finale ou des guillemets typographiques collés depuis une documentation sont les coupables habituels. Corrigez ces deux points avant de regarder quoi que ce soit d'autre.

La même requête en Python

La version Python fait la même chose avec le même corps de requête. L'intérêt de la réécrire est de passer d'un test en shell à un code intégrable dans une application, où le corps de la requête est une structure de données plutôt qu'une chaîne entre guillemets.

En utilisant la bibliothèque standard

Si vous ne voulez pas ajouter de dépendance, urllib suffit :

import json
import os
import urllib.request

api_key = os.environ["HIAPI_API_KEY"]
base_url = os.environ["HIAPI_BASE_URL"]

payload = {
    "model": "grok-4.7",
    "messages": [
        {"role": "system", "content": "You are a concise technical assistant."},
        {"role": "user", "content": "In one sentence, what is a bearer token?"},
    ],
}

request = urllib.request.Request(
    f"{base_url}/v1/chat/completions",
    data=json.dumps(payload).encode("utf-8"),
    headers={
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
    },
    method="POST",
)

with urllib.request.urlopen(request) as response:
    body = json.loads(response.read().decode("utf-8"))

print(body["choices"][0]["message"]["content"])

En utilisant requests

Si requests est déjà dans votre environnement, l'appel est plus court :

import os
import requests

response = requests.post(
    f"{os.environ['HIAPI_BASE_URL']}/v1/chat/completions",
    headers={"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"},
    json={
        "model": "grok-4.7",
        "messages": [
            {"role": "system", "content": "You are a concise technical assistant."},
            {"role": "user", "content": "In one sentence, what is a bearer token?"},
        ],
    },
    timeout=60,
)
response.raise_for_status()
print(response.json()["choices"][0]["message"]["content"])

Pourquoi cette version est plus sûre pour une application

Remarquez trois choix délibérés. La clé et l'URL de base proviennent de variables d'environnement, jamais de littéraux dans le code source. Le corps de la requête est un dictionnaire Python, de sorte qu'un guillemet mal placé produit immédiatement une SyntaxError plutôt qu'un refus serveur déroutant. Et l'appel définit un délai d'expiration : sans timeout, une connexion bloquée peut suspendre indéfiniment un processus de travail.

Exécutez la version Python avec le même prompt que dans curl. La formulation de la réponse peut varier légèrement d'une exécution à l'autre — le modèle n'est pas déterministe — mais la structure de la réponse doit être identique : un tableau choices, un message avec content, et un bloc usage. Si la structure correspond, votre client est correctement connecté et les sections suivantes ne sont que des améliorations facultatives.

Activer le streaming

Le streaming change la façon dont les tokens arrivent, pas ce que vous demandez. Au lieu d'attendre la réponse complète, vous la recevez progressivement, ce qui explique la réactivité perçue des interfaces de chat.

La modification de la requête

Ajoutez un champ au corps de requête que vous avez déjà :

{
  "model": "grok-4.7",
  "stream": true,
  "messages": [
    { "role": "user", "content": "Count from one to five, one number per line." }
  ]
}

Le point de terminaison, les en-têtes ou le reste des messages ne changent pas. C'est tout l'intérêt d'apprendre d'abord la forme de base : le streaming est un indicateur supplémentaire, pas une seconde API.

Ce qui est renvoyé

Une fois stream activé, la réponse n'est plus un objet JSON unique. C'est une série d'événements envoyés par le serveur (SSE). Chaque événement transporte une ligne data: dont la charge utile est un fragment JSON de même forme que la réponse normale, sauf que choices[0] contient un objet delta au lieu d'un message complet. Les premiers fragments peuvent ne contenir que le rôle ; les fragments intermédiaires portent des morceaux de contenu ; le flux se termine par la ligne sentinelle data: [DONE].

En tant que client, votre tâche consiste à concaténer dans l'ordre les chaînes delta.content et à vous arrêter à la sentinelle. Traitez tout fragment dépourvu de content comme une non-opération plutôt que comme une erreur.

Consommer les blocs en Python

import json
import os
import requests

with requests.post(
    f"{os.environ['HIAPI_BASE_URL']}/v1/chat/completions",
    headers={"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"},
    json={
        "model": "grok-4.7",
        "stream": True,
        "messages": [{"role": "user", "content": "Count from one to five."}],
    },
    stream=True,
    timeout=60,
) as response:
    response.raise_for_status()
    for line in response.iter_lines():
        if not line:
            continue
        line = line.decode("utf-8")
        if not line.startswith("data: "):
            continue
        data = line[len("data: "):]
        if data == "[DONE]":
            break
        delta = json.loads(data)["choices"][0].get("delta", {})
        text = delta.get("content")
        if text:
            print(text, end="", flush=True)

Deux détails déterminent si le streaming fonctionne correctement ou semble bloqué. Passez stream=True au client HTTP pour qu'il ne mette pas en tampon tout le corps de la réponse, et itérez ligne par ligne plutôt que de lire la réponse d'un coup. Le flush=True sur print ne concerne que ce que vous voyez à l'écran ; sans lui, la sortie peut sembler n'arriver qu'en une seule fois à la fin, même si les blocs sont traités au fur et à mesure.

Valider le streaming séparément

Ne validez pas le streaming et l'appel d'outils dans le même test. Confirmez d'abord que le texte concaténé donne une réponse sensée à un prompt simple, puis ajoutez les fonctionnalités une par une. Si le flux se termine sans sentinelle, c'est le signe de vérifier la connexion, pas le modèle.

L'option d'appel d'outils

L'appel d'outils permet au modèle de demander des fonctions définies dans votre code, plutôt que de seulement générer du texte. L'ajout côté requête est exactement du même type que pour le streaming.

Où placer l'option

Les définitions d'outils forment un tableau tools sur le corps de la requête. Chaque entrée décrit un élément appelable : un nom, une description de quand l'utiliser, et une description JSON schema de ses paramètres. La description compte plus qu'il n'y paraît — c'est le seul guide dont dispose le modèle pour juger quand l'outil s'applique.

{
  "model": "grok-4.7",
  "messages": [
    { "role": "user", "content": "What is the weather in Lisbon right now?" }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Return the current weather for a named city.",
        "parameters": {
          "type": "object",
          "properties": {
            "city": { "type": "string", "description": "City name, e.g. Lisbon" }
          },
          "required": ["city"]
        }
      }
    }
  ]
}

La forme à retenir est type plus function, avec name, description et parameters imbriqués. Si vous avez déjà des définitions JSON schema, c'est dans le bloc parameters qu'elles vont.

Comment le modèle répond

Lorsque le modèle décide qu'un outil est nécessaire, le message assistant dans choices[0] n'est pas du texte ordinaire. Son content est généralement vide et il porte un tableau tool_calls. Chaque entrée possède un identifiant, un nom de fonction correspondant à l'une de vos définitions, et une chaîne arguments contenant du JSON. Analysez cette chaîne arguments — c'est une chaîne, pas un objet, et la traiter comme un objet est une source d'erreur fréquente.

Votre code exécute ensuite cette fonction et envoie une requête de suivi : la conversation d'origine, le message assistant avec tool_calls, et un nouveau message de rôle tool contenant l'identifiant d'appel et le résultat. Le modèle utilise ce résultat pour produire la réponse finale. Le tool_call_id doit correspondre à l'identifiant figurant dans le message assistant ; sans cela, la requête de suivi est ambiguë.

Mesures de protection pratiques

  • Validez les arguments analysés avec le même schema que celui envoyé. Le modèle est guidé par le schema, mais pas contraint par lui.
  • Traitez le nom de fonction renvoyé comme une entrée non fiable et ne le routez que vers une liste d'autorisation explicite de fonctions.
  • N'activez pas stream et les outils lors du premier test. Confirmez d'abord le round-trip d'outil non streamé de bout en bout, puis combinez-les si votre cas d'usage l'exige.

Valider la réponse avant la mise en production

Un appel qui fonctionne dans le terminal n'équivaut pas à une intégration validée. Parcourez cette liste de contrôle de bout en bout, puis conservez le script comme test de fumée.

Confirmer la couche transport

Avant d'analyser quoi que ce soit, vérifiez que le statut HTTP est 200. Un client qui analyse trop tôt produit un KeyError déroutant alors que le vrai problème est un 401. Assertissez explicitement le statut et journalisez le corps de la réponse en cas d'échec — le serveur indique généralement ce qui n'a pas fonctionné.

Confirmer la structure de la réponse

Assertissez, ne supposez pas. Lors d'un appel non streamé réussi, vérifiez trois choses : choices existe et n'est pas vide, choices[0].message.content est une chaîne non vide, et le modèle renvoyé dans la réponse correspond à celui que vous avez envoyé. Cette dernière vérification intercepte un nombre étonnant d'erreurs de configuration — un modèle par défaut qui écrase celui que vous avez demandé.

Exercer délibérément les chemins d'erreur

N'attendez pas qu'une panne survienne pour savoir comment votre code se comporte. Exécutez trois tests négatifs rapides :

  • Appelez sans l'en-tête d'authentification et confirmez que votre code signale clairement une erreur d'authentification au lieu de réessayer indéfiniment.
  • Envoyez un corps de requête sans le champ model et confirmez que vous obtenez une erreur côté client plutôt qu'un blocage.
  • Envoyez un prompt délibérément très long et confirmez que votre gestion du timeout et de la troncature se comporte comme prévu.

Chacun doit produire un échec concret et journalisé — pas un vague « quelque chose s'est mal passé ».

Valider les fonctionnalités avancées séparément

Si vous avez activé le streaming, confirmez que les blocs concaténés forment une réponse cohérente et que la sentinelle met fin à la boucle. Si vous avez activé les outils, confirmez que le round-trip se termine : l'appel d'outil est analysé, la fonction est exécutée, le résultat revient avec l'identifiant correspondant et produit une réponse textuelle finale. Placez chaque validation dans son propre petit script, afin qu'un échec pointe vers une fonctionnalité précise.

Rendre les vérifications reproductibles

Rassemblez toute la séquence dans un seul fichier qui se termine par un code de sortie non nul dès qu'une assertion échoue, et exécutez-le contre votre configuration de préproduction avant chaque déploiement. Il ne devrait prendre que quelques secondes et couvrir l'appel de base, un appel en streaming et, si vous utilisez des outils, un round-trip d'outil. Lorsqu'il passe, vous pouvez faire confiance au fait que les échecs en production proviennent des requêtes que vous envoyez, et non de l'infrastructure sous-jacente.

Une fois la vérification réussie, exécutez une dernière fois l'appel curl. Si le JSON brut correspond à la sortie de votre application, l'intégration est terminée.

Articles similaires

Voir tous les articles →

Commencez avec des artefacts IA persistants

Obtenez votre clé API et appelez des modèles d'image, de vidéo et d'audio via une API unique basée sur les tasks.

Lire la documentation de l'API