Aller au contenu principal

Fonctions IA

API développeur Hushscript

Une surface REST conçue pour les agents IA et l'automatisation, sur le même compte, le même solde et les mêmes jetons que partout ailleurs.

Hushscript répond aussi à de simples appels REST, pour les agents et les scripts qui préfèrent appeler un point de terminaison HTTP plutôt que faire tourner un client MCP. C’est le même compte, le même solde et les mêmes jetons porteurs du début à la fin : rien ici ne change la façon dont la transcription est facturée ou stockée.

Démarrage rapide

L’API nécessite un jeton d’accès personnel, et il existe deux façons d’en détenir un. Une personne en crée un sous Tokens sur la page MCP du compte, choisit ses scopes, et décide s’il peut acheter des minutes. Ou un agent ouvre son propre compte sans aucune personne impliquée : POST /v1/agent/accounts démarre une inscription payante, et POST /v1/agent/accounts/{signup_id}/claim échange son secret de réclamation à usage unique contre un compte réel et un premier jeton. Dans les deux cas, le jeton est affiché une seule fois et ressemble à hsr1:<region>:pat.<id>.<secret>. Un jeton émis via la connexion OAuth du serveur MCP fonctionne aussi ici ; voir Se connecter. Un jeton ne peut jamais créer, lister ni révoquer d’autres jetons, et un compte détient au maximum 25 jetons actifs ; le déroulé complet du compte d’agent, rotation d’identifiant comprise, est le guide Usage automatisé.

Une fois que vous détenez un jeton, appelez l’API directement :

curl https://api.hushscript.com/v1/account \
  -H "Authorization: Bearer hsr1:eu:pat.7f3a9c.2b6e1d4a9f2c88b1a3d4e5f60718293"
{
  "balance_seconds": 0,
  "held_seconds": 0,
  "credits_expire_at": null,
  "card_on_file": false,
  "data_region": "eu",
  "limits": {
    "max_active_jobs": 3,
    "max_daily_seconds": 36000,
    "active_jobs": 0,
    "daily_seconds_used": 0
  }
}

Cela répond avec le solde en secondes, les secondes bloquées par les jobs en cours, la date d’expiration des crédits, si une carte est enregistrée, la région de données, et les limites d’admission (max_active_jobs, max_daily_seconds, et ce qui est déjà utilisé). Un compte tout neuf démarre avec un solde nul. POST /v1/uploads vérifie le solde, pas la carte : sans minutes, il répond 3001 insufficient_balance. La carte est ce qui alimente le solde, puisque la vérification de carte ponctuelle dans l’application débloque les 30 minutes gratuites, et que les packs s’achètent contre une carte enregistrée.

Automatiser de bout en bout

