Vai al contenuto principale

Funzioni IA

API per sviluppatori di Hushscript

Una superficie REST pensata per agenti IA e automazioni, sullo stesso account, lo stesso saldo e gli stessi token di tutto il resto.

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.

  1. Leggi l’account. GET /v1/account. Se card_on_file è false, salva prima una carta.

  2. Salva una carta, una volta sola. POST /v1/billing/setup-session restituisce un checkout_url, un session_id e 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"
    }

    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/cards la elenca con il suo id. POST /v1/billing/cards/default cambia quella predefinita se l’account ne possiede più di una.

  3. Acquista minuti. GET /v1/billing/packs elenca i cinque pacchetti con id, seconds, amount e currency:

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

    POST /v1/billing/purchase con pack, quick_payment_method_id (l’id della carta salvata) e un idempotency_key addebita la carta fuori sessione e risponde con il nuovo 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 }

    Questo richiede lo scope billing sul token e la fatturazione attivata per l’account. Un corpo senza l’id di una carta, o una carta rifiutata, viene respinto con 4021 pat_purchase_requires_app; una carta che l’emittente vuole verificare viene respinta con 4023 pat_purchase_requires_authentication. Nessuno dei due apre una pagina che nessuno può completare.

  4. Carica. POST /v1/uploads con size_bytes, duration_seconds (da 15 secondi a 10 ore), un title opzionale, transcription_options e 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"
      }'

    Questo applica una trattenuta di credito e risponde con un job_id più 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 PUT di 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.bin

    Recupera altre pagine da GET /v1/uploads/{job}/part-urls?start=<n>, e chiama POST /v1/uploads/{job}/heartbeat ben 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; un PUT ripetuto 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.

  5. Avvia e attendi. POST /v1/uploads/{job}/complete con n ed etag di ogni parte inviata a un URL prefirmato (ometti parts se 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}: state passa attraverso uploading, queued e processing fino a done o failed, e un job completato porta 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. 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/transcripts pagina 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.

Inizia a trascrivere – 30 minuti da provare

Un blocco da $1 conferma la tua carta e viene rilasciato subito — non ti viene mai addebitato nulla, e i tuoi 30 minuti gratuiti arrivano immediatamente.

Inizia – 30 minuti gratuiti