आधिकारिक SDKs server code और scripts के लिए REST API को लपेटते हैं। एक call से file transcribe होती है: वह recording upload करती है, job पूरा होने तक इंतज़ार करती है और transcript लौटा देती है। बीच में SDK मिनट hold होने से पहले file जांचता है, जिन्हें दोबारा भेजना सुरक्षित है उन्हें retry करता है, लंबे upload को चालू रखता है, और हर upload और purchase के साथ idempotency key भेजता है, ताकि retry से दोबारा charge न लगे। CLI, TypeScript SDK पर बना है और terminal से वही काम करता है।
पैकेज
| भाषा | पैकेज | Registry | स्रोत |
|---|---|---|---|
| TypeScript | @hushscript/sdk | npm: www.npmjs.com/package/@hushscript/sdk | github.com/Hushscript/hushscript-sdk-typescript |
| Python | hushscript | PyPI: pypi.org/project/hushscript | github.com/Hushscript/hushscript-sdk-python |
| Go | github.com/Hushscript/hushscript-sdk-go | pkg.go.dev: pkg.go.dev/github.com/Hushscript/hushscript-sdk-go | github.com/Hushscript/hushscript-sdk-go |
| PHP | hushscript/sdk | Packagist: packagist.org/packages/hushscript/sdk | github.com/Hushscript/hushscript-sdk-php |
| CLI | @hushscript/cli | npm: www.npmjs.com/package/@hushscript/cli | github.com/Hushscript/hushscript-cli |
Runtime की न्यूनतम आवश्यकताएं:
- TypeScript: Node 22 या नया। Bun 1.2+ और Deno 2+ की जांच सिर्फ़ package import करने के लिए होती है, उनके HTTP व्यवहार की नहीं।
- Python: 3.10 या नया।
- Go: 1.25 या नया।
- PHP: 8.2 या नया,
ext-jsonऔरext-mbstringके साथ; parts को एक साथ upload करने के लिएext-curl। - CLI: Node 22 या नया।
SDKs servers और scripts के लिए हैं। API browser origins स्वीकार नहीं करती, और browser bundle में रखा token लीक हुआ token है, इसलिए जहां window और document मौजूद हों वहां TypeScript SDK शुरू होने से मना कर देता है।
टोकन बनाएं
हर SDK और CLI personal access token से authenticate करता है। खाते के MCP page पर नया टोकन बनाएं से token बनाएं, अपने code के लिए ज़रूरी scopes चुनें और तय करें कि वह मिनट खरीद सकेगा या नहीं। Token सिर्फ़ एक बार दिखता है और hsr1:<region>:pat.<id>.<secret> जैसा होता है। Scopes और token कैसे काम करता है, यह API page पर है।
अगर आप token नहीं देते, तो SDKs उसे HUSHSCRIPT_TOKEN से पढ़ते हैं:
export HUSHSCRIPT_TOKEN=hsr1:...
एक agent अपना account खुद भी खोल सकता है, hosted checkout page पर भुगतान करा सकता है और code से अपना पहला token claim कर सकता है: TypeScript में Hushscript.agent.signup() और Hushscript.agent.claim(), Python में Hushscript.agent_signup() और Hushscript.agent_claim(), Go में AgentSignup और AgentClaim, और PHP में Client::agentSignup() और Client::agentClaim()। यह flow और इसके नियम Agents के लिए automatic transcription में हैं।
TypeScript
npm install @hushscript/sdk
import { writeFile } from "node:fs/promises";
import { Hushscript } from "@hushscript/sdk";
const hs = new Hushscript(); // reads HUSHSCRIPT_TOKEN
const transcript = await hs.transcribe("meeting.mp3");
console.log(transcript.text);
await writeFile("meeting.srt", transcript.toSRT());
transcribe() path, Blob, Uint8Array या ReadableStream<Uint8Array> लेता है। Stream के लिए उसका सटीक size और durationSeconds चाहिए। hs.balance() वे मिनट लौटाता है जो आप खर्च कर सकते हैं, hs.transcripts.list() पूरे हो चुके transcripts को pages में देता है, और hs.buy("300min", { acknowledgeNoRefund: true }) एक pack खरीदता है। हर /v1 operation hs.api के रूप में भी उपलब्ध है, उन्हीं retries, timeouts और redaction के साथ।
Python
pip install hushscript
from pathlib import Path
from hushscript import Hushscript
with Hushscript() as hs: # reads HUSHSCRIPT_TOKEN
transcript = hs.transcribe("meeting.mp3")
print(transcript.text)
Path("meeting.srt").write_text(transcript.to_srt(), encoding="utf-8")
हर call का AsyncHushscript पर उसी नाम से asyncio रूप है। transcribe() path, bytes या binary file object लेता है; जिस file object में seek नहीं हो सकता, उसके लिए size और duration_seconds चाहिए। hs.balance(), hs.transcripts.list() और hs.buy("300min", acknowledge_no_refund=True) क्रम से balance, transcript list और purchases संभालते हैं।
Go
go get github.com/Hushscript/hushscript-sdk-go
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)
}
}
Transcribe path लेता है, TranscribeReader एक io.ReaderAt और उसका सटीक size, और TranscribeStream सिर्फ़ आगे बढ़ने वाला reader, उसके size और DurationSeconds के साथ। client.Balance, client.Transcripts.List और client.Buy क्रम से balance, transcript list और purchases संभालते हैं। जो options off, on या unset हो सकते हैं, वे *bool हैं, जिन्हें hushscript.Bool से बनाया जाता है।
PHP
composer require hushscript/sdk
<?php
require __DIR__ . '/vendor/autoload.php';
use Hushscript\Client;
$hs = new Client(); // reads HUSHSCRIPT_TOKEN
$transcript = $hs->transcribe('meeting.mp3');
echo $transcript->text();
file_put_contents('meeting.srt', $transcript->toSrt());
transcribe() path या खुला stream लेता है; जिस stream में seek नहीं हो सकता, उसके लिए size और duration_seconds options चाहिए। Options में snake_case array keys इस्तेमाल होती हैं और results में camelCase properties। $hs->balance(), $hs->transcripts()->list() और $hs->buy('300min', true) क्रम से balance, transcript list और purchases संभालते हैं। Laravel में service provider में एक Client bind करें और transcriptions को queued job में, स्थिर idempotency_key option के साथ चलाएं।
CLI
npm install --global @hushscript/cli
hushscript login
hushscript transcribe meeting.mp3 --format srt --out meeting.srt
CLI token पहले --token से लेता है, फिर HUSHSCRIPT_TOKEN से, फिर उससे जो hushscript login ने सहेजा था। login token बिना echo किए मांगता है और उसे ऐसी file में रखता है जिसे सिर्फ़ आपका user पढ़ सकता है; hushscript logout उसे हटा देता है। CI में environment variable को प्राथमिकता दें।
| Command | यह क्या करता है |
|---|---|
login |
Token मांगकर उसे सहेजता है। |
logout |
सहेजा हुआ token हटाता है। |
balance |
आपके खर्च करने योग्य मिनट दिखाता है। |
transcribe <file> |
Recording upload करता है, इंतज़ार करता है और transcript print करता है। Flags: --language, --translate, --format srt|vtt|txt|json, --out, --key। |
resume <token> <file> |
उस transcription को पूरा करता है जिसे transcribe अधूरा छोड़ गया था। |
transcripts |
पूरे हो चुके transcripts को नए से पुराने क्रम में list करता है। |
transcript <id> |
एक transcript print करता है। |
jobs |
Jobs list करता है; जो पूरे नहीं हुए उनके लिए --active। |
packs |
खरीदे जा सकने वाले minute packs कीमतों के साथ list करता है। |
buy <pack> |
आपके सहेजे default card से एक pack खरीदता है। Flags: --yes, --key। |
--json stdout पर सिर्फ़ एक JSON document print करता है, और stderr को JSON Lines में बदल देता है। Exit code सफलता पर 0 होता है, API या SDK के error बताने पर 1, usage error पर 2 (कुछ भेजा नहीं गया), और run बीच में रोके जाने पर 130।
समर्थित files
MP3, M4A, MP4 और MOV (video का audio track इस्तेमाल होता है), WAV, FLAC, और Vorbis या Opus वाली OGG, 15 seconds से 10 घंटे तक। SDKs file के bytes से format जांचते हैं और मिनट hold होने से पहले duration probe करते हैं। वे media convert नहीं करते, इसलिए बाक़ी सब कुछ पहले convert करें:
ffmpeg -i input -vn -c:a libopus output.opus
Errors
SDK जो भी error उठाता है वह एक ही family का होता है, इसलिए एक catch सबको संभाल लेता है: TypeScript और Python में HushscriptError, Go में *hushscript.Error, और PHP में HushscriptException। Error में insufficient_balance जैसा slug code, numeric code, HTTP status, message, आगे क्या करना है यह बताने वाला hint, details और retryAfter (PHP में slug errorCode है; Python में retryAfter को retry_after लिखा जाता है) होते हैं।
import { HushscriptError, InsufficientBalanceError } from "@hushscript/sdk";
try {
await hs.transcribe("meeting.mp3");
} catch (error) {
if (error instanceof InsufficientBalanceError) console.log(error.hint);
else if (error instanceof HushscriptError) console.log(error.code, error.hint ?? error.message);
else throw error;
}
PreflightError का मतलब है कि SDK ने कोई credit hold होने से पहले ही file को अस्वीकार कर दिया। आपका balance किसी file के लिए काफ़ी है या नहीं, यह server तय करता है: upload बनते समय, कोई part भेजे जाने से पहले, 402 लौट आता है।
Charge और retries
हर upload और हर purchase के साथ idempotency key जाती है, और retries उसी key को दोबारा इस्तेमाल करते हैं, इसलिए retry की गई call पहली call को replay करती है, दूसरी शुरू नहीं करती।
buy() आपके सहेजे default card पर charge लगाता है। Code से खरीदना तब तक बंद रहता है जब तक तीन switches इसकी अनुमति न दें: token में billing scope हो, token पर “इस टोकन को मिनट खरीदने दें” चालू हो, और account के लिए “कनेक्टेड ऐप्स को मिनट खरीदने दें” चालू हो। इनमें से कोई भी न हो, तो call pat_scope_missing के साथ fail होती है। इसे call करने से पहले अपने खरीदार को no-refund नोटिस दिखाएं।
Purchase को ज़्यादा से ज़्यादा एक बार retry किया जाता है, network error, 502 या 503 पर, उसी key के साथ। कुछ जवाब साबित करते हैं कि कुछ भी charge नहीं हुआ: 400, 402, 404 या 422, और code 4021 (pat_purchase_requires_app, card declined हुआ या आपके बिना charge नहीं हो सकता) या 4023 (pat_purchase_requires_authentication, बैंक भुगतान की पुष्टि चाहता है) के साथ 403। 4021 या 4023 के बाद pack को app में खरीदें। Request भेजे जाने के बाद कोई भी दूसरी विफलता, 401 या 429 समेत, यह बताती है कि card पर charge लग चुका हो सकता है। वह error idempotency key साथ लाता है: उसी key के साथ दोबारा कोशिश करें, और purchase कभी दो बार नहीं हो सकती। Python में:
from hushscript import HushscriptError
try:
purchase = hs.buy("300min", acknowledge_no_refund=True)
except HushscriptError as error:
refused = error.status in {400, 402, 404, 422} or (
error.status == 403 and error.numeric_code in {4021, 4023}
)
if error.idempotency_key is None or refused:
raise # only these refusals charged nothing; any other failure keeps the key for a retry
purchase = hs.buy("300min", acknowledge_no_refund=True, idempotency_key=error.idempotency_key)
जो purchase अपनी request भेजे जाने से पहले fail हुई, उसमें कोई key नहीं होती: कुछ भी charge नहीं हुआ। आप खुद जो key दें वह 1 से 128 characters की होनी चाहिए, A-Za-z0-9_- में से; उसे किसी दूसरे pack के लिए दोबारा इस्तेमाल न करें। जब purchase भेजी जा चुकी हो सकती है, तब CLI key print करता है:
hushscript buy 300min --yes --key <key>
Resume tokens
Job बन जाने के बाद, error idempotency key के साथ एक resume token भी लाता है। इंतज़ार का समय खत्म होने पर token के साथ WaitTimeoutError उठता है, और job चलता रहता है। दूसरी बार charge लगे बिना आगे बढ़ने के लिए token को resume() में वापस दें: जो job uploading से आगे निकल चुका है उसे file नहीं चाहिए, और जो अभी upload हो रहा है वह उसी file से जारी रहता है। PHP में:
try {
$hs->transcribe($path, ['wait_timeout' => 60]);
} catch (\Hushscript\Exception\WaitTimeoutError $timeout) {
$transcript = $hs->resume($timeout->resumeToken, $path);
}
CLI में, transcribe के दौरान Ctrl-C job का resume token और उसे जारी रखने वाला command print करता है:
hushscript resume <token> meeting.mp3 --format srt --out meeting.srt
Logging और redaction
SDKs कोई telemetry नहीं भेजते; User-Agent header ही client की एकमात्र पहचान है। Logging default में बंद है। HUSHSCRIPT_LOG=debug हर request की एक line standard error पर लिखता है, जिसमें method, path, status और timing होती है, और कभी कोई header, body, title या transcript text नहीं।
Token हर error, log line और client के हर printed रूप से redact किया जाता है। Error messages, hints और causes में URL का host और path बना रहता है, लेकिन उसकी query string ?[redacted] हो जाती है, इसलिए signed upload URL कभी print नहीं होता। जो results आपको कोई secret देते हैं, जैसे claim secret या नया token, उसे field के रूप में पढ़ने योग्य रखते हैं लेकिन print होने पर [redacted] दिखाते हैं; JSON export आपका अपना है और उसमें असली मान रहता है। CLI अपने जाने हर token को stderr से हटा देता है; stdout पर उसके results आपका output हैं और scrub नहीं किए जाते।
Configuration
| Setting | Environment variable | Default |
|---|---|---|
| Token | HUSHSCRIPT_TOKEN |
none |
| Base URL | HUSHSCRIPT_BASE_URL |
https://api.hushscript.com |
| Log level | HUSHSCRIPT_LOG |
off |
| Request timeout | none | 60 seconds |
| Retries | none | 3 |
Code में दिया गया option अपने environment variable पर भारी पड़ता है, और खाली मान को unset माना जाता है। मिनट उसी balance से आते हैं जो app में है; packs और कीमतें कीमतें पेज पर हैं।