Tout ce qui suit l’existence du compte fonctionne sans personne, que ce compte ait été ouvert dans l’application par une personne ou par un agent via /v1/agent/accounts (voir Usage automatisé). Une seule étape de navigateur subsiste, et un agent peut piloter ce navigateur lui-même.

  1. Lire le compte. GET /v1/account. Si card_on_file vaut false, enregistrez d’abord une carte.

  2. Enregistrer une carte, une fois. POST /v1/billing/setup-session renvoie un checkout_url, un session_id et un expires_at :

    curl -X POST https://api.hushscript.com/v1/billing/setup-session \
      -H "Authorization: Bearer hsr1:eu:pat.7f3a9c.2b6e1d4a9f2c88b1a3d4e5f60718293"
    {
      "checkout_url": "https://checkout.stripe.com/c/pay/cs_live_a1B2c3D4e5F6g7H8",
      "session_id": "seti_1PxYzQ2eZvKYlo2C",
      "expires_at": "2026-09-11T15:45:00Z"
    }

    Ouvrez l’URL dans un navigateur que vous contrôlez et complétez la page Stripe hébergée ; rien n’est débité et Hushscript ne voit jamais la carte. Ensuite, GET /v1/billing/cards la liste avec son id. POST /v1/billing/cards/default change la carte par défaut si le compte en détient plusieurs.

  3. Acheter des minutes. GET /v1/billing/packs liste les cinq packs avec id, seconds, amount et currency :

    curl https://api.hushscript.com/v1/billing/packs \
      -H "Authorization: Bearer hsr1:eu:pat.7f3a9c.2b6e1d4a9f2c88b1a3d4e5f60718293"

    POST /v1/billing/purchase avec pack, quick_payment_method_id (l’id de la carte enregistrée) et un idempotency_key débite la carte hors session et répond avec le nouveau balance_seconds :

    curl -X POST https://api.hushscript.com/v1/billing/purchase \
      -H "Authorization: Bearer hsr1:eu:pat.7f3a9c.2b6e1d4a9f2c88b1a3d4e5f60718293" \
      -H "Content-Type: application/json" \
      -d '{
        "pack": "300min",
        "quick_payment_method_id": "pm_2QeT4bY7uX9mK3nP",
        "idempotency_key": "purchase-2026-09-11-02"
      }'
    { "balance_seconds": 18000 }

    Cela nécessite le scope billing sur le jeton et la facturation activée pour le compte. Un corps sans id de carte, ou une carte refusée, est rejeté avec 4021 pat_purchase_requires_app ; une carte que l’émetteur veut faire vérifier est rejetée avec 4023 pat_purchase_requires_authentication. Ni l’un ni l’autre n’ouvre une page que personne ne peut terminer.

  4. Déposer. POST /v1/uploads avec size_bytes, duration_seconds (de 15 secondes à 10 heures), un title optionnel, transcription_options et un idempotency_key :

    curl -X POST https://api.hushscript.com/v1/uploads \
      -H "Authorization: Bearer hsr1:eu:pat.7f3a9c.2b6e1d4a9f2c88b1a3d4e5f60718293" \
      -H "Content-Type: application/json" \
      -d '{
        "size_bytes": 41943040,
        "duration_seconds": 1200,
        "title": "Q3 board call",
        "transcription_options": { "speaker_detection": true },
        "idempotency_key": "upload-2026-09-11-02"
      }'

    Cela pose un blocage de crédit et répond avec un job_id plus une première page d’URL de parties présignées :

    {
      "job_id": "job_5e2a91cf4d7b6081a9f3c2e4b5d6a7c8",
      "part_urls": [
        { "n": 1, "url": "https://r2.hushscript.com/uploads/job_5e2a91cf.../part-1?X-Amz-Signature=..." }
      ]
    }

    Faites un PUT de chaque partie vers son URL (parties de 32 MiB par défaut, la dernière plus petite) :

    curl -X PUT "https://r2.hushscript.com/uploads/job_5e2a91cf.../part-1?X-Amz-Signature=..." \
      --data-binary @part-01.bin

    Récupérez les pages suivantes via GET /v1/uploads/{job}/part-urls?start=<n>, et appelez POST /v1/uploads/{job}/heartbeat bien avant le délai d’inactivité de 20 minutes lors d’un transfert long. Quand les URL présignées sont indisponibles, ou qu’une partie échoue, PUT /v1/uploads/{job}/parts/{n} envoie plutôt les octets de cette partie via l’API ; un PUT répété remplace la partie, donc les nouvelles tentatives sont sûres. Audio uniquement : mp3, m4a, wav, flac, ogg ou opus, 5 Go au maximum, vérifié côté serveur ; extrayez la piste audio d’une vidéo avant de la déposer.

  5. Démarrer et attendre. POST /v1/uploads/{job}/complete avec le n et l’etag de chaque partie envoyée à une URL présignée (omettez parts si toutes les parties sont passées par l’API) :

    curl -X POST https://api.hushscript.com/v1/uploads/job_5e2a91cf4d7b6081a9f3c2e4b5d6a7c8/complete \
      -H "Authorization: Bearer hsr1:eu:pat.7f3a9c.2b6e1d4a9f2c88b1a3d4e5f60718293" \
      -H "Content-Type: application/json" \
      -d '{
        "parts": [
          { "n": 1, "etag": "\"9f86d081884c7d65\"" }
        ]
      }'

    Ensuite, interrogez GET /v1/jobs/{id} : state passe par uploading, queued et processing jusqu’à done ou failed, et un job terminé porte un transcript_id :

    curl https://api.hushscript.com/v1/jobs/job_5e2a91cf4d7b6081a9f3c2e4b5d6a7c8 \
      -H "Authorization: Bearer hsr1:eu:pat.7f3a9c.2b6e1d4a9f2c88b1a3d4e5f60718293"
    {
      "id": "job_5e2a91cf4d7b6081a9f3c2e4b5d6a7c8",
      "state": "done",
      "transcript_id": "trs_2b6e1d4a9f7c3088a1b2c3d4e5f6a7b9"
    }
  6. Lire le résultat. GET /v1/transcripts/{id} renvoie les métadonnées et le corps complet, avec les noms des locuteurs, la langue détectée, les étiquettes et la date de suppression automatique :

    curl https://api.hushscript.com/v1/transcripts/trs_2b6e1d4a9f7c3088a1b2c3d4e5f6a7b9 \
      -H "Authorization: Bearer hsr1:eu:pat.7f3a9c.2b6e1d4a9f2c88b1a3d4e5f60718293"

    GET /v1/transcripts pagine la liste.

