Les SDK officiels encapsulent l’API REST pour le code serveur et les scripts. Un seul appel transcrit un fichier : il envoie l’enregistrement, attend la tâche et vous rend la transcription. En chemin, le SDK vérifie le fichier avant toute réservation de minutes, relance ce qui peut l’être sans risque, maintient en vie un téléversement long et joint une clé d’idempotence à chaque téléversement et à chaque achat, pour qu’une nouvelle tentative ne débite jamais deux fois. La CLI repose sur le SDK TypeScript et fait la même chose depuis un terminal.
Paquets
| Langage | Paquet | Registre | Source |
|---|---|---|---|
| TypeScript | @hushscript/sdk | npm: www.npmjs.com/package/@hushscript/sdk | github.com/Hushscript/hushscript-sdk-typescript |
| Python | hushscript | PyPI: pypi.org/project/hushscript | github.com/Hushscript/hushscript-sdk-python |
| Go | github.com/Hushscript/hushscript-sdk-go | pkg.go.dev: pkg.go.dev/github.com/Hushscript/hushscript-sdk-go | github.com/Hushscript/hushscript-sdk-go |
| PHP | hushscript/sdk | Packagist: packagist.org/packages/hushscript/sdk | github.com/Hushscript/hushscript-sdk-php |
| CLI | @hushscript/cli | npm: www.npmjs.com/package/@hushscript/cli | github.com/Hushscript/hushscript-cli |
Versions minimales d’exécution :
- TypeScript : Node 22 ou plus récent. Bun 1.2+ et Deno 2+ sont vérifiés uniquement pour l’import du paquet, pas pour leur comportement HTTP.
- Python : 3.10 ou plus récent.
- Go : 1.25 ou plus récent.
- PHP : 8.2 ou plus récent, avec
ext-jsonetext-mbstring;ext-curlpour le téléversement simultané des parties. - CLI : Node 22 ou plus récent.
Les SDK sont destinés aux serveurs et aux scripts. L’API n’accepte pas les
origines de navigateur, et un jeton dans un bundle de navigateur est un jeton
divulgué : le SDK TypeScript refuse donc de démarrer là où window et
document existent.
Obtenir un jeton
Chaque SDK et la CLI s’authentifient avec un jeton d’accès personnel. Créez-en
un sous Créer un nouveau jeton sur la page MCP du compte,
choisissez les scopes dont votre code a besoin et décidez s’il peut acheter
des minutes. Le jeton n’est affiché qu’une fois et ressemble à
hsr1:<region>:pat.<id>.<secret>. Les scopes et le fonctionnement d’un jeton
sont décrits sur la page de l’API.
Les SDK lisent le jeton dans HUSHSCRIPT_TOKEN quand vous n’en passez pas :
export HUSHSCRIPT_TOKEN=hsr1:...
Un agent peut aussi ouvrir son propre compte, le faire payer sur une page de
paiement hébergée et récupérer son premier jeton depuis le code :
Hushscript.agent.signup() et Hushscript.agent.claim() en TypeScript,
Hushscript.agent_signup() et Hushscript.agent_claim() en Python, AgentSignup et AgentClaim en
Go, et Client::agentSignup() et Client::agentClaim() en PHP. Le parcours et
ses règles sont décrits dans Usage automatisé.
TypeScript
npm install @hushscript/sdk
import { writeFile } from "node:fs/promises";
import { Hushscript } from "@hushscript/sdk";
const hs = new Hushscript(); // reads HUSHSCRIPT_TOKEN
const transcript = await hs.transcribe("meeting.mp3");
console.log(transcript.text);
await writeFile("meeting.srt", transcript.toSRT());
transcribe() accepte un chemin, un Blob, un Uint8Array ou un
ReadableStream<Uint8Array>. Un flux exige sa size exacte et sa
durationSeconds. hs.balance() renvoie les minutes dont vous disposez,
hs.transcripts.list() parcourt page par page les transcriptions terminées et
hs.buy("300min", { acknowledgeNoRefund: true }) achète un pack. Chaque
opération /v1 est aussi disponible via hs.api, avec les mêmes nouvelles
tentatives, les mêmes délais d’attente et la même expurgation des secrets.
Python
pip install hushscript
from pathlib import Path
from hushscript import Hushscript
with Hushscript() as hs: # reads HUSHSCRIPT_TOKEN
transcript = hs.transcribe("meeting.mp3")
print(transcript.text)
Path("meeting.srt").write_text(transcript.to_srt(), encoding="utf-8")
Chaque appel a un jumeau asyncio sur AsyncHushscript, avec les mêmes noms.
transcribe() accepte un chemin, des bytes ou un objet fichier binaire ; un
objet fichier qui ne permet pas de se repositionner exige size et
duration_seconds. hs.balance(), hs.transcripts.list() et
hs.buy("300min", acknowledge_no_refund=True) couvrent le solde, la liste des
transcriptions et les achats.
Go
go get github.com/Hushscript/hushscript-sdk-go
package main
import (
"context"
"fmt"
"log"
"os"
hushscript "github.com/Hushscript/hushscript-sdk-go"
)
func main() {
client, err := hushscript.New() // reads HUSHSCRIPT_TOKEN
if err != nil {
log.Fatal(err)
}
transcript, err := client.Transcribe(context.Background(), "meeting.mp3", nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(transcript.Text(nil))
if err := os.WriteFile("meeting.srt", []byte(transcript.SRT(nil)), 0o600); err != nil {
log.Fatal(err)
}
}
Transcribe accepte un chemin, TranscribeReader un io.ReaderAt et sa taille
exacte, et TranscribeStream un lecteur séquentiel avec sa taille et
DurationSeconds. client.Balance, client.Transcripts.List et client.Buy
couvrent le solde, la liste des transcriptions et les achats. Les options qui
peuvent être activées, désactivées ou non définies sont des *bool, créés avec
hushscript.Bool.
PHP
composer require hushscript/sdk
<?php
require __DIR__ . '/vendor/autoload.php';
use Hushscript\Client;
$hs = new Client(); // reads HUSHSCRIPT_TOKEN
$transcript = $hs->transcribe('meeting.mp3');
echo $transcript->text();
file_put_contents('meeting.srt', $transcript->toSrt());
transcribe() accepte un chemin ou un flux ouvert ; un flux qui ne permet pas
de se repositionner exige les options size et duration_seconds. Les options
utilisent des clés de tableau en snake_case et les résultats des propriétés en
camelCase. $hs->balance(), $hs->transcripts()->list() et
$hs->buy('300min', true) couvrent le solde, la liste des transcriptions et
les achats. Pour Laravel, liez un seul Client dans un fournisseur de services
et exécutez les transcriptions dans un job en file d’attente avec une option
idempotency_key stable.
CLI
npm install --global @hushscript/cli
hushscript login
hushscript transcribe meeting.mp3 --format srt --out meeting.srt
La CLI prend le jeton dans --token, puis dans HUSHSCRIPT_TOKEN, puis dans
celui que hushscript login a enregistré. login demande le jeton sans
l’afficher et le conserve dans un fichier que seul votre utilisateur peut lire ;
hushscript logout le supprime. En CI, préférez la variable d’environnement.
| Commande | Ce qu’elle fait |
|---|---|
login |
Demande un jeton et l’enregistre. |
logout |
Supprime le jeton enregistré. |
balance |
Affiche les minutes dont vous disposez. |
transcribe <file> |
Envoie un enregistrement, attend et affiche la transcription. Options : --language, --translate, --format srt|vtt|txt|json, --out, --key. |
resume <token> <file> |
Termine une transcription laissée en suspens par transcribe. |
transcripts |
Liste les transcriptions terminées, les plus récentes d’abord. |
transcript <id> |
Affiche une transcription. |
jobs |
Liste les tâches ; --active pour celles qui ne sont pas terminées. |
packs |
Liste les packs de minutes achetables, avec leurs prix. |
buy <pack> |
Achète un pack avec votre carte par défaut enregistrée. Options : --yes, --key. |
--json affiche un seul document JSON sur stdout et rien d’autre, et
transforme stderr en JSON Lines. Le code de sortie est 0 en cas de succès, 1
quand l’API ou le SDK a signalé une erreur, 2 pour une erreur d’usage (rien n’a
été envoyé) et 130 quand l’exécution a été interrompue.
Fichiers acceptés
MP3, M4A, MP4 et MOV (la piste audio d’une vidéo est utilisée), WAV, FLAC et OGG avec Vorbis ou Opus, de 15 secondes à 10 heures. Les SDK vérifient le format à partir des octets du fichier et sondent la durée avant toute réservation de minutes. Ils ne convertissent pas les médias : convertissez d’abord tout autre format :
ffmpeg -i input -vn -c:a libopus output.opus
Erreurs
Toutes les erreurs levées par un SDK appartiennent à une même famille, de
sorte qu’un seul catch suffit : HushscriptError en TypeScript et en Python,
*hushscript.Error en Go et HushscriptException en PHP. Une erreur porte un
code sous forme de slug, comme insufficient_balance, le code numérique, le
statut HTTP, un message, un hint qui indique quoi faire ensuite, les détails
et retryAfter (en PHP le slug s’appelle errorCode ; en Python, retryAfter
s’écrit retry_after).
import { HushscriptError, InsufficientBalanceError } from "@hushscript/sdk";
try {
await hs.transcribe("meeting.mp3");
} catch (error) {
if (error instanceof InsufficientBalanceError) console.log(error.hint);
else if (error instanceof HushscriptError) console.log(error.code, error.hint ?? error.message);
else throw error;
}
Une PreflightError signifie que le SDK a refusé le fichier avant toute
réservation de crédit. C’est le serveur qui décide si votre solde couvre un
fichier : un 402 revient à la création du téléversement, avant l’envoi de la
moindre partie.
Facturation et nouvelles tentatives
Chaque téléversement et chaque achat porte une clé d’idempotence, que les nouvelles tentatives réutilisent : un appel relancé rejoue donc le premier au lieu d’en démarrer un second.
buy() débite votre carte par défaut enregistrée. L’achat depuis le code est
désactivé tant que trois réglages ne l’autorisent pas : le jeton a le scope
billing, l’option « Autoriser ce jeton à acheter des minutes » est activée
sur le jeton, et « Autoriser les applications connectées à acheter des
minutes » est activée pour le compte. S’il en manque un, l’appel échoue avec
pat_scope_missing. Montrez à votre acheteur l’avertissement d’absence de
remboursement avant de l’appeler.
Un achat est relancé au plus une fois, après une erreur réseau, un 502 ou un
503, avec la même clé. Certaines réponses prouvent que rien n’a été débité : un
400, 402, 404 ou 422, et un 403 avec le code 4021 (pat_purchase_requires_app,
la carte a été refusée ou ne peut pas être débitée sans vous) ou 4023
(pat_purchase_requires_authentication, la banque veut confirmer le
paiement). Après 4021 ou 4023, achetez le pack dans l’application. Toute autre
défaillance survenue une fois la requête envoyée, y compris un 401 ou un 429,
signifie que la carte a peut-être été débitée. Cette erreur porte la clé
d’idempotence : redemandez avec la même clé, et l’achat ne peut jamais avoir
lieu deux fois. En Python :
from hushscript import HushscriptError
try:
purchase = hs.buy("300min", acknowledge_no_refund=True)
except HushscriptError as error:
refused = error.status in {400, 402, 404, 422} or (
error.status == 403 and error.numeric_code in {4021, 4023}
)
if error.idempotency_key is None or refused:
raise # only these refusals charged nothing; any other failure keeps the key for a retry
purchase = hs.buy("300min", acknowledge_no_refund=True, idempotency_key=error.idempotency_key)
Un achat qui a échoué avant l’envoi de sa requête ne porte aucune clé : rien
n’a été débité. Une clé que vous fournissez vous-même doit comporter de 1 à 128
caractères parmi A-Za-z0-9_- ; ne la réutilisez pas pour un autre pack. La
CLI affiche la clé quand un achat a pu être envoyé :
hushscript buy 300min --yes --key <key>
Jetons de reprise
Dès qu’une tâche existe, une erreur porte un jeton de reprise à côté de la clé
d’idempotence. Une attente qui expire lève WaitTimeoutError avec le jeton, et
la tâche continue de s’exécuter. Repassez le jeton à resume() pour continuer
sans second débit : une tâche qui a dépassé l’étape de téléversement n’a plus
besoin du fichier, et celle qui téléverse encore est poursuivie avec le même
fichier. En PHP :
try {
$hs->transcribe($path, ['wait_timeout' => 60]);
} catch (\Hushscript\Exception\WaitTimeoutError $timeout) {
$transcript = $hs->resume($timeout->resumeToken, $path);
}
Dans la CLI, Ctrl-C pendant transcribe affiche le jeton de reprise de la
tâche et la commande qui la poursuit :
hushscript resume <token> meeting.mp3 --format srt --out meeting.srt
Journalisation et expurgation
Les SDK n’envoient aucune télémétrie ; l’en-tête User-Agent est la seule
identification du client. La journalisation est désactivée par défaut.
HUSHSCRIPT_LOG=debug écrit une ligne par requête sur l’erreur standard, avec
la méthode, le chemin, le statut et la durée, et jamais un en-tête, un corps,
un titre ni le texte d’une transcription.
Le jeton est expurgé de chaque erreur, de chaque ligne de journal et de chaque
forme imprimée du client. Dans les messages d’erreur, les indications et les
causes, une URL conserve son hôte et son chemin, mais sa chaîne de requête
devient ?[redacted] : une URL de téléversement signée ne s’affiche donc
jamais. Les résultats qui vous remettent un secret, comme un secret de
récupération ou un nouveau jeton, le gardent lisible dans un champ mais
affichent [redacted] à l’impression ; un export JSON vous appartient et
contient la valeur. La CLI retire de stderr tous les jetons qu’elle connaît ;
ses résultats sur stdout sont votre sortie et ne sont pas filtrés.
Configuration
| Réglage | Variable d’environnement | Valeur par défaut |
|---|---|---|
| Jeton | HUSHSCRIPT_TOKEN |
aucune |
| URL de base | HUSHSCRIPT_BASE_URL |
https://api.hushscript.com |
| Niveau de journalisation | HUSHSCRIPT_LOG |
off |
| Délai d’attente des requêtes | aucune | 60 secondes |
| Nouvelles tentatives | aucune | 3 |
Une option passée dans le code l’emporte sur sa variable d’environnement, et une valeur vide compte comme non définie. Les minutes viennent du même solde que l’application ; les packs et les prix figurent sur la page des tarifs.