Skip to main content

Automated usage

An agent can open a Hushscript account, pay for it, transcribe recordings, and recover its own credentials, start to finish, without a person signing in.

Opening a Hushscript account used to need a person, at least once. That is no longer the whole story. A payment-first flow lets an agent open its own account, fund it, and run it, with no human account holder anywhere in the loop. /developers and /mcp document the two interfaces this account then uses; this page is the walkthrough for getting one.

Sign up

POST /v1/agent/accounts opens a headless signup. There is no account yet, no cookie, and no token: just a pending purchase.

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 is for receipts and notices only, never a login. pack_id is one of 45min, 300min, 900min, 1800min, 6000min; never send amount or currency yourselves, both are derived from the pack on the server. Only the two smallest packs, 45min and 300min, can be bought at signup. A larger pack_id is refused, and the refusal carries details.allowed_packs listing what this account may buy right now, so a caller can retry without guessing. The rest of the ladder unlocks with age, not with volume: see What a new account may buy below. accept_terms_version must match the server’s current policy version exactly, or the call fails with policy_version_stale, which names the current value in its body. An optional data_region hint is honored only when it agrees with the region your network location already implies. An optional dry_run: true validates everything with no Stripe session and no charge; its signup_id is prefixed dry_ and can never be claimed.

claim_secret is shown exactly once, in this response. Hushscript stores only its hash. Losing it before the claim call means losing the signup: there is no recovery route for a claim secret, and the escrowed payment is refunded by the sweep described below, not handed back through a lookup.

Complete the checkout in your own browser

checkout_url is a hosted Stripe Checkout page. It is the only step in this entire flow that needs a browser, and it does not need to be a person’s browser: an agent can drive it with its own automation (fill the card fields, submit, follow the redirect). Hushscript never sees the card details either way; Stripe does. The window to finish it and then claim is 30 minutes, the expires_at above.

A signup that gets paid but is never claimed is refunded automatically by an hourly sweep, roughly an hour after that 30 minute window closes. The refund is full, because minutes are only credited to a balance at claim time, so an unclaimed signup never had any to consume.

Claim the account

POST /v1/agent/accounts/{signup_id}/claim turns a paid, unclaimed signup into a real account, in one call.

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
}

Claiming is single use. It creates exactly one account, with a synthetic, unresolvable login identity behind it, grants the paid pack exactly once even if the request is retried, and mints exactly one PAT: the pat value above, also shown exactly once.

A wrong secret, an unknown signup_id, a signup already claimed, a refunded one, and an expired one all answer the identical agent_claim_invalid error. There is no way for a caller to tell those apart from the response, on purpose. Only once the secret itself checks out does payment state come into it: a Checkout Session that has not settled yet answers wrong_state instead.

The balance_seconds above is the whole starting balance. Agent accounts get no welcome bonus and no free minutes from card verification the way a person’s first account does; they start from nothing but the pack they paid for. That is deliberate, not a gap: the account was already paid for before it existed.

Buy more minutes

From here the account behaves like any other, over the same /v1/ surface /developers documents in full.

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
}

This needs the billing scope, which the claim response above already granted, and it shares a tighter 60 requests a minute per account with the card-saving route, ahead of the Stripe call either one makes.

What a new account may buy

Pack size unlocks on the age of settled payments, not on how much an account spends. A purchase counts toward the next tier only once it is 7 days past its own payment date, so a brand new account cannot reach the large packs by buying quickly.

Settled payments aged past 7 days Packs it may buy
Nothing yet, including a fresh claim 45min, 300min
At least 45 minutes’ worth adds 900min, 1800min
At least 15 hours’ worth adds 6000min

A refused purchase names the current set in details.allowed_packs rather than failing blind. The signup call applies the first row of that table, which is why the walkthrough above buys 300min and not something larger. Separately from the ladder, a rolling 24 hour burn cap limits how fast balance that has not yet aged past the dispute window can be spent.

Transcribe

Uploading and transcribing is the same multipart flow as any other account.

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=..." }
  ]
}

PUT each part to its presigned URL, then POST the same job’s /complete with the n and etag of every part sent that way. Then poll the 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": "..."
}

Rotate the credential

A machine account has no password and no usable mailbox, so there is no “forgot your password” path if a PAT leaks or simply needs replacing. Rotation is that path.

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
}

The call takes no body. It atomically mints a successor and revokes the token that authenticated the request, so the old PAT fails on the very next call made with it. The successor keeps the predecessor’s scopes, billing permission, name, client label, and expiry policy. This route touches nothing but the caller’s own token: it cannot list, mint, or revoke any other credential on the account. It is the only credential-recovery path a machine account has, so rotate before the old token is discarded, not after.

Errors

Status Code Slug Meaning
401 2000 unauthorized Missing or invalid bearer token
403 2023 pat_scope_missing The token lacks the scope this call needs, or billing is off for the account
403 4021 pat_purchase_requires_app No saved card was named, or the charge was declined; nothing was charged
403 4023 pat_purchase_requires_authentication The card issuer wants a challenge the caller cannot complete; the card itself is fine
402 3001 insufficient_balance Not enough balance to admit the job
429 5000 rate_limited Too many requests; wait for Retry-After

These four are specific to agent accounts and are never reached by a human one:

Status Code Slug Meaning
409 4035 agent_signup_pending A signup for this contact_email is still open. Wait for it to be claimed, refunded or expired, or use a different address
401 4036 agent_claim_invalid Wrong secret, unknown signup, already claimed, refunded, or expired. Identical on purpose
403 4037 agent_pack_locked This account’s tier does not allow that pack yet. Carries details.allowed_packs; retry with one of those
429 4038 agent_purchase_capped 3 purchases, paid or declined, in the trailing 24 hours. Counted per account across every credential it has held, so rotating does not reset it. Carries details.retry_after_seconds

Once the claim secret itself checks out, an unpaid Checkout Session answers wrong_state (4001) rather than agent_claim_invalid. The full catalog is the OpenAPI document.

Limits

Calls are limited to 1,200 a minute. For an agent account that budget belongs to the account, not to the individual token: every credential in the rotation lineage draws on the same one, so rotating a PAT does not hand the successor a fresh allowance. The two billing writes, saving a card and buying a pack, share a tighter 60 a minute per account, ahead of the Stripe call either one makes. The 24 hour purchase cap above is counted the same way, per account rather than per credential.

Learn more

This page covers the account lifecycle: opening one, funding it, and keeping its credential alive. For everything the account can then do, see the REST API, including the full OpenAPI document, or the MCP server for the same account over tools instead of raw HTTP.

Start transcribing – 30 minutes to try

A $1 hold confirms your card and releases immediately — you're never charged, and 30 free minutes land right away.

Start – 30 free minutes