Les options de transcription sont celles de l’application, à l’identique : language_code ou détection automatique, speaker_detection, medical_mode (nécessite language_code en en, es, fr ou de, facturé à +100 %), translation_targets (+25 % par langue), multichannel, keyterms_prompt, un prompt en texte libre, et les dictionary_ids et prompt_preset_id enregistrés que liste GET /v1/transcription-context.

Une partie du compte reste MCP uniquement. Importer depuis un lien, modifier ou supprimer des transcriptions, les Insights, les exports, l’enregistrement de dictionnaires et de modèles d’invite, et les paramètres du compte n’ont pas encore de route /v1/ ; le serveur MCP couvre tout cela avec le même jeton.

Authentification

Chaque appel /v1/ porte un jeton porteur dans l’en-tête Authorization, vérifié contre les mêmes scopes que ceux qu’utilise le serveur MCP :

Scope Ce que ça permet
transcripts:read Lire et exporter les transcriptions, leurs métadonnées et la liste des éléments supprimés
transcripts:write Modifier, étiqueter, traduire, restaurer et supprimer des transcriptions
transcribe Déposer des enregistrements, importer depuis un lien et lancer des transcriptions
insights Lire, générer et supprimer des Insights
context Gérer les dictionnaires enregistrés et les modèles d’invite
account:read Lire le solde, l’utilisation, les transactions et les blocages
settings:write Modifier les paramètres du compte
org:read Lire les membres de l’espace de travail, l’activité de la réserve, les factures et le journal d’audit
export Demander un export complet du compte, vérifier son statut et le télécharger
billing Enregistrer une carte et acheter des packs de minutes

Un appel hors des scopes du jeton échoue avec pat_scope_missing, en 403. Le scope billing reste aussi inerte tant que le titulaire du compte n’a pas activé la facturation pour le compte dans l’application ; un appel de facturation sur un compte où cet interrupteur est désactivé échoue avec le même pat_scope_missing, et réémettre le jeton ne le débloque pas. Un jeton ne peut pas créer, lister ni révoquer de jetons, et un compte détient au maximum 25 jetons actifs.

Points de terminaison

En service aujourd’hui, chacun protégé par le scope indiqué :

Méthode Chemin Scope
POST /v1/agent/accounts none
POST /v1/agent/accounts/{signup_id}/claim none
POST /v1/agent/credentials/rotate none
GET /v1/account account:read
POST /v1/billing/setup-session billing
GET /v1/billing/cards billing
POST /v1/billing/cards/default billing
GET /v1/billing/packs billing
POST /v1/billing/purchase billing
GET /v1/billing/transactions account:read
GET /v1/billing/ledger account:read
GET /v1/billing/holds account:read
POST /v1/uploads transcribe
GET /v1/uploads/{job}/part-urls transcribe
PUT /v1/uploads/{job}/parts/{n} transcribe
POST /v1/uploads/{job}/heartbeat transcribe
POST /v1/uploads/{job}/complete transcribe
GET /v1/jobs transcribe
GET /v1/jobs/{id} transcribe
GET /v1/transcripts transcripts:read
GET /v1/transcripts/deleted transcripts:read
GET /v1/transcripts/{id} transcripts:read
GET /v1/transcription-context context
GET /v1/org/members org:read
GET /v1/org/invoices org:read
GET /v1/org/ledger org:read
GET /v1/org/audit org:read

