Help us shape the future of Go! Take the 2026 Go Developer Survey

hushscript

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 14, 2026 License: MIT Imports: 35 Imported by: 0

README

Hushscript Go SDK

The official Go SDK for Hushscript, a privacy-first, pay-as-you-go transcription service. It uploads a file, waits for the transcript and hands it back, and it handles the failures in between so you do not have to.

Why Hushscript

  • No subscription. You buy prepaid minute packs, and nothing recurs. Current prices are on the pricing page.
  • The audio you send isn't kept. The audio sent for transcription isn't kept after processing. Stored transcripts are encrypted at rest, and you choose how long they stay.
  • Free speaker labels and AI insights. Speaker labels carry no extra charge (medical mode and translation cost more). The first all-in AI insights run on a transcript (summaries, action items, quotes, chapters) is free in the Hushscript app.
  • Built for specialist recordings. Key terms, prompts and multichannel audio in around 99 languages, plus a medical mode for English, Spanish, French and German.
  • An SDK you can read. It is MIT licensed, official, sends no telemetry, and is tested against a conformance suite shared with the other Hushscript SDKs.

What you can do with it

  • Transcribe a file from a path, an io.ReaderAt or a forward-only stream, with progress callbacks and retries that cannot charge you twice.
  • Set the language or let it be detected, turn speaker labels on or off, and pass Keyterms and a Prompt to steer the vocabulary.
  • Use medical mode, multichannel audio, or translate into other languages (TranslateTo) in the same call.
  • Export SRT, WebVTT and plain text that match the Hushscript app's exports byte for byte, including translations and the AI-cleaned body.
  • Resume an interrupted job with its resume token instead of paying twice.
  • Check your balance, list transcripts and jobs, and buy minute packs from code (off until you allow it).
  • Let an agent sign up, pay at a hosted checkout and claim its own token, with no human account.

Website · Pricing · SDK docs · API reference

Quick start

go get github.com/Hushscript/hushscript-sdk-go
export HUSHSCRIPT_TOKEN=hsr1:...   # Account → MCP in the Hushscript app
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	hushscript "github.com/Hushscript/hushscript-sdk-go"
)

func main() {
	client, err := hushscript.New() // reads HUSHSCRIPT_TOKEN
	if err != nil {
		log.Fatal(err)
	}
	transcript, err := client.Transcribe(context.Background(), "meeting.mp3", nil)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(transcript.Text(nil))
	if err := os.WriteFile("meeting.srt", []byte(transcript.SRT(nil)), 0o600); err != nil {
		log.Fatal(err)
	}
}

Requires Go 1.25.0 or newer. Server-side use only: a token must never ship in a browser bundle.

Options that can be off, on or unset are *bool. hushscript.Bool(false) and hushscript.Bool(true) build one, and nil keeps the default:

transcript, err := client.Transcribe(ctx, "meeting.mp3", &hushscript.TranscribeOptions{
	Speakers: hushscript.Bool(false),
})
Key terms and prompt

