Ouvrir un compte Hushscript nécessitait autrefois une personne, au moins une
fois. Ce n’est plus toute l’histoire. Un flux qui donne la priorité au
paiement permet à un agent d’ouvrir son propre compte, de le financer et de
l’exploiter, sans aucun titulaire humain nulle part dans la boucle.
/developers et /mcp documentent les deux interfaces que ce compte
utilise ensuite ; cette page est le déroulé pour en obtenir un.
S’inscrire
POST /v1/agent/accounts ouvre une inscription sans interface. Il n’y a pas
encore de compte, pas de cookie, pas de jeton : juste un achat en attente.
curl -X POST https://api.hushscript.com/v1/agent/accounts \
-H "Content-Type: application/json" \
-d '{
"contact_email": "ops@example-agent.dev",
"pack_id": "300min",
"accept_terms_version": "2026-08-01",
"agent": {
"name": "research-crawler",
"platform": "langgraph",
"contact_url": "https://example-agent.dev/bots/research-crawler"
}
}'
{
"signup_id": "hsr1:eu:4c3a1f9e7b2d4e6f8a0c1b2d3e4f5061",
"claim_secret": "cs_9f3d2a1b7e6c4f5a8b9d0e1f2a3b4c5d",
"checkout_url": "https://checkout.stripe.com/c/pay/cs_test_a1B2c3D4e5F6",
"pack": "300min",
"amount": 599,
"currency": "usd",
"expires_at": 1789112400
}
contact_email sert uniquement aux reçus et aux avis, jamais à une
connexion. pack_id est l’un des suivants : 45min, 300min, 900min,
1800min, 6000min ; n’envoyez jamais vous-mêmes amount ni currency,
les deux sont dérivés du pack côté serveur. Seuls les deux plus petits packs,
45min et 300min, peuvent être achetés à l’inscription. Un pack_id plus
grand est refusé, et le refus porte details.allowed_packs, qui liste ce que
ce compte peut acheter dès maintenant, afin qu’un appelant puisse réessayer
sans deviner. Le reste de l’échelle se débloque avec l’âge, pas avec le
volume : voir Ce qu’un nouveau compte peut acheter ci-dessous.
accept_terms_version doit correspondre exactement à la version de
politique actuelle du serveur, sinon l’appel échoue avec
policy_version_stale, qui nomme la valeur actuelle dans son corps. Une
indication optionnelle data_region n’est honorée que lorsqu’elle
correspond à la région que votre emplacement réseau implique déjà. Un
dry_run: true optionnel valide tout sans session Stripe et sans
prélèvement ; son signup_id est préfixé dry_ et ne peut jamais être
réclamé.
claim_secret n’est affiché qu’une seule fois, dans cette réponse.
Hushscript ne stocke que son hash. Le perdre avant l’appel de réclamation
signifie perdre l’inscription : il n’existe aucune voie de récupération pour
un secret de réclamation, et le paiement séquestré est remboursé par le
balayage décrit ci-dessous, pas restitué via une recherche.
Finaliser le paiement dans votre propre navigateur
checkout_url est une page Stripe Checkout hébergée. C’est la seule étape
de tout ce flux qui nécessite un navigateur, et il n’a pas besoin d’être le
navigateur d’une personne : un agent peut le piloter avec sa propre
automatisation (remplir les champs de carte, valider, suivre la
redirection). Hushscript ne voit jamais les détails de la carte, dans un cas
comme dans l’autre ; Stripe si. La fenêtre pour le terminer puis réclamer le
compte est de 30 minutes, celle indiquée par expires_at ci-dessus.
Une inscription payée mais jamais réclamée est remboursée automatiquement par un balayage horaire, environ une heure après la fermeture de cette fenêtre de 30 minutes. Le remboursement est intégral, car les minutes ne sont créditées à un solde qu’au moment de la réclamation, donc une inscription non réclamée n’en a jamais eu à consommer.
Réclamer le compte
POST /v1/agent/accounts/{signup_id}/claim transforme une inscription
payée et non réclamée en un compte réel, en un seul appel.
curl -X POST https://api.hushscript.com/v1/agent/accounts/hsr1:eu:4c3a1f9e7b2d4e6f8a0c1b2d3e4f5061/claim \
-H "Content-Type: application/json" \
-d '{"claim_secret": "cs_9f3d2a1b7e6c4f5a8b9d0e1f2a3b4c5d"}'
{
"user_id": "usr_7d1a2b3c4d5e6f708192a3b4c5d6e7f8",
"pat": "hsr1:eu:pat.k3n2j1.8f7e6d5c4b3a29180716253443526170",
"scopes": [
"transcripts:read",
"transcripts:write",
"transcribe",
"account:read",
"export",
"billing",
"pat:rotate"
],
"balance_seconds": 18000
}
Réclamer est à usage unique. Cela crée exactement un compte, avec une
identité de connexion synthétique et irrésoluble derrière lui, accorde le
pack payé exactement une fois même si la requête est retentée, et génère
exactement un PAT : la valeur pat ci-dessus, également affichée une seule
fois.
Un secret erroné, un signup_id inconnu, une inscription déjà réclamée, une
remboursée, et une expirée répondent toutes avec l’erreur identique
agent_claim_invalid. Il n’y a aucun moyen pour un appelant de les
distinguer depuis la réponse, volontairement. Ce n’est qu’une fois le secret
lui-même vérifié que l’état du paiement entre en jeu : une session Checkout
qui n’a pas encore été réglée répond wrong_state à la place.
Le balance_seconds ci-dessus est le solde de départ complet. Les comptes
d’agent ne reçoivent ni bonus de bienvenue ni minutes gratuites pour la
vérification de carte, contrairement au premier compte d’une personne ; ils
partent de rien d’autre que le pack qu’ils ont payé. C’est délibéré, pas une
lacune : le compte était déjà payé avant même d’exister.
Acheter plus de minutes
À partir d’ici, le compte se comporte comme n’importe quel autre, sur la
même surface /v1/ que /developers documente intégralement.
curl -X POST https://api.hushscript.com/v1/billing/purchase \
-H "Authorization: Bearer hsr1:eu:pat.k3n2j1.8f7e6d5c4b3a29180716253443526170" \
-H "Content-Type: application/json" \
-d '{
"pack": "300min",
"quick_payment_method_id": "pm_1PqR2sT3uV4wX5yZ",
"idempotency_key": "purchase-2026-09-11-01"
}'
{
"balance_seconds": 36000
}
Ceci nécessite le scope billing, déjà accordé par la réponse de
réclamation ci-dessus, et partage une limite plus stricte de 60 requêtes par
minute et par compte avec la route d’enregistrement de carte, en amont de
l’appel Stripe que l’une ou l’autre effectue.
Ce qu’un nouveau compte peut acheter
La taille du pack se débloque selon l’âge des paiements réglés, pas selon ce qu’un compte dépense. Un achat ne compte pour le palier suivant qu’une fois 7 jours passés depuis sa propre date de paiement, si bien qu’un compte tout neuf ne peut pas atteindre les gros packs en achetant rapidement.
| Paiements réglés vieux de plus de 7 jours | Packs que le compte peut acheter |
|---|---|
| Rien encore, y compris une réclamation toute fraîche | 45min, 300min |
| Au moins l’équivalent de 45 minutes | ajoute 900min, 1800min |
| Au moins l’équivalent de 15 heures | ajoute 6000min |
Un achat refusé nomme l’ensemble actuel dans details.allowed_packs plutôt
que d’échouer à l’aveugle. L’appel d’inscription applique la première ligne
de ce tableau, ce qui explique pourquoi le déroulé ci-dessus achète
300min et non quelque chose de plus grand. Indépendamment de l’échelle,
un plafond glissant de 24 heures limite la vitesse à laquelle un solde qui
n’a pas encore dépassé l’âge de la fenêtre de litige peut être dépensé.
Transcrire
Déposer et transcrire suit le même flux multipart que pour n’importe quel autre compte.
curl -X POST https://api.hushscript.com/v1/uploads \
-H "Authorization: Bearer hsr1:eu:pat.k3n2j1.8f7e6d5c4b3a29180716253443526170" \
-H "Content-Type: application/json" \
-d '{
"size_bytes": 48213504,
"duration_seconds": 1860,
"title": "weekly-standup-2026-09-11",
"idempotency_key": "upload-2026-09-11-01"
}'
{
"job_id": "job_3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d",
"part_urls": [
{ "n": 1, "url": "https://r2.hushscript.com/uploads/job_3a2b1c0d.../part-1?X-Amz-Signature=..." }
]
}
Faites un PUT de chaque partie vers son URL présignée, puis un POST sur
/complete du même job avec le n et l’etag de chaque partie envoyée de
cette façon. Ensuite, interrogez le job :
curl https://api.hushscript.com/v1/jobs/job_3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d \
-H "Authorization: Bearer hsr1:eu:pat.k3n2j1.8f7e6d5c4b3a29180716253443526170"
{
"id": "job_3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d",
"state": "done",
"transcript_id": "trs_6f5e4d3c2b1a0908f7e6d5c4b3a29180"
}
curl https://api.hushscript.com/v1/transcripts/trs_6f5e4d3c2b1a0908f7e6d5c4b3a29180 \
-H "Authorization: Bearer hsr1:eu:pat.k3n2j1.8f7e6d5c4b3a29180716253443526170"
{
"id": "trs_6f5e4d3c2b1a0908f7e6d5c4b3a29180",
"language": "en",
"duration_seconds": 1860,
"body": "..."
}
Faire tourner l’identifiant
Un compte machine n’a ni mot de passe ni boîte mail utilisable, donc il n’existe pas de parcours « mot de passe oublié » si un PAT fuite ou a simplement besoin d’être remplacé. La rotation est ce parcours.
curl -X POST https://api.hushscript.com/v1/agent/credentials/rotate \
-H "Authorization: Bearer hsr1:eu:pat.k3n2j1.8f7e6d5c4b3a29180716253443526170"
{
"pat": "hsr1:eu:pat.p9q8r7.1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
"pat_id": "p9q8r7",
"scopes": [
"transcripts:read",
"transcripts:write",
"transcribe",
"account:read",
"export",
"billing",
"pat:rotate"
],
"expires_at": null
}
L’appel ne prend aucun corps. Il génère atomiquement un successeur et révoque le jeton qui a authentifié la requête, si bien que l’ancien PAT échoue dès le prochain appel effectué avec lui. Le successeur conserve les scopes du prédécesseur, sa permission de facturation, son nom, son étiquette client et sa politique d’expiration. Cette route ne touche à rien d’autre que le propre jeton de l’appelant : elle ne peut ni lister, ni générer, ni révoquer aucun autre identifiant du compte. C’est la seule voie de récupération d’identifiant dont dispose un compte machine, donc effectuez la rotation avant que l’ancien jeton ne soit abandonné, pas après.
Erreurs
| Statut | Code | Slug | Signification |
|---|---|---|---|
| 401 | 2000 | unauthorized |
Jeton porteur manquant ou invalide |
| 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 |
| 429 | 5000 | rate_limited |
Trop de requêtes ; attendez Retry-After |
Ces quatre-là sont spécifiques aux comptes d’agent et ne sont jamais atteintes par un compte humain :
| Statut | Code | Slug | Signification |
|---|---|---|---|
| 409 | 4035 | agent_signup_pending |
Une inscription pour ce contact_email est encore ouverte. Attendez qu’elle soit réclamée, remboursée ou expirée, ou utilisez une adresse différente |
| 401 | 4036 | agent_claim_invalid |
Secret erroné, inscription inconnue, déjà réclamée, remboursée, ou expirée. Identique volontairement |
| 403 | 4037 | agent_pack_locked |
Le palier de ce compte n’autorise pas encore ce pack. Porte details.allowed_packs ; réessayez avec l’un d’eux |
| 429 | 4038 | agent_purchase_capped |
3 achats, payés ou refusés, dans les 24 dernières heures. Compté par compte à travers tout identifiant qu’il a détenu, donc une rotation ne réinitialise pas le compteur. Porte details.retry_after_seconds |
Une fois le secret de réclamation lui-même vérifié, une session Checkout non
payée répond wrong_state (4001) plutôt que agent_claim_invalid. Le
catalogue complet est le document OpenAPI.
Limites
Les appels sont limités à 1 200 par minute. Pour un compte d’agent, ce budget appartient au compte, pas au jeton individuel : chaque identifiant de la lignée de rotation puise dans le même compteur, donc faire tourner un PAT ne donne pas au successeur une nouvelle réserve. Les deux écritures de facturation, enregistrer une carte et acheter un pack, partagent une limite plus stricte de 60 par minute et par compte, en amont de l’appel Stripe que l’une ou l’autre effectue. Le plafond d’achat de 24 heures ci-dessus est compté de la même façon, par compte plutôt que par identifiant.
En savoir plus
Cette page couvre le cycle de vie du compte : l’ouvrir, le financer, et maintenir son identifiant actif. Pour tout ce que le compte peut ensuite faire, voir l’API REST, y compris le document OpenAPI complet, ou le serveur MCP pour le même compte via des outils plutôt que du HTTP brut.