Hushscript risponde anche a normali chiamate REST, per agenti e script che preferiscono chiamare un endpoint HTTP piuttosto che eseguire un client MCP. È lo stesso account, lo stesso saldo e gli stessi token bearer dall’inizio alla fine: niente qui cambia il modo in cui la trascrizione viene tariffata o conservata.
Avvio rapido
L’API richiede un token di accesso personale, e ci sono due modi per
ottenerne uno. Una persona ne crea uno sotto Token nella
pagina MCP dell’account, sceglie i
suoi scope e decide se può acquistare minuti. Oppure un agente apre un
proprio account senza alcuna persona coinvolta: POST /v1/agent/accounts
avvia una registrazione a pagamento, e
POST /v1/agent/accounts/{signup_id}/claim scambia il suo segreto di
reclamo monouso con un account vero e un primo token. In entrambi i casi il
token viene mostrato una sola volta e ha la forma
hsr1:<region>:pat.<id>.<secret>. Anche un token generato tramite l’accesso
OAuth del server MCP funziona qui; vedi Connessione. Un
token non può mai generare, elencare o revocare altri token, e un account ne
può avere al massimo 25 attivi; il flusso completo per gli account agente,
inclusa la rotazione delle credenziali, è la guida
Uso automatizzato.
Una volta ottenuto un token, chiama l’API direttamente:
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
}
}
Questo risponde con il saldo in secondi, i secondi trattenuti dai job in
corso, la data di scadenza dei crediti, se è salvata una carta, la regione
dei dati, e i limiti di ammissione (max_active_jobs, max_daily_seconds, e
quanto è già stato usato). Un account appena creato parte con saldo zero.
POST /v1/uploads controlla il saldo, non la carta: senza minuti restituisce
3001 insufficient_balance. La carta è il modo in cui il saldo arriva lì,
dato che la verifica una tantum della carta nell’app sblocca i 30 minuti
gratuiti, e i pacchetti si acquistano addebitando una carta salvata.
Automatizzare dall’inizio alla fine
Tutto ciò che avviene dopo che l’account esiste funziona senza una persona,
sia che l’account sia stato aperto nell’app da una persona sia che un agente
lo abbia aperto tramite /v1/agent/accounts (vedi
Uso automatizzato). Resta un unico passaggio nel browser, e
un agente può guidare quel browser da solo.
-
Leggi l’account.
GET /v1/account. Secard_on_fileèfalse, salva prima una carta. -
Salva una carta, una volta sola.
POST /v1/billing/setup-sessionrestituisce uncheckout_url, unsession_ide unexpires_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" }Apri l’URL in un browser che controlli e completa la pagina Stripe ospitata; non viene addebitato nulla e Hushscript non vede mai la carta. Poi
GET /v1/billing/cardsla elenca con il suo id.POST /v1/billing/cards/defaultcambia quella predefinita se l’account ne possiede più di una. -
Acquista minuti.
GET /v1/billing/packselenca i cinque pacchetti conid,seconds,amountecurrency:curl https://api.hushscript.com/v1/billing/packs \ -H "Authorization: Bearer hsr1:eu:pat.7f3a9c.2b6e1d4a9f2c88b1a3d4e5f60718293"POST /v1/billing/purchaseconpack,quick_payment_method_id(l’id della carta salvata) e unidempotency_keyaddebita la carta fuori sessione e risponde con il nuovobalance_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 }Questo richiede lo scope
billingsul token e la fatturazione attivata per l’account. Un corpo senza l’id di una carta, o una carta rifiutata, viene respinto con4021 pat_purchase_requires_app; una carta che l’emittente vuole verificare viene respinta con4023 pat_purchase_requires_authentication. Nessuno dei due apre una pagina che nessuno può completare. -
Carica.
POST /v1/uploadsconsize_bytes,duration_seconds(da 15 secondi a 10 ore), untitleopzionale,transcription_optionse unidempotency_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" }'Questo applica una trattenuta di credito e risponde con un
job_idpiù una prima pagina di URL di parte prefirmati:{ "job_id": "job_5e2a91cf4d7b6081a9f3c2e4b5d6a7c8", "part_urls": [ { "n": 1, "url": "https://r2.hushscript.com/uploads/job_5e2a91cf.../part-1?X-Amz-Signature=..." } ] }Esegui
PUTdi ogni parte sul suo URL (parti da 32 MiB per impostazione predefinita, l’ultima più piccola):curl -X PUT "https://r2.hushscript.com/uploads/job_5e2a91cf.../part-1?X-Amz-Signature=..." \ --data-binary @part-01.binRecupera altre pagine da
GET /v1/uploads/{job}/part-urls?start=<n>, e chiamaPOST /v1/uploads/{job}/heartbeatben entro il timeout di inattività di 20 minuti durante un trasferimento lungo. Quando gli URL prefirmati non sono disponibili, o una parte fallisce,PUT /v1/uploads/{job}/parts/{n}invia invece i byte di quella parte attraverso l’API; unPUTripetuto sostituisce la parte, quindi i nuovi tentativi sono sicuri. Solo audio: mp3, m4a, wav, flac, ogg o opus, al massimo 5 GB, verificato sul server; estrai la traccia audio da un video prima di caricarlo. -
Avvia e attendi.
POST /v1/uploads/{job}/completeconnedetagdi ogni parte inviata a un URL prefirmato (omettipartsse ogni parte è passata attraverso 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\"" } ] }'Poi interroga periodicamente
GET /v1/jobs/{id}:statepassa attraversouploading,queuedeprocessingfino adoneofailed, e un job completato porta untranscript_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" } -
Leggi il risultato.
GET /v1/transcripts/{id}restituisce i metadati e il corpo completo, con i nomi dei parlanti, la lingua rilevata, i tag e la data di eliminazione automatica:curl https://api.hushscript.com/v1/transcripts/trs_2b6e1d4a9f7c3088a1b2c3d4e5f6a7b9 \ -H "Authorization: Bearer hsr1:eu:pat.7f3a9c.2b6e1d4a9f2c88b1a3d4e5f60718293"GET /v1/transcriptspagina l’elenco.
Le opzioni di trascrizione sono quelle dell’app, identiche: language_code
oppure il rilevamento automatico, speaker_detection, medical_mode
(richiede language_code in en, es, fr o de, fatturata al +100%),
translation_targets (+25% per lingua), multichannel, keyterms_prompt,
un prompt in testo libero, e i dictionary_ids e il prompt_preset_id
salvati che GET /v1/transcription-context elenca.
Una parte dell’account resta ancora solo per MCP. Importare da un link,
modificare o eliminare trascrizioni, gli Insights, le esportazioni, salvare
dizionari e preset dei prompt, e le impostazioni dell’account non hanno
ancora una rotta /v1/; il server MCP copre tutto questo con lo
stesso token.
Autenticazione
Ogni chiamata /v1/ porta un token bearer nell’intestazione
Authorization, verificato rispetto agli stessi scope che usa il server
MCP:
| Scope | Cosa consente |
|---|---|
transcripts:read |
Leggere ed esportare le trascrizioni, i loro metadati e l’elenco degli elementi eliminati |
transcripts:write |
Modificare, taggare, tradurre, ripristinare ed eliminare le trascrizioni |
transcribe |
Caricare registrazioni, importare da un link e avviare trascrizioni |
insights |
Leggere, generare ed eliminare gli Insights |
context |
Gestire i dizionari salvati e i preset dei prompt |
account:read |
Leggere saldo, utilizzo, transazioni e trattenute |
settings:write |
Modificare le impostazioni dell’account |
org:read |
Leggere i membri dello spazio di lavoro, il registro contabile, le fatture e il registro di audit |
export |
Richiedere un’esportazione completa dell’account, verificarne lo stato e scaricarla |
billing |
Salvare una carta e acquistare pacchetti di minuti |
Una chiamata al di fuori degli scope del token fallisce con
pat_scope_missing, con stato 403. Lo scope billing resta inerte finché
il proprietario dell’account non attiva la fatturazione per l’account
nell’app; una chiamata di fatturazione su un account dove quell’interruttore
è spento fallisce con lo stesso pat_scope_missing, e rigenerare il token
non lo risolve. Un token non può creare, elencare o revocare token, e un
account ne può avere al massimo 25 attivi.
Endpoint
Attivi oggi, ciascuno vincolato allo scope indicato:
| Method | Path | 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 avvia una registrazione headless senza ancora un
token, /v1/agent/accounts/{signup_id}/claim trasforma una registrazione a
pagamento in un account vero e nel suo primo token, e
/v1/agent/credentials/rotate genera un successore per il token chiamante
e lo revoca, senza toccare nessun’altra credenziale sull’account. La guida
Uso automatizzato copre tutti e tre per intero.
Ogni elenco accetta un limit e un cursor opaco, e risponde con un
next_cursor che è null sull’ultima pagina. Restituisci il cursore
invariato; codifica la posizione, così una pagina non viene mai saltata o
ripetuta quando arrivano nuove righe tra una chiamata e l’altra.
La definizione completa e aggiornata, con parametri e schemi di risposta per ogni operazione, è il documento OpenAPI: trattalo come fonte di verità rispetto a questa tabella. Viene servito a qualsiasi token bearer indipendentemente dallo scope, così un client può recuperarlo con le credenziali che già possiede.
Interfaccia MCP
Preferisci gli strumenti all’HTTP grezzo? Il server MCP mette lo stesso account dietro 51 strumenti invece di questi endpoint, per un client che parla già MCP invece che REST.
Limiti
Le richieste effettuate con un token sono limitate a 1.200 al minuto per
token. POST /v1/billing/setup-session e POST /v1/billing/purchase
condividono un budget più stretto di 60 al minuto per account, prima della
chiamata a Stripe che effettuerebbero. Una richiesta rifiutata risponde con
429 rate_limited e un’intestazione Retry-After che indica l’attesa in
secondi; attendi quel tempo prima di riprovare. I caricamenti sono limitati
a 5 GB e 10 ore, con un minimo di 15 secondi, e i limiti di ammissione
propri dell’account (max_active_jobs, max_daily_seconds) sono riportati
da GET /v1/account.
Sandbox
Non esiste una modalità dry-run: ogni chiamata /v1/ viene eseguita su un
account reale, e acquistare minuti spende denaro vero.
Errori
Un errore è un corpo JSON che porta un code numerico stabile e uno slug
error, allo stato HTTP mostrato sotto. I corpi di errore /v1/ sono una
proiezione congelata: error, code e un insieme fisso di chiavi di
dettaglio. La forma di errore di /api non è congelata e può portare
altro. I codici che un chiamante automatizzato deve gestire:
| Status | Code | Slug | Meaning |
|---|---|---|---|
| 401 | 2000 | unauthorized |
Token bearer mancante o non valido |
| 403 | 2022 | pat_forbidden |
La rotta non accetta alcun token |
| 403 | 2023 | pat_scope_missing |
Al token manca lo scope richiesto da questa chiamata, oppure la fatturazione è disattivata per l’account |
| 403 | 4021 | pat_purchase_requires_app |
Non è stata indicata nessuna carta salvata, oppure l’addebito è stato rifiutato; nessun importo è stato addebitato |
| 403 | 4023 | pat_purchase_requires_authentication |
L’emittente della carta richiede una verifica che chi chiama non può completare; la carta in sé è valida |
| 402 | 3001 | insufficient_balance |
Saldo insufficiente per ammettere il job |
| 402 | 3002 | card_declined |
La carta salvata è stata rifiutata |
| 402 | 3003 | org_insufficient_balance |
Il pool dello spazio di lavoro che finanzia questo caricamento è insufficiente |
| 404 | 4000 | not_found |
Nessun job, caricamento o risorsa di questo tipo |
| 409 | 4001 | wrong_state |
La risorsa non si trova in uno stato che consente questa operazione |
| 422 | 1021 | duration_out_of_range |
La durata dichiarata è inferiore a 15 secondi o superiore a 10 ore |
| 429 | 5000 | rate_limited |
Troppe richieste; attendi il valore di Retry-After |
| 502 | 6001 | provider_error |
Un servizio a monte è fallito |
| 500 | 9000 | internal_error |
Un errore inatteso del server |
Il documento OpenAPI indica il codice esatto che ogni operazione può
restituire, e il server MCP pubblica il catalogo completo come risorsa
hushscript://error-codes.