Trước đây, mở một tài khoản Hushscript luôn cần một con người, ít nhất một
lần. Giờ không còn như vậy nữa. Một luồng thanh toán trước cho phép một
agent tự mở tài khoản, nạp tiền và vận hành tài khoản đó, không có chủ tài
khoản là con người nào trong toàn bộ quy trình. /developers và /mcp mô
tả hai giao diện mà tài khoản này sau đó sử dụng; trang này là hướng dẫn
từng bước để có được một tài khoản như vậy.
Đăng ký
POST /v1/agent/accounts mở một lượt đăng ký không cần giao diện
(headless). Chưa có tài khoản nào, chưa có cookie, và chưa có token nào:
chỉ có một giao dịch mua đang chờ xử lý.
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 chỉ dùng để nhận biên lai và thông báo, không bao giờ dùng
để đăng nhập. pack_id là một trong các giá trị 45min, 300min,
900min, 1800min, 6000min; đừng bao giờ tự gửi amount hay
currency, cả hai đều được suy ra từ gói trên server. Chỉ hai gói nhỏ
nhất, 45min và 300min, mới có thể mua ngay khi đăng ký. Một pack_id
lớn hơn sẽ bị từ chối, và phản hồi từ chối đó mang theo
details.allowed_packs liệt kê những gì tài khoản này có thể mua ngay lúc
này, để bên gọi có thể thử lại mà không cần đoán. Phần còn lại của bậc
thang gói mở khóa theo thời gian, không theo khối lượng: xem Tài khoản
mới có thể mua gì bên dưới.
accept_terms_version phải khớp chính xác với phiên bản chính sách hiện
tại của server, nếu không lệnh gọi sẽ thất bại với policy_version_stale,
lỗi này nêu rõ giá trị hiện tại trong nội dung phản hồi. Gợi ý
data_region (tùy chọn) chỉ được chấp nhận khi nó khớp với khu vực mà vị
trí mạng của bạn đã ngụ ý sẵn. dry_run: true (tùy chọn) xác thực mọi thứ
mà không tạo phiên Stripe và không tính phí; signup_id của nó có tiền tố
dry_ và không bao giờ có thể được xác nhận.
claim_secret chỉ được hiển thị đúng một lần, trong phản hồi này.
Hushscript chỉ lưu trữ giá trị băm (hash) của nó. Làm mất nó trước khi gọi
lệnh xác nhận nghĩa là mất luôn lượt đăng ký đó: không có cách nào khôi
phục một claim secret, và khoản thanh toán đang giữ ký quỹ sẽ được hoàn
lại qua đợt quét được mô tả bên dưới, chứ không được trả lại qua một lượt
tra cứu.
Hoàn tất thanh toán trong trình duyệt của bạn
checkout_url là một trang Stripe Checkout được lưu trữ sẵn. Đây là bước
duy nhất trong toàn bộ luồng này cần đến trình duyệt, và trình duyệt đó
không cần phải là của một con người: một agent có thể tự điều khiển nó
bằng cơ chế tự động hóa của riêng mình (điền các trường thẻ, gửi đi, theo
dõi đường dẫn chuyển hướng). Dù theo cách nào, Hushscript cũng không bao
giờ thấy chi tiết thẻ; Stripe mới là bên thấy. Khoảng thời gian để hoàn
tất bước này rồi xác nhận là 30 phút, chính là expires_at ở trên.
Một lượt đăng ký đã được thanh toán nhưng chưa từng được xác nhận sẽ được hoàn tiền tự động bởi một đợt quét chạy mỗi giờ, khoảng một giờ sau khi cửa sổ 30 phút đó đóng lại. Khoản hoàn tiền là toàn bộ, vì số phút chỉ được ghi có vào số dư tại thời điểm xác nhận, nên một lượt đăng ký chưa được xác nhận chưa từng có phút nào để tiêu.
Xác nhận tài khoản
POST /v1/agent/accounts/{signup_id}/claim biến một lượt đăng ký đã
thanh toán nhưng chưa xác nhận thành một tài khoản thật sự, chỉ trong một
lệnh gọi.
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
}
Việc xác nhận chỉ dùng được một lần. Nó tạo ra đúng một tài khoản, với một
danh tính đăng nhập tổng hợp, không thể tra ngược đứng sau, cấp đúng một
lần gói đã thanh toán dù lệnh gọi có bị thử lại, và tạo ra đúng một PAT:
giá trị pat ở trên, cũng chỉ được hiển thị đúng một lần.
Một secret sai, một signup_id không tồn tại, một lượt đăng ký đã được
xác nhận rồi, một lượt đã được hoàn tiền, và một lượt đã hết hạn đều trả
về cùng một lỗi agent_claim_invalid. Bên gọi không có cách nào phân biệt
các trường hợp đó từ phản hồi, đây là chủ ý. Chỉ khi bản thân secret là
đúng thì trạng thái thanh toán mới được xét đến: một Checkout Session
chưa hoàn tất sẽ trả về wrong_state thay vào đó.
balance_seconds ở trên là toàn bộ số dư khởi điểm. Tài khoản agent không
nhận được khoản thưởng chào mừng nào và không có phút miễn phí nào từ
việc xác minh thẻ như tài khoản đầu tiên của một con người; chúng chỉ bắt
đầu với đúng gói đã thanh toán, không hơn. Đây là chủ ý, không phải một
khoảng thiếu sót: tài khoản đã được thanh toán trước khi nó tồn tại.
Mua thêm phút
Từ đây trở đi, tài khoản này hoạt động như bất kỳ tài khoản nào khác,
trên cùng bề mặt /v1/ mà /developers ghi lại đầy đủ.
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
}
Việc này cần scope billing, thứ mà phản hồi xác nhận ở trên đã cấp sẵn,
và nó dùng chung giới hạn chặt hơn, 60 yêu cầu mỗi phút cho mỗi tài khoản,
với route lưu thẻ, trước cả lệnh gọi Stripe mà một trong hai route đó
thực hiện.
Tài khoản mới có thể mua gì
Kích thước gói mở khóa theo tuổi của các khoản thanh toán đã hoàn tất, không theo số tiền tài khoản đã chi. Một giao dịch mua chỉ được tính vào bậc tiếp theo khi nó đã qua 7 ngày kể từ ngày thanh toán của chính nó, vì vậy một tài khoản hoàn toàn mới không thể chạm tới các gói lớn bằng cách mua thật nhanh.
| Các khoản thanh toán đã hoàn tất quá 7 ngày | Các gói có thể mua |
|---|---|
| Chưa có gì, kể cả một lượt xác nhận vừa mới | 45min, 300min |
| Ít nhất tương đương 45 phút | thêm 900min, 1800min |
| Ít nhất tương đương 15 giờ | thêm 6000min |
Một giao dịch mua bị từ chối sẽ nêu rõ tập hợp hiện tại trong
details.allowed_packs thay vì thất bại một cách mù mờ. Lệnh gọi đăng ký
áp dụng đúng hàng đầu tiên của bảng đó, đó là lý do vì sao hướng dẫn ở
trên mua 300min chứ không phải một gói lớn hơn. Tách biệt với bậc thang
này, một giới hạn tiêu hao cuộn 24 giờ giới hạn tốc độ tiêu số dư chưa
qua khỏi cửa sổ tranh chấp.
Phiên âm
Tải lên và phiên âm dùng cùng luồng nhiều phần (multipart) như bất kỳ tài khoản nào khác.
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 từng phần lên URL đã ký sẵn (presigned) của nó, sau đó POST tới
/complete của cùng job đó kèm n và etag của mỗi phần đã gửi theo
cách đó. Sau đó, poll job này:
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": "..."
}
Xoay vòng token
Một tài khoản máy không có mật khẩu và không có hộp thư nào dùng được, nên không có đường dẫn kiểu “quên mật khẩu” nếu một PAT bị lộ hoặc chỉ đơn giản là cần thay thế. Xoay vòng chính là đường dẫn đó.
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
}
Lệnh gọi này không cần nội dung (body). Nó tạo ra token kế nhiệm và thu hồi token đã xác thực yêu cầu này một cách nguyên tử, nên PAT cũ sẽ thất bại ngay ở lệnh gọi tiếp theo dùng nó. Token kế nhiệm giữ nguyên scope, quyền thanh toán, tên, nhãn client và chính sách hết hạn của token trước đó. Route này chỉ chạm vào token của chính bên gọi: nó không thể liệt kê, tạo, hay thu hồi bất kỳ thông tin xác thực nào khác trên tài khoản. Đây là đường dẫn khôi phục thông tin xác thực duy nhất mà một tài khoản máy có, vì vậy hãy xoay vòng trước khi token cũ bị loại bỏ, không phải sau đó.
Lỗi
| Trạng thái | Mã | Slug | Ý nghĩa |
|---|---|---|---|
| 401 | 2000 | unauthorized |
Thiếu hoặc sai bearer token |
| 403 | 2023 | pat_scope_missing |
Token thiếu scope mà lệnh gọi này cần, hoặc thanh toán đang tắt trên tài khoản |
| 403 | 4021 | pat_purchase_requires_app |
Không có thẻ đã lưu nào được chỉ định, hoặc giao dịch bị từ chối; không có gì bị tính phí |
| 403 | 4023 | pat_purchase_requires_authentication |
Ngân hàng phát hành thẻ yêu cầu một bước xác thực mà bên gọi không thể hoàn tất; bản thân thẻ vẫn ổn |
| 402 | 3001 | insufficient_balance |
Không đủ số dư để nhận job |
| 429 | 5000 | rate_limited |
Quá nhiều yêu cầu; chờ theo Retry-After |
Bốn lỗi sau đây là riêng của tài khoản agent và không bao giờ xảy ra với tài khoản của con người:
| Trạng thái | Mã | Slug | Ý nghĩa |
|---|---|---|---|
| 409 | 4035 | agent_signup_pending |
Một lượt đăng ký cho contact_email này vẫn đang mở. Hãy chờ nó được xác nhận, hoàn tiền hoặc hết hạn, hoặc dùng một địa chỉ khác |
| 401 | 4036 | agent_claim_invalid |
Secret sai, lượt đăng ký không tồn tại, đã được xác nhận, đã hoàn tiền, hoặc đã hết hạn. Giống hệt nhau là có chủ ý |
| 403 | 4037 | agent_pack_locked |
Bậc của tài khoản này chưa cho phép gói đó. Mang theo details.allowed_packs; thử lại với một trong các gói đó |
| 429 | 4038 | agent_purchase_capped |
3 giao dịch mua, dù thành công hay bị từ chối, trong 24 giờ gần nhất. Được đếm theo tài khoản trên mọi thông tin xác thực mà nó từng có, nên xoay vòng không reset con số này. Mang theo details.retry_after_seconds |
Một khi bản thân claim secret là đúng, một Checkout Session chưa thanh
toán sẽ trả về wrong_state (4001) thay vì agent_claim_invalid. Danh
mục đầy đủ nằm trong tài liệu OpenAPI.
Giới hạn
Các lệnh gọi bị giới hạn ở 1.200 lệnh mỗi phút. Đối với tài khoản agent, hạn mức đó thuộc về tài khoản, không thuộc về từng token riêng lẻ: mọi thông tin xác thực trong chuỗi xoay vòng đều dùng chung một hạn mức, nên xoay vòng một PAT không cấp cho token kế nhiệm một hạn mức mới. Hai lệnh ghi liên quan đến thanh toán, lưu thẻ và mua gói, dùng chung giới hạn chặt hơn, 60 lệnh mỗi phút cho mỗi tài khoản, trước cả lệnh gọi Stripe mà một trong hai lệnh đó thực hiện. Giới hạn mua 24 giờ ở trên cũng được đếm theo cách tương tự, theo tài khoản chứ không theo từng thông tin xác thực.
Tìm hiểu thêm
Trang này trình bày vòng đời của tài khoản: mở một tài khoản, nạp tiền cho nó, và giữ cho thông tin xác thực của nó luôn còn hiệu lực. Để biết mọi việc tài khoản đó có thể làm tiếp theo, xem REST API, bao gồm toàn bộ tài liệu OpenAPI, hoặc máy chủ MCP cho cùng tài khoản đó qua các công cụ thay vì HTTP thô.