/v1/agent/accounts ouvre une inscription sans interface et sans jeton pour l’instant, /v1/agent/accounts/{signup_id}/claim transforme une inscription payée en un compte réel et son premier jeton, et /v1/agent/credentials/rotate génère un successeur pour le jeton appelant et le révoque, sans toucher à aucun autre identifiant du compte. Le guide Usage automatisé couvre les trois de bout en bout.

Chaque liste accepte un limit et un cursor opaque, et répond avec un next_cursor qui vaut null sur la dernière page. Renvoyez le cursor inchangé ; il encode la position, si bien qu’une page n’est jamais sautée ni répétée quand des lignes arrivent entre deux appels.

La définition complète et à jour, avec les paramètres et les schémas de réponse de chaque opération, est le document OpenAPI : traitez-le comme la source de vérité plutôt que ce tableau. Il est servi à tout jeton porteur quel que soit son scope, si bien qu’un client peut le récupérer avec les identifiants qu’il détient déjà.

Interface MCP

Vous préférez des outils au HTTP brut ? Le serveur MCP place le même compte derrière 51 outils au lieu de ces points de terminaison, pour un client qui parle déjà MCP plutôt que REST.

Limites

Les requêtes effectuées avec un jeton sont limitées à 1 200 par minute et par jeton. POST /v1/billing/setup-session et POST /v1/billing/purchase partagent un budget plus strict de 60 par minute et par compte, en amont de l’appel Stripe que l’un ou l’autre effectue. Une requête refusée répond 429 rate_limited avec un en-tête Retry-After indiquant le délai d’attente en secondes ; patientez ce délai avant de réessayer. Les dépôts sont plafonnés à 5 Go et 10 heures, avec un minimum de 15 secondes, et les limites d’admission propres au compte (max_active_jobs, max_daily_seconds) sont rapportées par GET /v1/account.

Bac à sable

Il n’existe aucun mode d’essai : chaque appel /v1/ s’exécute contre un compte réel, et acheter des minutes dépense de l’argent réel.

Erreurs

Une erreur est un corps JSON qui porte un code numérique stable et un slug error, au statut HTTP indiqué ci-dessous. Les corps d’erreur /v1/ sont une projection figée : error, code, et un ensemble fixe de clés de détail. La forme d’erreur d’/api n’est pas figée et peut en porter davantage. Les codes qu’un appelant automatisé doit gérer :

Statut Code Slug Signification
401 2000 unauthorized Jeton porteur manquant ou invalide
403 2022 pat_forbidden La route n’accepte aucun jeton
403 2023 pat_scope_missing Le jeton n’a pas le scope requis pour cet appel, ou la facturation est désactivée sur le compte
403 4021 pat_purchase_requires_app Aucune carte enregistrée n’a été nommée, ou le paiement a été refusé ; rien n’a été débité
403 4023 pat_purchase_requires_authentication L’émetteur de la carte demande une vérification que l’appelant ne peut pas effectuer ; la carte elle-même est valide
402 3001 insufficient_balance Solde insuffisant pour admettre le job
402 3002 card_declined La carte enregistrée a été refusée
402 3003 org_insufficient_balance La réserve de l’espace de travail qui finance ce dépôt est insuffisante
404 4000 not_found Aucun job, dépôt ou ressource de ce type
409 4001 wrong_state La ressource n’est pas dans un état qui permette cela
422 1021 duration_out_of_range La durée déclarée est inférieure à 15 secondes ou supérieure à 10 heures
429 5000 rate_limited Trop de requêtes ; attendez Retry-After
502 6001 provider_error Un service en amont a échoué
500 9000 internal_error Une erreur serveur inattendue

Le document OpenAPI nomme le code exact que chaque opération peut renvoyer, et le serveur MCP publie le catalogue complet sous forme de ressource hushscript://error-codes.

Commencer à transcrire – 30 minutes pour essayer

Un blocage de 1 $ confirme votre carte et est libéré immédiatement — vous n'êtes jamais débité, et vos 30 minutes gratuites sont créditées aussitôt.

Commencer – 30 minutes gratuites