Keyterms and Prompt bias the transcript toward your vocabulary and context. Both are trimmed (Unicode white space), blank terms are dropped and repeated terms count once; an empty list or a blank prompt means the option is off and nothing is sent. The limits, checked before any request (an invalid_option error names the offending term's index):

  • at most 1000 Keyterms;
  • each term at most 6 words and at most 128 characters (code points);
  • Prompt at most 2000 characters (code points);
  • with both set, the 2000 applies to the compiled prompt the backend builds: 203 + len(prompt) + sum(len(term) + 2) + (terms - 1).

Saved dictionaries and prompt presets are merged on the server, so the SDK cannot count them. The server stays the authority and answers 422 invalid_transcription_options without saying which limit failed.

Inputs

Transcribe takes a path. TranscribeReader takes an io.ReaderAt and its exact size. For a forward-only input (a pipe, a network body) use TranscribeStream: it reads one part at a time, in order, and needs the exact size and DurationSeconds, because a stream can be neither rewound nor probed.

transcript, err := client.TranscribeStream(ctx, resp.Body, resp.ContentLength, &hushscript.TranscribeOptions{
	DurationSeconds: 1800,
})

Resume takes the same kinds: ResumeOptions.Path, Reader with Size, or Stream, which is read from where it stands and must hold the size the resume token records.

Check my balance

balance, err := client.Balance(ctx)
if err != nil {
	return err
}
fmt.Printf("%d minutes to spend\n", balance.Minutes)

balance.Minutes is what you can spend now. Minutes held for jobs that are still running are already taken out of it, so do not subtract HeldSeconds again.

List my transcripts

for transcript, err := range client.Transcripts.List(ctx, nil) {
	if err != nil {
		return err
	}
	fmt.Println(transcript.ID, transcript.Title)
}

The list holds finished transcripts only. A recording that is still processing is a job, so look for it with client.Jobs.List(ctx, &hushscript.JobListOptions{Active: true}). client.Jobs.Wait waits for one, and client.Transcripts.Get returns the full Transcript once it is done. Every list is an iter.Seq2 that fetches pages as you range over it, checks ctx between pages, and yields an error once and then stops.

Buy a pack

packs, err := client.Billing.Packs(ctx)
if err != nil {
	return err
}
for _, pack := range packs {
	fmt.Println(pack.ID, pack.Minutes, "minutes", pack.Price.Formatted)
}
purchase, err := client.Buy(ctx, "300min", &hushscript.BuyOptions{AcknowledgeNoRefund: true})
if err != nil {
	return err
}
fmt.Printf("%d minutes to spend now\n", purchase.Minutes)

The packs are 45min, 300min, 900min, 1800min and 6000min. Prices depend on your country, so read them from pack.Price and never hard-code one. Price.Formatted divides by the minor-unit digits of Stripe's currency table, not by locale data.

Buy charges your saved default card, or the only card that can be charged when there is no default, and returns a Purchase: the Seconds and Minutes from the purchase response, without a follow-up request. A lost or unusable response can still return an error after payment; retry with the IdempotencyKey attached to that error. With no usable card it returns a KindPaymentMethodRequired error and sends nothing: no_default_card when there is none (add one at the URL from client.Billing.AddCardURL, or in the app), default_card_required when several cards could be charged and none is the default (pick one with client.Billing.SetDefaultCard).

Show your buyer this notice before you call it, then set AcknowledgeNoRefund:

Minutes are added to your account instantly after payment. All purchases are final and non-refundable.

The flag records that the notice was shown. It does not gate the charge, and without it Buy still goes ahead.

Allow buying first

Buying from code is off until you allow it in three places. If any is missing, the call fails with pat_scope_missing.

  1. The token has the permission labeled "Buy minutes and manage your saved payment methods" (the billing scope), ticked when you create it.
  2. The token has "Let this token buy minutes" turned on, on the same "Create a new token" form.
  3. "Let connected apps buy minutes" is on for the whole account.

All of it is in the app under Account → MCP.

When a purchase does not go through

If the card is declined or cannot be charged without you, the call fails with pat_purchase_requires_app (4021, HTTP 403); if the bank wants to confirm the payment, it fails with pat_purchase_requires_authentication (4023, HTTP 403). In both cases nothing was charged: buy that pack in the app. A key that met 4021 is dead; a new Buy call mints a new one.

A purchase is retried at most once, on a network error, a 502 or a 503, with the same idempotency key, so those retries cannot charge you twice. When Buy still gives up after the request was sent (the connection dropped twice, a 401, a 408, a 409, a 429, a server error, or an answer the SDK cannot use), the card may have been charged. Every such error carries IdempotencyKey; ask again with it and the purchase can never happen twice:

purchase, err := client.Buy(ctx, "300min", &hushscript.BuyOptions{AcknowledgeNoRefund: true})
var failure *hushscript.Error
if errors.As(err, &failure) && failure.IdempotencyKey != "" {
	switch {
	case failure.Status == 400 || failure.Status == 402 || failure.Status == 404 || failure.Status == 422 ||
		failure.Status == 403 && (failure.NumericCode == 4021 || failure.NumericCode == 4023):
		// Only these refusals charged nothing (4021 and 4023 are 403). A 401 or a 429 does not
		// prove it: the server answers them before it replays a completed purchase, so after the
		// SDK's one retry they can follow a first attempt that charged.
	default:
		// Anything else after the send may have charged: a 401, a 408, a 409, a 429, a 5xx, no
		// status at all (a lost connection) or an unusable answer. Ask again with the same key.
		purchase, err = client.Buy(ctx, "300min", &hushscript.BuyOptions{
			AcknowledgeNoRefund: true,
			IdempotencyKey:      failure.IdempotencyKey,
		})
	}
}

A key you pass yourself must be 1 to 128 characters from A-Za-z0-9_-. Do not reuse a key for a different pack.

Export subtitles

_ = os.WriteFile("meeting.srt", []byte(transcript.SRT(nil)), 0o600)
_ = os.WriteFile("meeting.vtt", []byte(transcript.VTT(&hushscript.FormatOptions{Language: "es"})), 0o600)
_ = os.WriteFile("meeting.txt", []byte(transcript.Text(&hushscript.TextOptions{Timestamps: true})), 0o600)

The output is byte for byte what the Hushscript app exports. SRT and VTT wrap lines into caption cues by default; pass Captions: hushscript.Bool(false) for one cue per utterance.

Agents: sign up without a human account

An agent can open an account, have it paid for at a hosted checkout page, and claim its own token. Signup and claim need no token yet, so they are package functions, not methods of a Client. They take the same options as New (WithBaseURL, WithHTTPClient and so on) and ignore a token.

// The server shows each token once, so write every one down the moment it arrives.
keep := func(token string) error {
	file, err := os.CreateTemp(".", ".token-*") // created with mode 0600
	if err != nil {
		return err
	}
	if _, err := file.WriteString(token + "\n"); err != nil {
		_ = file.Close()
		_ = os.Remove(file.Name())
		return err
	}
	if err := file.Close(); err != nil {
		_ = os.Remove(file.Name())
		return err
	}
	return os.Rename(file.Name(), "agent-token") // an earlier token is replaced, never truncated first
}

signup, err := hushscript.AgentSignup(ctx, hushscript.AgentSignupRequest{
	Email:       "agent@example.com",
	Pack:        "45min",
	AcceptTerms: "<the policy version you accept>",
	Agent:       hushscript.AgentInfo{Name: "My agent", Platform: "custom"},
})
if err != nil {
	return err
}
fmt.Printf("Pay %s at %s\n", signup.Price.Formatted, signup.CheckoutURL)

// After the checkout is paid:
account, err := hushscript.AgentClaim(ctx, signup.SignupID, signup.ClaimSecret)
if err != nil {
	return err
}
if err := keep(account.Token); err != nil { // before anything else can fail
	return err
}
client, err := hushscript.New(hushscript.WithToken(account.Token))
if err != nil {
	return err
}
next, err := client.Agent.RotateToken(ctx) // revokes the claimed token; the client sends next.Token
if err != nil {
	return err
}
if err := keep(next.Token); err != nil {
	return err
}
  • AcceptTerms is never filled in for you; an empty one is a KindValidation error (accept_terms_required) before any request. A wrong version fails with policy_version_stale, and the error's Hint names the current one.
  • The claim answers wrong_state (a KindConflict error) until the checkout is paid.
  • New agent accounts can buy only 45min and 300min until earlier purchases settle.
  • Keep ClaimSecret and every token: the server shows each of them once, and a rotation revokes the token it replaces, so lose the new one and the account is out of reach. A claim or a rotation whose answer is lost, or comes back without a usable token, is a KindOutcomeUnknown error and is never retried, because a retry could not succeed; its Hint says what to check. When the answer did carry a token but not the rest, Error.ReceivedToken() returns it so it is not lost; it never appears in a printed or encoded error.
  • ClaimSecret, AgentAccount.Token and RotatedToken.Token stay readable fields, but printing the result with any fmt verb (%v, %+v, %#v, %s), a Stringer call or slog's text handler shows [redacted] in their place. json.Marshal carries the value on purpose, so do not encode these results into a log.
  • DryRun: true validates a signup without opening a checkout.

Errors

Every error the SDK returns is a *hushscript.Error: match it with errors.As and branch on Kind or Code.

transcript, err := client.Transcribe(ctx, "meeting.mp3", nil)
var failure *hushscript.Error
switch {
case err == nil:
	fmt.Println(transcript.Text(nil))
case errors.As(err, &failure) && failure.Kind == hushscript.KindInsufficientBalance:
	fmt.Println(failure.Hint)
case errors.As(err, &failure):
	fmt.Println(failure.Code, failure.Hint)
default:
	return err
}

An error carries Code (a slug such as insufficient_balance), NumericCode, Status (0 when there was no response), Message, Hint (what to do next, or empty), Details (the API's own snake_case keys) and RetryAfter. The kinds, with Kind.String() giving the class name every Hushscript SDK uses:

ApiError                         has Status (Kind.IsAPI)
├─ AuthenticationError           401
├─ PermissionDeniedError         403
├─ InsufficientBalanceError      402
├─ NotFoundError                 404
├─ ConflictError                 409
├─ ValidationError               400, 422
└─ RateLimitError                429
ConfigurationError
HushscriptError                  unexpected_error, Status 0 (KindUnexpected)
PreflightError                   no credit was held (Kind.IsPreflight)
├─ UnsupportedMediaError
├─ FileLimitError
├─ DailyLimitError
└─ ResumeMismatchError
PaymentMethodRequiredError
UploadError
JobFailedError
WaitTimeoutError                 has ResumeToken
AbortError                       has ResumeToken once a job exists
NetworkError
OutcomeUnknownError

An error returned after an upload started, or after a purchase was sent, carries IdempotencyKey; once the job exists it carries ResumeToken too. Pass the token to client.Resume to carry on without a second charge.

A failure of the SDK's own after a request was sent, one that fits none of the kinds above, is a KindUnexpected error (class name HushscriptError) with the code unexpected_error and Status 0; the original rides along as its cause, redacted. It is not an API answer, so Kind.IsAPI is false for it. OnProgress and OnResumeToken cannot return an error: a panic in one is yours, and leaves the call with the value you raised, never recovered or wrapped. runtime.Goexit inside a callback is unsupported. The SDK does not recover panics from its own internals either; number parsing is fuzzed instead, so a malformed answer comes back as an error, not a panic.

What the SDK does for you

  • Checks before it spends. It sniffs the format from the file's bytes, probes the duration, and refuses a file the server would refuse, or one your daily limit cannot cover, before any minutes are held. It does not check your balance: the server decides at create whether the job can be paid (an organization pool can pay for it), and its 402 arrives before any part is sent.
  • Keeps retries from charging twice. Every upload and purchase carries an idempotency key, and retries reuse it. A resume token replays the same job instead of starting a new one, and the key on a failed purchase does the same for Buy.
  • Retries what is safe. Reads, heartbeats and part uploads retry on network errors, 429 and 5xx with jittered backoff, and honor Retry-After up to 60 seconds. A purchase retries once on a network error, 502 or 503. A claim, a rotation and a signup never retry.
  • Paces uploads. The API allows four upload creates a minute. A loop over a folder waits as needed, and OnProgress keeps reporting.
  • Keeps the upload alive. It uploads parts in parallel with bounded memory, falls back to the proxied route when direct upload fails, refreshes expired part URLs and sends a heartbeat every two minutes.
  • Waits and fetches. It polls the job until it is done, returns a KindJobFailed error if it fails, and gives you a resume token if the wait times out. The job keeps running.
  • Reads the token per attempt. After RotateToken, every later attempt, retries already queued included, sends the new token.
  • Redacts the token from every error, log line and formatted Client, and the secrets in the signup, claim and rotation results from their printed forms.

Supported formats

MP3, M4A, MP4 and MOV (the audio track of a video is used), WAV, FLAC, and OGG with Vorbis or Opus. Files can be up to 5 GB and from 15 seconds to 10 hours. The SDK does not convert media. For anything else, convert it first:

ffmpeg -i input -vn -c:a libopus output.opus

Configuration

New takes functional options:

Option Env var Default
WithToken HUSHSCRIPT_TOKEN none
WithBaseURL HUSHSCRIPT_BASE_URL https://api.hushscript.com
WithTimeout none 60 s per request attempt
WithMaxRetries none 3 (0 turns retries off)
WithLogLevel HUSHSCRIPT_LOG off (debug logs one metadata line per request attempt to standard error)
WithLogger none none; an *slog.Logger that receives the debug lines instead
WithHTTPClient none a plain http.Client that never follows redirects
WithClock none the system clock; pass a Clock in tests

An explicit option beats its environment variable. A token, base URL or log level that is empty or only whitespace, as an option or in its environment variable, counts as not set: the option falls back to the environment variable, then to the default, and a missing token is a configuration error. The base URL must be https://, or http:// to localhost, 127.0.0.1 or [::1], with no path. Each upload part has its own 300 s timeout, which you cannot change. WithHTTPClient takes a shallow copy of the *http.Client at New, so reassigning its fields afterwards does not reach the SDK.

Privacy

The SDK sends no telemetry. The only client identification is the User-Agent header (hushscript-go/<version> go/<version>, or go/devel on a toolchain without a numeric version). Logging is off by default; HUSHSCRIPT_LOG=debug (or WithLogLevel("debug"), or WithLogger) writes one line per request attempt with the method, path, status and timing, and never a header, body, title or transcript text.

The low-level API

Every /v1 operation is available as client.API(), the generated client, sent through the same retries, timeouts and redaction:

response, err := client.API().GetAccountWithResponse(ctx)

The friendly results keep what the API sent in a Raw field, unknown fields included: Account, Balance, Job, Pack, Card, Cards, Purchase, Transaction, LedgerEntry, Hold, TranscriptSummary, DeletedTranscript, Utterance, the agent results, and the nested UploadLimits and JobOptions. AgentSignupResult.Raw, AgentAccount.Raw and RotatedToken.Raw hold a secret, so no text form of those results prints it. Structs with a Raw field cannot be compared with ==, and json.Marshal of them now writes a Raw key. client.API() returns the whole body as well.

Server only

The SDK is for servers. The API does not accept browser origins, and a token in a browser bundle is a leaked token.

Pricing

Personal accounts buy prepaid minute packs. The price of a pack depends on your country, and your minutes stay valid for a year after your last transcription or purchase. A transcription uses the minutes of the recording; medical mode and each translation target use more. Current prices are on hushscript.com/pricing.

Requirements

Go 1.25.0 or newer. CI tests Go 1.25, 1.26 and 1.27 with automatic toolchain downloads disabled. Go 1.25 no longer receives upstream security updates; use Go 1.26.9 or newer for production. The vulnerability check remains a required gate on every runtime.

Releases

Releases come from release-please. A Go module is published by its tag, so there is no registry token: when the release PR is merged, the publish workflow builds the source archive and a CycloneDX SBOM, attests the archive's build provenance behind the release environment, and attaches all three to the GitHub release. proxy.golang.org is asked for the new version once the tag exists.

Development

Everything runs in containers; the host needs only just and Docker.

just ci        # lint, test, conformance, examples and build on Go 1.25, 1.26 and 1.27
just test      # unit tests with the race detector and the 85% coverage floor
just examples  # every program in examples/ against the conformance mock
just regen     # regenerate openapi.json and generated/ from the production spec

The conformance suite is read at the ref (a tag or a commit SHA) in conformance-ref, the one place it is pinned, and no scenario may be skipped (CONFORMANCE_STRICT=1, the default of the justfile). Until the conformance repository is public, point the mock and the fixtures at a local checkout: CONFORMANCE_CONTEXT=../hushscript-sdk-conformance CONFORMANCE_DIR=../hushscript-sdk-conformance just ci. The unit tests also read the conformance fixtures (fixtures/hint-rendering.json) and fail without them: just test and just mutation find a checkout through CONFORMANCE_DIR, then a local CONFORMANCE_CONTEXT, then a fetch of the pinned ref (scripts/conformance-dir.sh).

just mutation runs go-mutesting on the HTTP core and transcribe pipeline against the floor in the justfile (mutation_floor). The nightly workflow runs one just mutation-shard job per source file; each writes its killed and scored counts and fails only on a timeout or output it cannot read, and a final job runs just mutation-sum to enforce the floor on the total of all eight files.

generated/ is never edited by hand. scripts/generate.go also declares one path parameter the API document leaves out (signup_id on the claim operation), in a private copy of the spec.

Accepted deviations from the SDK specification
  • fieldalignment is off in .golangci.yml: struct layouts here, Error included, are ordered for readers, not for padding.
  • The Scorecard workflow has id-token: write, which section 13.3 allows only for publishing: Scorecard needs it to publish its results.
  • The audit compose service has outbound network access, next to regen and smoke: go mod tidy -diff (the module and tools/) asks the module proxy; on Go 1.27, the newest supported version, govulncheck also asks the vulnerability database. Older versions skip the vulnerability check.

Security

See SECURITY.md.

License

MIT

Documentation

Overview

Package hushscript is the official Go SDK for the Hushscript transcription API.

New builds a Client from options and the HUSHSCRIPT_TOKEN, HUSHSCRIPT_BASE_URL and HUSHSCRIPT_LOG environment variables. Client.API returns the generated client for every /v1 operation, wired to the SDK's retrying HTTP core: timeouts, retries with backoff, Retry-After handling, upload-create pacing, token redaction and typed errors. A failed call returns a *Error; use errors.As to read its Kind, Code, Status, Hint and Details.

Client.Transcribe uploads a file by path, Client.TranscribeReader an io.ReaderAt of known size, and Client.TranscribeStream a forward-only io.Reader, which needs its exact size and a DurationSeconds:

transcript, err := client.TranscribeStream(ctx, body, size, &hushscript.TranscribeOptions{DurationSeconds: 1800})

The SDK never logs headers, query strings, bodies or transcript text, and never prints the token.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Bool

func Bool(v bool) *bool

Bool returns a pointer to v, for the options that tell "not set" from false with a *bool: Speakers, AutoInsights, Captions and Merge. hushscript.Bool(false) turns one off.

Types

type Account

type Account struct {
	// BalanceSeconds is net of holds and clawback debt; it may be negative.
	BalanceSeconds int
	// HeldSeconds is committed to in-flight jobs and already deducted from BalanceSeconds.
	HeldSeconds int
	// CreditsExpireAt is when the balance expires; nil while no expiry is armed.
	CreditsExpireAt *time.Time
	CardOnFile      bool
	// DataRegion is for example us, eu, apac or oc.
	DataRegion string
	Limits     UploadLimits
	// PurchasesRemainingInWindow is set for agent accounts only; nil otherwise.
	PurchasesRemainingInWindow *int
	// Raw is the answer as the API sent it, unknown fields included.
	Raw json.RawMessage
}

Account is the account: balance, limits, card and region (spec 6.3).

type AgentAccount

type AgentAccount struct {
	// Token is the account's token, shown once: write it down before anything else can fail.
	Token  string
	UserID string
	Scopes []string
	// Balance is the pack just granted. A new account holds nothing and has no expiry in the answer.
	Balance Balance
	// Raw is the answer as the API sent it, unknown fields included. It holds the token, so no text form
	// of the result shows it.
	Raw json.RawMessage
}

AgentAccount is what AgentClaim returns.

func AgentClaim

func AgentClaim(ctx context.Context, signupID, claimSecret string, opts ...Option) (*AgentAccount, error)

AgentClaim claims a paid agent signup and returns the account's token, which the server shows once. Write it down before doing anything else. It needs no token and takes the same options as AgentSignup. The claim answers wrong_state (a KindConflict error) until the checkout is paid. It is never retried: a lost answer, or one without a token, is an OutcomeUnknown error whose Hint says what to check.

func (AgentAccount) Format

func (a AgentAccount) Format(f fmt.State, _ rune)

Format covers every fmt verb, including %d and %x, which would otherwise print the struct fields.

func (AgentAccount) GoString

func (a AgentAccount) GoString() string

GoString is String, so %#v never shows the token either.

func (AgentAccount) String

func (a AgentAccount) String() string

String shows the account with Token replaced by [redacted]; the field itself stays readable.

type AgentInfo

type AgentInfo struct {
	Name     string
	Platform string
	// ContactURL is optional.
	ContactURL string
}

AgentInfo describes the agent an account is opened for.

type AgentService

type AgentService struct {
	// contains filtered or unexported fields
}

AgentService is Client.Agent: the call an agent account makes with its own token.

func (AgentService) RotateToken

func (a AgentService) RotateToken(ctx context.Context) (*RotatedToken, error)

RotateToken mints a successor token and revokes the one in use. The Client sends the new token from then on, to retries already queued as well; store the returned one right away. It is never retried: a lost answer, or one without a usable token, is an OutcomeUnknown error whose Hint says what to check, and the Client keeps its old token then.

type AgentSignupRequest

type AgentSignupRequest struct {
	// Email is for receipts and notices only; it never signs in.
	Email string
	// Pack is 45min or 300min: a new agent account can buy only those two until earlier purchases settle.
	Pack string
	// AcceptTerms is the policy version being accepted. It is never defaulted, and an empty one is
	// refused before any request. A stale one fails with policy_version_stale, and the error's Hint
	// names the current version.
	AcceptTerms string
	Agent       AgentInfo
	// DataRegion is an optional hint, honored only when it agrees with the region derived from the network.
	DataRegion string
	// DryRun validates the request without opening a checkout; the result cannot be claimed.
	DryRun bool
}

AgentSignupRequest is the request of AgentSignup.

type AgentSignupResult

type AgentSignupResult struct {
	// SignupID is passed back to AgentClaim verbatim.
	SignupID string
	// ClaimSecret is shown once; AgentClaim needs it.
	ClaimSecret string
	// CheckoutURL is the hosted checkout page where the account is paid for; it expires at ExpiresAt.
	CheckoutURL string
	Price       Money
	ExpiresAt   time.Time
	// Raw is the answer as the API sent it, unknown fields included. It holds the claim secret, so no
	// text form of the result shows it.
	Raw json.RawMessage
}

AgentSignupResult is what AgentSignup returns.

func AgentSignup

func AgentSignup(ctx context.Context, req AgentSignupRequest, opts ...Option) (*AgentSignupResult, error)

AgentSignup opens an agent account. It needs no token: a token from an option or HUSHSCRIPT_TOKEN is not sent. The agent then has the checkout paid, at CheckoutURL, and claims the account with AgentClaim. Options are the ones of New that apply (WithBaseURL, WithHTTPClient, WithTimeout, WithLogger and kin). The request is never retried; a lost answer is an OutcomeUnknown error.

func (AgentSignupResult) Format

func (r AgentSignupResult) Format(f fmt.State, _ rune)

Format covers every fmt verb, including %d and %x, which would otherwise print the struct fields.

func (AgentSignupResult) GoString

func (r AgentSignupResult) GoString() string

GoString is String, so %#v never shows the claim secret either.

func (AgentSignupResult) String

func (r AgentSignupResult) String() string

String shows the result with ClaimSecret replaced by [redacted]; the field itself stays readable.

type Balance

type Balance struct {
	// Seconds is spendable now and may be negative (clawback debt). The seconds held for in-flight jobs
	// are already deducted: it is not "balance minus held".
	Seconds int
	// Minutes is Seconds / 60, rounded toward zero.
	Minutes int
	// HeldSeconds is committed to in-flight jobs and already deducted from Seconds.
	HeldSeconds int
	// ExpiresAt is when the balance expires; nil while no expiry is armed.
	ExpiresAt *time.Time
	// PurchasesRemaining is set for agent accounts only; nil otherwise.
	PurchasesRemaining *int
	// Raw is the account answer it was read from as the API sent it, unknown fields included.
	Raw json.RawMessage
}

Balance is what an account can spend.

type BillingService

type BillingService struct {
	// contains filtered or unexported fields
}

BillingService is the friendly layer over the billing endpoints: Client.Billing.

func (BillingService) AddCardURL

func (b BillingService) AddCardURL(ctx context.Context) (string, error)

AddCardURL returns the hosted page where a card is saved; open it in a browser. The request carries a key, so its one retry after a 502 lands on the same page.

func (BillingService) Buy

func (b BillingService) Buy(ctx context.Context, pack string, opts *BuyOptions) (*Purchase, error)

Buy buys a pack with the default card, or the only card that can be charged when there is no default, and returns the balance the purchase answer reports, without a follow-up request. A lost or unusable response can still return an error after payment. Every error raised after the purchase request was sent carries IdempotencyKey; pass it back in BuyOptions to ask again with no chance of a second charge. A nil opts uses the defaults.

func (BillingService) Cards

func (b BillingService) Cards(ctx context.Context) (*Cards, error)

Cards lists the saved payment methods and the default one.

func (BillingService) Holds

func (b BillingService) Holds(ctx context.Context) iter.Seq2[Hold, error]

Holds walks the seconds reserved by work in flight, newest first. The iterator is as in Transactions.

func (BillingService) Ledger

Ledger walks every movement of the credit balance, newest first: holds, settles, releases, purchases and refunds. The iterator is as in Transactions.

func (BillingService) Packs

func (b BillingService) Packs(ctx context.Context) ([]Pack, error)

Packs lists the minute packs the account can buy, priced in its own currency. It needs the billing scope.

func (BillingService) SetDefaultCard

func (b BillingService) SetDefaultCard(ctx context.Context, cardID string) error

SetDefaultCard makes a saved card the default one.

func (BillingService) Transactions

func (b BillingService) Transactions(ctx context.Context) iter.Seq2[Transaction, error]

Transactions walks the purchases, newest first. The iterator yields an error once and then ends.

type BuyOptions

type BuyOptions struct {
	// AcknowledgeNoRefund records that the no-refund, instant-delivery notice was shown to the buyer.
	// It is evidence for disputes and never gates the charge: without it Buy still goes ahead.
	AcknowledgeNoRefund bool
	// IdempotencyKey is 1 to 128 characters from A-Z, a-z, 0-9, _ and -. Left empty, Buy mints one.
	// Pass the key an error carried to ask again without any chance of a second charge.
	IdempotencyKey string
}

BuyOptions are the options of Buy. The zero value buys with a fresh idempotency key and does not acknowledge the notice.

type Card

type Card struct {
	ID    string
	Type  string
	Brand string
	Last4 string
	// ExpMonth and ExpYear are 0 when the method has no expiry.
	ExpMonth int
	ExpYear  int
	// Email is "" when the method has none.
	Email     string
	IsDefault bool
	// FastCheckoutEligible says whether Buy may charge it without the buyer present.
	FastCheckoutEligible bool
	// Raw is the method as the API sent it, unknown fields included.
	Raw json.RawMessage
}

Card is a saved payment method.

type Cards

type Cards struct {
	// DefaultID is "" when there is no default card.
	DefaultID string
	Cards     []Card
	// Raw is the answer as the API sent it, unknown fields included.
	Raw json.RawMessage
}

Cards is the saved payment methods and which one is the default.

type Client

type Client struct {
	// Jobs lists, reads and waits for processing jobs.
	Jobs JobsService
	// Transcripts lists and reads finished transcripts.
	Transcripts TranscriptsService
	// Billing lists packs and cards, buys minutes and reads the purchase history.
	Billing BillingService
	// Agent rotates the token of an agent account. Signup and claim need no token: see AgentSignup
	// and AgentClaim.
	Agent AgentService
	// contains filtered or unexported fields
}

Client is the entry point of the SDK. It is safe for concurrent use.

func New

func New(opts ...Option) (*Client, error)

New builds a Client from the options, the environment and the defaults (see the With options). It returns a *Error of kind KindConfiguration when the configuration is unusable.

func (Client) API

API returns the generated client for every /v1 operation, sharing the SDK's retries, timeouts and error handling. On a zero Client (one not built by New) it returns a client whose every call fails with a KindConfiguration error, so a forgotten New shows up as an error and not a nil dereference.

func (Client) Account

func (c Client) Account(ctx context.Context) (*Account, error)

Account reads the account: balance, limits, card on file and data region.

func (Client) Balance

func (c Client) Balance(ctx context.Context) (*Balance, error)

Balance reads what the account can spend. It is net of holds: HeldSeconds says how much of the balance is already committed, and is not to be subtracted again.

func (Client) Buy

func (c Client) Buy(ctx context.Context, pack string, opts *BuyOptions) (*Purchase, error)

Buy buys a pack; it is Billing.Buy.

func (Client) Format

func (c Client) Format(f fmt.State, _ rune)

Format covers every fmt verb, including %d and %x, which would otherwise print the struct fields.

func (Client) GoString

func (c Client) GoString() string

GoString is String, so %#v never shows the token either.

func (*Client) LogValue

func (c *Client) LogValue() slog.Value

LogValue is the client as slog logs it: the same text as String, never the struct. It is on the pointer, so a nil *Client logs as "<nil>" and does not panic.

func (Client) Resume

func (c Client) Resume(ctx context.Context, token string, opts *ResumeOptions) (result *Transcript, err error)

Resume picks a transcription up from the token an error carried. It reads the job first. A job past uploading is waited for and fetched without the file; a job still uploading replays its create with the original key (which returns the same job, with no second hold) and needs the file, as Path, as Reader and Size, or as Stream, of the same size as the original. A Stream is read from where it stands, as the start of the file, and must hold exactly the size the token records; Size is not given with it. A job that no longer exists is a ResumeMismatch error with code resume_job_missing, and nothing is replayed.

func (Client) String

func (c Client) String() string

String describes the client without its token.

func (Client) Transcribe

func (c Client) Transcribe(ctx context.Context, path string, opts *TranscribeOptions) (*Transcript, error)

Transcribe uploads the file at path, waits for it to be transcribed and returns the transcript. The format is decided by the file's bytes, not its name. A nil opts uses every default.

Every error raised after the upload was created carries the idempotency key (Error.IdempotencyKey) and, once the job exists, a resume token (Error.ResumeToken); a cancelled ctx is a KindAbort error.

func (Client) TranscribeReader

func (c Client) TranscribeReader(ctx context.Context, r io.ReaderAt, size int64, opts *TranscribeOptions) (*Transcript, error)

TranscribeReader is Transcribe for a random-access reader of exactly size bytes. It reads each part at its own offset, never the whole file at once; a reader that holds more or fewer bytes than size is an UploadError with code stream_size_mismatch, before the upload is completed.

func (Client) TranscribeStream

func (c Client) TranscribeStream(ctx context.Context, r io.Reader, size int64, opts *TranscribeOptions) (*Transcript, error)

TranscribeStream is Transcribe for a forward-only reader of exactly size bytes, such as a pipe or a network body. The SDK cannot seek it or probe it, so opts.DurationSeconds is required, and the size must be exact: a reader that holds more or fewer bytes is an UploadError with code stream_size_mismatch, before the upload is completed. Parts are read one at a time, in order, with at most one part in memory. Canceling ctx is noticed between parts; close the reader to interrupt a read that is blocked. The SDK never closes r.

type Clock

type Clock interface {
	// Now returns the current time.
	Now() time.Time
	// Sleep waits for d, or returns the context's error as soon as the context is done.
	Sleep(ctx context.Context, d time.Duration) error
}

Clock is the SDK's source of time. Everything that waits (backoff, pacing, polling) goes through Sleep, so a test or the conformance runner can inject a clock that never really waits.

type DeletedTranscript

type DeletedTranscript struct {
	ID              string
	Title           string
	DurationSeconds int
	// CreatedAt is when the transcript was uploaded.
	CreatedAt time.Time
	DeletedAt time.Time
	// Cause is manual, scheduled, dormant or expired; a cause the SDK does not know yet passes through
	// as the API's own string.
	Cause string
	// Receipt is the stored deletion receipt, opaque and as the API sends it (snake_case keys, string
	// timestamps); nil when it could not be read back.
	Receipt map[string]any
	// Raw is the row as the API sent it, unknown fields included.
	Raw json.RawMessage
}

DeletedTranscript is the record kept after a transcript was removed; its content is gone.

type Error

type Error struct {
	// Code is the API's error slug such as "insufficient_balance", or the SDK's own slug.
	Code string
	// NumericCode is the API's stable numeric code, 0 for errors raised by the SDK.
	NumericCode int
	// Status is the HTTP status, 0 when there was no response.
	Status int
	// Hint tells the caller what to do about it, "" when there is nothing to add.
	Hint string
	// Details holds the extra keys of the error body with the API's own snake_case names, nested
	// objects included.
	Details map[string]any
	// RetryAfter is how long to wait before trying again, when the API said so.
	RetryAfter time.Duration
	// Kind is the class of the error.
	Kind ErrorKind
	// Message is the catalog meaning for API errors, a fixed text for the SDK's own.
	Message string
	// IdempotencyKey is the key of the upload create, set on every error Transcribe raises once the
	// create was sent. Passing it back in TranscribeOptions replays the same job instead of placing
	// a second hold.
	IdempotencyKey string
	// ResumeToken lets Resume pick the job up again. It is set once the job id is known, on a
	// WaitTimeout error and on a cancellation, and on every other error of a Transcribe call.
	ResumeToken string
	// JobID is the id of the failed job, on a JobFailed error.
	JobID string
	// FailureKind is "media_unreadable" or "media_undecodable" when the file itself could not be
	// read, on a JobFailed error; "" otherwise.
	FailureKind string
	// JobError is the job's own failure text, opaque, on a JobFailed error.
	JobError string
	// contains filtered or unexported fields
}

Error is the one error type of the SDK. Match it with errors.As and branch on Kind or Code. Status, NumericCode and RetryAfter are zero when they do not apply, which is always so for errors the SDK raises itself.

func (*Error) Error

func (e *Error) Error() string

Error returns the code, the message and the hint, with the token redacted.

func (*Error) LogValue

func (e *Error) LogValue() slog.Value

LogValue is the error as slog logs it: the redacted text of Error, never the struct. It is on the pointer, so a nil *Error (an error variable that holds a typed nil) logs as "<nil>" and does not panic.

func (*Error) ReceivedToken

func (e *Error) ReceivedToken() string

ReceivedToken is the token string a claim or rotation answer carried when the rest of the answer could not be used, so the credential the server showed once is not lost; "" when there is none. It is never part of Error(), the message, a formatted error or its JSON; treat it like any token.

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap returns the error that caused this one, for errors.Is and errors.As.

type ErrorKind

type ErrorKind int

ErrorKind is the class of an Error, following the hierarchy of the SDK specification (section 9.2).

const (
	KindAPI ErrorKind = iota
	KindConfiguration
	KindUnsupportedMedia
	KindFileLimit
	KindDailyLimit
	KindResumeMismatch
	KindAuthentication
	KindPermissionDenied
	KindInsufficientBalance
	KindNotFound
	KindConflict
	KindValidation
	KindRateLimit
	KindPaymentMethodRequired
	KindUpload
	KindJobFailed
	KindWaitTimeout
	KindAbort
	KindNetwork
	KindOutcomeUnknown
	// KindPreflight is appended so that the values of the kinds released before it do not move.
	KindPreflight
	// KindUnexpected is a failure of the SDK's own after a request was sent that fits no other kind
	// (code unexpected_error, Status 0). It is not an API answer: IsAPI is false for it.
	KindUnexpected
)

The error kinds. KindAPI is any non-2xx answer that has no more specific kind.

func (ErrorKind) IsAPI

func (k ErrorKind) IsAPI() bool

IsAPI reports whether the kind is an answer from the API: ApiError and its subclasses. KindUnexpected is not: it is a failure of the SDK's own and carries no status.

func (ErrorKind) IsPreflight

func (k ErrorKind) IsPreflight() bool

IsPreflight reports whether the kind belongs to the preflight family: errors raised before any request that holds credit, so no hold was placed. KindPreflight itself is the family's base, raised for an invalid option.

func (ErrorKind) String

func (k ErrorKind) String() string

String returns the class name used by every Hushscript SDK, for example "RateLimitError".

type FormatOptions

type FormatOptions struct {
	// Language is a translation locale or "cleaned"; "" and an unknown locale give the original.
	Language string
	// Captions re-cuts the text into cues of at most two lines of 42 characters; nil means true. False
	// gives one cue per utterance.
	Captions *bool
}

FormatOptions are the options of SRT and VTT. The zero value gives readable captions of the original language.

type Hold

type Hold struct {
	ID string
	// Kind is transcription, translation, insights or qa; a kind the SDK does not know yet passes through.
	Kind      string
	Seconds   int
	CreatedAt time.Time
	// Raw is the row as the API sent it, unknown fields included.
	Raw json.RawMessage
}

Hold is seconds reserved by work still running; they are already deducted from the balance.

type Job

type Job struct {
	ID string
	// State is uploading, fetching, queued, processing, done or failed; a state the SDK does not know
	// yet passes through as the API's own string.
	State string
	// TranscriptID is set once the job is done.
	TranscriptID string
	// Error is the failure text of a failed job, opaque.
	Error string
	// FailureKind is "media_unreadable" or "media_undecodable" when the file itself could not be read.
	FailureKind string
	Mode        string
	// DeclaredSeconds, VerifiedSeconds, ActualSeconds and BillableSeconds are nil while unknown.
	DeclaredSeconds *int
	VerifiedSeconds *int
	ActualSeconds   *int
	BillableSeconds *int
	// RetryOf is the id of the failed job this one retries; "" when it retries none.
	RetryOf   string
	CreatedAt time.Time
	Options   JobOptions
	// Raw is the job as the API sent it, unknown fields included.
	Raw json.RawMessage
}

Job is a processing job as the API reports it (spec 6.4). The private-result and from-url fetch fields are left out; Client.API still returns them.

type JobListOptions

type JobListOptions struct {
	// Active keeps only the jobs that have not finished.
	Active bool
}

JobListOptions are the options of Jobs.List.

type JobOptions

type JobOptions struct {
	// LanguageCode is the forced language; "" when the language was auto-detected.
	LanguageCode       string
	SpeakerDetection   bool
	MedicalMode        bool
	Multichannel       bool
	TranslationTargets []string
	// Keyterms and Prompt say whether they were set.
	Keyterms bool
	Prompt   bool
	// AutoGenerateInsights is the upload's override; nil when it used the account default.
	AutoGenerateInsights *bool
	// Raw is the options object as the API sent it, unknown fields included.
	Raw json.RawMessage
}

JobOptions is what a job was submitted with, from the API's content-free summary: it says whether keyterms and a prompt were set, never what they were.

type JobsService

type JobsService struct {
	// contains filtered or unexported fields
}

JobsService is the friendly layer over the jobs endpoints: Client.Jobs.

func (JobsService) Get

func (j JobsService) Get(ctx context.Context, id string) (*Job, error)

Get reads one job.

func (JobsService) List

func (j JobsService) List(ctx context.Context, opts *JobListOptions) iter.Seq2[Job, error]

List walks every job, newest first, fetching pages as it goes; a nil opts lists them all. The iterator yields an error once and then ends. ctx is checked before every page and every job.

func (JobsService) Wait

func (j JobsService) Wait(ctx context.Context, id string, opts *WaitOptions) (*Job, error)

Wait polls the job until it is done or failed and returns it either way; a failed job is a result here, not an error. Running out of WaitTimeout is a WaitTimeout error without a resume token.

type LedgerEntry

type LedgerEntry struct {
	ID           int
	DeltaSeconds int
	Kind         string
	// JobID and Note are "" when the entry has none.
	JobID     string
	Note      string
	CreatedAt time.Time
	// Raw is the entry as the API sent it, unknown fields included.
	Raw json.RawMessage
}

LedgerEntry is one movement of the credit balance.

type ListOptions

type ListOptions struct {
	// PageSize is the rows per page: 0 for the API's default of 50, otherwise 1 or more (the API clamps
	// it at 100).
	PageSize int
}

ListOptions are the options of Transcripts.List.

type Money

type Money struct {
	// Amount is in the currency's minor units, from the API.
	Amount int
	// Currency is the ISO 4217 code as the API sends it.
	Currency string
	// Formatted is Amount divided by Stripe's minor-unit digits for the currency.
	Formatted string
}

Money is a price as the API states it, with a display string in the en locale.

The amount digits and the grouping rules (minor-unit digits from Stripe's table, thousands grouped with commas) are the same in every Hushscript SDK. The rest of Formatted is this SDK's own: it writes $, €, £ or ¥ for USD, EUR, GBP and JPY, and for every other known currency the code and a no-break space before the number ("KRW 1,234"), where the TypeScript SDK takes its symbols from Intl and may print another. Compare Amount and Currency, never Formatted, across SDKs.

type Option

type Option func(*config) error

Option configures New.

func WithBaseURL

func WithBaseURL(baseURL string) Option

WithBaseURL sets the API host. It must be https, or http to localhost, 127.0.0.1 or [::1] (the conformance mock). An empty or whitespace-only value counts as not set: New reads HUSHSCRIPT_BASE_URL and then uses https://api.hushscript.com.

func WithClock

func WithClock(clock Clock) Option

WithClock replaces the clock the SDK sleeps on, for tests and the conformance runner.

func WithHTTPClient

func WithHTTPClient(client *http.Client) Option

WithHTTPClient replaces the http.Client the SDK sends requests with, for a proxy, custom TLS roots or a counting transport. The SDK sets no Client.Timeout of its own on it (timeouts go through contexts). It sends through a shallow copy that never follows redirects, so the caller's client is left as it was and a 3xx answer is an error, whatever CheckRedirect the caller set.

func WithLogLevel

func WithLogLevel(level string) Option

WithLogLevel sets the log level to "off" or "debug". It beats HUSHSCRIPT_LOG, so WithLogLevel("off") silences HUSHSCRIPT_LOG=debug. "debug" without WithLogger logs to standard error. An empty or whitespace-only level counts as not set: New reads HUSHSCRIPT_LOG.

func WithLogger

func WithLogger(logger *slog.Logger) Option

WithLogger turns on one debug line per request attempt: method, path, status, attempt, duration and retry delay. Never headers, queries, bodies or titles. Without it, HUSHSCRIPT_LOG=debug logs to standard error.

func WithMaxRetries

func WithMaxRetries(retries int) Option

WithMaxRetries sets how many times a request is retried after the first attempt (default 3). It caps every retry rule; 0 turns retries off.

func WithTimeout

func WithTimeout(timeout time.Duration) Option

WithTimeout sets the per-request timeout (default 60 s). Each attempt of a retried request gets its own.

func WithToken

func WithToken(token string) Option

WithToken sets the API token. An empty or whitespace-only token counts as not set, and so does an empty or whitespace-only HUSHSCRIPT_TOKEN: New reads HUSHSCRIPT_TOKEN when the option is not set.

type Pack

type Pack struct {
	// ID is 45min, 300min, 900min, 1800min or 6000min.
	ID      string
	Seconds int
	// Minutes is Seconds / 60, rounded toward zero.
	Minutes int
	// Price is in the account's own currency, as the API states it: never hard-code one.
	Price Money
	// BonusMinutes is what an available referral bonus would add to this purchase; 0 when none.
	BonusMinutes int
	// Available is false only for an agent account's tier-locked pack.
	Available bool
	// Raw is the pack as the API sent it, unknown fields included.
	Raw json.RawMessage
}

Pack is a minute pack as the account can see it.

type Page

type Page[T any] struct {
	Items      []T
	NextCursor string
}

Page is one page of a list. NextCursor is opaque and "" on the last page.

type PageOptions

type PageOptions struct {
	// Cursor is a previous page's NextCursor; "" fetches the first page.
	Cursor string
	// PageSize is as in ListOptions.
	PageSize int
}

PageOptions are the options of Transcripts.Page.

type Progress

type Progress struct {
	Stage ProgressStage
	// Percent is the share of bytes the API has acknowledged, 0 to 100 (uploading only).
	Percent    int
	BytesSent  int64
	BytesTotal int64
	// State is "queued" or "processing" (processing only).
	State string
}

Progress is one report to a TranscribeOptions.OnProgress callback. It is called from the goroutine that runs the call and from its upload workers, never concurrently with itself.

type ProgressStage

type ProgressStage string

ProgressStage says what a Progress report is about.

const (
	// StageUploading reports Percent, BytesSent and BytesTotal.
	StageUploading ProgressStage = "uploading"
	// StageProcessing reports State, "queued" or "processing".
	StageProcessing ProgressStage = "processing"
)

The two stages of a transcription.

type Purchase

type Purchase struct {
	// Seconds is the balance after the purchase settled: spendable now, holds already deducted.
	Seconds int
	// Minutes is Seconds / 60, rounded toward zero.
	Minutes int
	// Raw is the purchase answer as the API sent it, unknown fields included.
	Raw json.RawMessage
}

Purchase is what a purchase left the account with, read from the purchase answer alone.

type ResumeOptions

type ResumeOptions struct {
	// Path is the original file.
	Path string
	// Reader and Size are the original file as a random-access reader of exactly Size bytes.
	Reader io.ReaderAt
	Size   int64
	// Stream is the original file as a forward-only reader, positioned at the start of the file. Its
	// size is the one the resume token records, so there is no Size to give; it is read in order, once.
	Stream io.Reader
	// Concurrency, WaitTimeout and OnProgress are as in TranscribeOptions.
	Concurrency int
	WaitTimeout time.Duration
	OnProgress  func(Progress)
}

ResumeOptions are the options of Resume. The file is needed only while the job is still uploading; give it as Path, as Reader with Size, or as Stream; only one of them.

type RotatedToken

type RotatedToken struct {
	// Token is the successor token, shown once; the Client already sends it.
	Token   string
	TokenID string
	Scopes  []string
	// ExpiresAt is nil when the token never expires.
	ExpiresAt *time.Time
	// Raw is the answer as the API sent it, unknown fields included. It holds the successor token, so no
	// text form of the result shows it.
	Raw json.RawMessage
}

RotatedToken is what RotateToken returns.

func (RotatedToken) Format

func (r RotatedToken) Format(f fmt.State, _ rune)

Format covers every fmt verb, including %d and %x, which would otherwise print the struct fields.

func (RotatedToken) GoString

func (r RotatedToken) GoString() string

GoString is String, so %#v never shows the successor token either.

func (RotatedToken) String

func (r RotatedToken) String() string

String shows the rotation with Token replaced by [redacted]; the field itself stays readable.

type TextOptions

type TextOptions struct {
	Language string
	// Speakers prefixes each block with its speaker; nil means true.
	Speakers *bool
	// Timestamps prefixes each block with [M:SS] or [H:MM:SS].
	Timestamps bool
	// Merge joins consecutive utterances of the same speaker label; nil means true.
	Merge *bool
}

TextOptions are the options of Text. The zero value gives the original language with speaker names, consecutive turns of one speaker merged, and no timestamps.

type Transaction

type Transaction struct {
	ID                  int
	Seconds             int
	AmountCents         int
	AmountRefundedCents int
	Currency            string
	Status              string
	CreatedAt           time.Time
	PaymentMethodType   string
	PaymentMethodBrand  string
	PaymentMethodLast4  string
	// ReceiptNumber is the public receipt reference; "" when there is none.
	ReceiptNumber string
	InitiatedVia  string
	// Raw is the row as the API sent it, unknown fields included.
	Raw json.RawMessage
}

Transaction is one purchase, as the API reports it.

type TranscribeOptions

type TranscribeOptions struct {
	// Title is the transcript's title, at most 300 bytes (the server truncates).
	Title string
	// Language forces the spoken language; "" auto-detects.
	Language string
	// Speakers turns speaker labels on or off; nil leaves the API's default.
	Speakers *bool
	// TranslateTo lists locales to translate into: +25% of the duration each, and speakers are forced on.
	TranslateTo []string
	// Keyterms biases transcription toward domain vocabulary. Each term is trimmed (Unicode white
	// space), blank terms are dropped and repeated terms count once. At most 1000 terms remain, each
	// at most 6 words (runs of white space separate words) and at most 128 characters (code points).
	// No terms left means the option is off and nothing is sent. A violation is an invalid_option
	// error naming the term's index, raised before any request.
	Keyterms []string
	// Prompt is free-text context, trimmed (Unicode white space) and sent only when something is left.
	// It is at most 2000 characters (code points). With Keyterms the backend compiles both into one
	// provider prompt, and the 2000 applies to that compiled text: 203 characters of fixed wording,
	// the prompt, each term plus 2, and one more per term after the first. A violation is an
	// invalid_option error, raised before any request. Saved dictionaries and prompt presets are
	// merged server-side and are not counted here; the server answers 422 for them.
	Prompt string
	// Medical transcribes as a medical dictation (billed double); Language must be en, es, fr or de.
	Medical bool
	// Multichannel transcribes each audio channel on its own and bills per channel, up to 8.
	Multichannel bool
	// AutoInsights overrides the account's automatic-Insights default; nil inherits it.
	AutoInsights *bool
	// MatterCode files the transcript under a matter (organization accounts), at most 64 characters.
	MatterCode string
	// DurationSeconds overrides the duration probe. It must be finite and positive, and 15 to 36000.
	// TranscribeStream requires it: a forward-only stream cannot be probed.
	DurationSeconds float64
	// IdempotencyKey defaults to a fresh UUID v4 per call. Pass the key an error carried to replay the same job.
	IdempotencyKey string
	// Concurrency is how many parts upload at once: 0 for the default 4, otherwise 1 to 8.
	Concurrency int
	// WaitTimeout is how long to wait for processing: 0 for the default hour. The job keeps running
	// when it runs out, and the error carries a resume token.
	WaitTimeout time.Duration
	// OnProgress receives upload and processing reports.
	//
	// OnProgress and OnResumeToken cannot return an error. A panic in one is the caller's own: the
	// SDK does not recover it or wrap it, and it leaves the call with the value it was raised with (a
	// panic in OnProgress on an upload worker stops the upload and is raised again, unchanged, on the
	// goroutine that made the call).
	OnProgress func(Progress)
	// OnResumeToken is called once, as soon as the job exists.
	OnResumeToken func(token string)
}

TranscribeOptions are the options of Transcribe, TranscribeReader and their kin. The zero value transcribes with every default. A zero Concurrency, WaitTimeout or DurationSeconds means "unset"; a negative, NaN or infinite one is an invalid_option error, and nothing is ever clamped.

type Transcript

type Transcript struct {
	ID    string
	Title string
	// Language is the detected language; "" when there is none.
	Language        string
	DurationSeconds int
	CreatedAt       time.Time
	UpdatedAt       time.Time
	// AutoDeleteAt is when the transcript is scheduled to be purged; nil keeps it indefinitely.
	AutoDeleteAt *time.Time
	Tags         []string
	Edited       bool
	// Speakers maps a label to its display name, for the speakers that were renamed.
	Speakers map[string]string
	// Utterances are in the original language.
	Utterances []Utterance
	// Languages are the translation locales, without the reserved "cleaned", in the API's order.
	Languages []string
	// Cleaned is the AI-cleaned body; nil when there is none.
	Cleaned []Utterance
	// Raw is the API's body as it came, unknown fields included; it is what MarshalJSON writes.
	Raw json.RawMessage
	// contains filtered or unexported fields
}

Transcript is a finished transcription with its formatters (spec 6.2). It is read-only after it was built from the API's body, by Transcribe, Transcripts.Get or json.Unmarshal.

func (Transcript) MarshalJSON

func (t Transcript) MarshalJSON() ([]byte, error)

MarshalJSON writes the API body the Transcript was built from; a Transcript that was not built from one writes the fields it holds.

func (*Transcript) SRT

func (t *Transcript) SRT(opts *FormatOptions) string

SRT renders the transcript as SubRip subtitles, byte for byte what the Hushscript app exports.

func (*Transcript) Text

func (t *Transcript) Text(opts *TextOptions) string

Text renders the transcript as plain text: "Name: text" blocks joined by a blank line. "\r" and whitespace-only lines are kept as they come, as in the app.

func (*Transcript) UnmarshalJSON

func (t *Transcript) UnmarshalJSON(data []byte) error

UnmarshalJSON builds a Transcript from the body of GET /v1/transcripts/{id}.

func (*Transcript) UtterancesFor

func (t *Transcript) UtterancesFor(language string) []Utterance

UtterancesFor returns the translation (or "cleaned" body) for language, and the original when language is empty or the transcript has no such translation.

func (*Transcript) VTT

func (t *Transcript) VTT(opts *FormatOptions) string

VTT renders the transcript as WebVTT subtitles, byte for byte what the Hushscript app exports.

type TranscriptSummary

type TranscriptSummary struct {
	ID    string
	Title string
	// Language is the detected language; "" when there is none.
	Language        string
	DurationSeconds int
	CreatedAt       time.Time
	// AutoDeleteAt is when the transcript is scheduled to be purged; nil keeps it indefinitely.
	AutoDeleteAt *time.Time
	Tags         []string
	// Raw is the row as the API sent it, unknown fields included.
	Raw json.RawMessage
}

TranscriptSummary is one row of the transcript list.

type TranscriptsService

type TranscriptsService struct {
	// contains filtered or unexported fields
}

TranscriptsService is the friendly layer over the transcript endpoints: Client.Transcripts.

func (TranscriptsService) Deleted

Deleted walks the deletion records, by upload time, newest first. The iterator is as in List.

func (TranscriptsService) Get

Get reads one transcript, with its formatters.

func (TranscriptsService) List

List walks every finished transcript, newest first, fetching pages as it goes; a nil opts uses the default page size. The iterator yields an error once and then ends. ctx is checked before every page and every row. Transcripts still processing are jobs: see Jobs.List with Active.

func (TranscriptsService) Page

Page fetches one page of List. A page whose NextCursor is the Cursor it was asked with is the pagination_loop error (KindUnexpected), not a page.

type UploadLimits

type UploadLimits struct {
	// MaxDailySeconds is the daily transcription cap, in seconds.
	MaxDailySeconds int
	// MaxActiveJobs is the most pipeline jobs in flight at once.
	MaxActiveJobs int
	// ActiveJobs is the pipeline jobs in flight now.
	ActiveJobs int
	// UsedTodaySeconds is the billable seconds used today.
	UsedTodaySeconds int
	// Raw is the limits object as the API sent it, unknown fields included.
	Raw json.RawMessage
}

UploadLimits are the caller's current upload admission limits.

type Utterance

type Utterance struct {
	// Speaker is the provider's raw label; empty for a transcript without speaker labels.
	Speaker string
	// SpeakerName is the saved name, else "Speaker {label}", else "" for an empty label.
	SpeakerName string
	StartMs     int
	EndMs       int
	Text        string
	// Raw is the utterance object as the API sent it, unknown fields included.
	Raw json.RawMessage
}

Utterance is one speaker turn of a transcript.

type WaitOptions

type WaitOptions struct {
	// WaitTimeout is how long to wait: 0 for the default hour.
	WaitTimeout time.Duration
	OnProgress  func(Progress)
}

WaitOptions are the options of Jobs.Wait.

Directories

Path Synopsis
examples
agent-signup command
Signs an agent account up, waits for the checkout to be paid, claims the token and rotates it.
Signs an agent account up, waits for the checkout to be paid, claims the token and rotates it.
balance command
Prints the balance, the latest transcripts and the jobs still running.
Prints the balance, the latest transcripts and the jobs still running.
batch-folder command
Transcribes every recording in a folder, one after the other, and writes a text file for each.
Transcribes every recording in a folder, one after the other, and writes a text file for each.
buy command
Spends money: it needs a pack id and -yes before it charges the saved card.
Spends money: it needs a pack id and -yes before it charges the saved card.
export-srt command
Transcribes one recording and writes it as subtitles.
Transcribes one recording and writes it as subtitles.
transcribe command
Transcribes one recording and prints the transcript.
Transcribes one recording and prints the transcript.
Package generated provides primitives to interact with the openapi HTTP API.
Package generated provides primitives to interact with the openapi HTTP API.
internal
gen
Package gen holds the pure parts of the generator: it validates the API spec and the shared hints and emits the Go source of the error catalog, the operation scope map and the hints table.
Package gen holds the pure parts of the generator: it validates the API spec and the shared hints and emits the Go source of the error catalog, the operation scope map and the hints table.
goldens
Package goldens lists the golden files of the conformance suite (fixtures/exports) and says how each one is rendered.
Package goldens lists the golden files of the conformance suite (fixtures/exports) and says how each one is rendered.
probe
Package probe reads the duration of an audio or video file without decoding it.
Package probe reads the duration of an audio or video file without decoding it.
Command generate regenerates openapi.json and everything under generated/ from the API spec and the conformance repository's hints.json.
Command generate regenerates openapi.json and everything under generated/ from the API spec and the conformance repository's hints.json.
runexamples command
Command runexamples runs every program in examples/ against the conformance mock the container shares a network with.
Command runexamples runs every program in examples/ against the conformance mock the container shares a network with.
Command smoke is the nightly production check: it reads the account of the token in HUSHSCRIPT_TOKEN through the SDK.
Command smoke is the nightly production check: it reads the account of the token in HUSHSCRIPT_TOKEN through the SDK.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL