Overview¶
Note
AI Context
Complexity: Low to Medium (unregister/delegate carry authorization and lifecycle side effects)
Cost: Free. No auth endpoint incurs platform billing.
Async: No. All auth operations are synchronous, except that signup/password-forgot/unregister trigger emails sent out-of-band.
All endpoints in this group are served directly at /auth/<name> — not under the /v1.0 prefix used by every other resource in the API. A generated stub exists for each path under /v1.0/auth/... that always returns 404 ROUTE_NOT_FOUND with a message pointing at the correct un-prefixed path; this is intentional routing scaffolding, not a bug.
Endpoint Summary¶
Method |
Path |
Auth |
Purpose |
|---|---|---|---|
POST |
|
None |
Self-service customer registration. |
POST |
|
None |
Verify the signup email token; provisions the first access key. |
GET |
|
None |
Serves an HTML page that auto-submits the verification token (link target from the verification email). |
POST |
|
Username/password |
Exchange agent credentials for a 7-day JWT. See Authentication quickstart. |
POST |
|
None (direct hash) |
Exchange a direct hash for a 4-hour resource-scoped JWT. |
POST |
|
None |
Request a password reset email. |
GET |
|
None |
Serves the HTML password reset form (link target from the reset email). |
POST |
|
None (reset token) |
Complete the password reset using the emailed token. |
POST |
|
Token or Accesskey |
Freeze the caller’s own account and schedule (or immediately execute) deletion. |
DELETE |
|
Token or Accesskey |
Cancel a scheduled deletion and restore the account to |
POST |
|
Token (ProjectSuperAdmin) |
Issue a short-lived support/investigation token scoped to another customer. See Authentication quickstart. |
Note
AI Implementation Hint
All unauthenticated /auth/* endpoints (login, signup, email-verify, boot, password-forgot, password-reset) share a single IP-based rate limiter: up to approximately 10 requests/second per client IP, burst 20. /auth/unregister and /auth/delegate require authentication first, then are subject to their own, separately-tracked IP-based limiter at the same approximate rate (10 requests/second, burst 20). Exceeding either limiter returns 429 with reason RATE_LIMIT_EXCEEDED (see Error Reason Codes).
Note
AI Implementation Hint — response body shape differs by endpoint
/auth/unregister and /auth/delegate sit behind the shared Authenticate() middleware, so authentication/authorization failures at that layer (missing token, expired token, frozen account) return the standard structured error envelope described in Error Reason Codes ({"error": {"status", "reason", "message", "request_id", ...}}). However, validation failures raised inside the auth handlers themselves — e.g. a malformed JSON body on any endpoint, a wrong password on /auth/unregister, an invalid confirmation_phrase, a bad accepted_tos on signup — return a bare HTTP status code (400) with an empty response body, not the JSON error envelope. Do not assume error.reason is present on every 4xx from this group; check for an empty body first.
Auth & Account Lifecycle¶
signup email-verify (set password) login / boot
+----------+ +--------------+ +----------------+ +--------------+
| initial |-->| active |--->| active |--->| JWT / key |
+----------+ +--------------+ +----------------+ +--------------+
| |
| (no verification | POST /auth/unregister
| within timeout) v
v +----------------+
+----------+ | frozen |
| expired | | (30-day grace) |
+----------+ +----------------+
| |
DELETE /auth/unregister (grace expires,
| or immediate:true)
v v
+----------------+ +----------------+
| active | | deleted |
+----------------+ +----------------+
For the full customer status lifecycle (including what gets cascade-deleted), see Customer — Account Deletion Lifecycle.
Signup — POST /auth/signup¶
Creates an unverified customer account and triggers a verification email. See the Signup quickstart for a walkthrough.
Request body
Field |
Type |
Description |
|---|---|---|
|
String, Required |
Email address for the new account. Must be unique across all customers. |
|
Boolean, Required |
Must be |
|
String, Optional |
Display name for the customer account. |
|
String, Optional |
Additional description. |
|
String, Optional |
Contact phone number (E.164 format recommended). |
|
String, Optional |
Mailing address. |
|
String, Optional |
HTTP method for webhook delivery: |
|
String, Optional |
URI where webhook events will be delivered. |
Response — 200 OK (success)
{
"customer": { "id": "...", "email": "...", "status": "initial", ... },
"accesskey": { "id": "...", "token": "vb_...", "name": "...", ... }
}
Response — 200 OK (silent failure, e.g. duplicate email)
{}
Note
AI Implementation Hint
Signup always returns HTTP 200, even on failure, to prevent email-enumeration attacks — a duplicate or invalid email produces an empty {} body rather than an error. The only true 400 is a structurally invalid request (missing email, missing/false accepted_tos, or malformed JSON). The returned accesskey.token is usable immediately; no separate POST /auth/login call is required. Signup also auto-provisions an empty OutboundConfig (blocking all outbound PSTN calls until explicitly configured) and auto-rolls back the entire signup (deletes the customer) if that provisioning step permanently fails.
Errors
Status |
Cause |
|---|---|
400 |
|
Email Verify — POST / GET /auth/email-verify¶
Validates the verification token from the signup email, marks the customer’s email as verified, and transitions the account from initial to active.
POST request body
Field |
Type |
Description |
|---|---|---|
|
String, Required |
64-character lowercase hex verification token from the signup email. |
Response — 200 OK
{
"customer": { "id": "...", "email": "...", "email_verified": true, "status": "active", ... }
}
Errors
Status |
Cause |
|---|---|
400 |
|
GET /auth/email-verify
Serves a static HTML confirmation page (the link target embedded in the verification email). The page reads token from the query string and, when the visitor clicks “Verify Email”, submits it to POST /auth/email-verify via client-side JavaScript. This is a convenience UI for humans following the email link — API integrations should call POST /auth/email-verify directly with the token extracted from the email/webhook.
Parameter |
Location |
Description |
|---|---|---|
|
Query, Required |
64-character lowercase hex string. An invalid/missing token returns |
Login (Token) — POST /auth/login¶
Exchanges an agent’s username/password for a JWT valid for 7 days. Fully documented with request/response examples in the Authentication quickstart; summarized here for completeness.
Field |
Type |
Description |
|---|---|---|
|
String, Required |
The agent’s username. |
|
String, Required |
The agent’s password. |
Response: {"username": "...", "token": "eyJ..."}. The token is also set as an HttpOnly, Secure, SameSite=Strict cookie named token on the response. Errors: 400 on missing fields, malformed JSON, or invalid credentials (login failures are not distinguished from bad requests — both return a bare 400).
Boot (Direct Token) — POST /auth/boot¶
Resolves a direct hash into a short-lived, resource-scoped JWT, for use cases where the end user has no VoIPBin account (e.g. an embedded AI voice widget on a customer’s public website). Also documented in the Authentication quickstart.
Request body
Field |
Type |
Description |
|---|---|---|
|
String, Required |
The direct hash link, e.g. |
Response — 200 OK
Field |
Type |
Description |
|---|---|---|
|
String |
JWT for API/WebSocket use. Pass as |
|
String |
Always |
|
String |
The resource type this token is scoped to (e.g. |
|
UUID |
The scoped resource’s ID. |
|
UUID |
The owning customer’s ID. |
|
String (ISO 8601) |
Token expiry. Valid for 4 hours from issuance. |
|
Object, Optional |
Present only for resource types with a registered public-display fetcher (currently |
Errors
Status |
Cause |
|---|---|
400 |
|
Note
AI Implementation Hint
Boot tokens are scoped: they only grant access to the resource types listed in the token (e.g. aicall for an ai/ai_team direct hash, webchat_session for a webchat_widget direct hash). For WebSocket subscriptions, boot tokens may only subscribe to 4-part topics (customer_id:<uuid>:<resource_type>:<resource_id>); broader topics are rejected.
Password Forgot — POST /auth/password-forgot¶
Generates a password reset token and emails a reset link to the agent, valid for 1 hour.
Request body
Field |
Type |
Description |
|---|---|---|
|
String, Required |
The agent’s username (email address). |
Response — 200 OK: always {}, regardless of whether the username exists, to prevent username-enumeration attacks. The underlying call to bin-agent-manager is made best-effort; a lookup failure is logged but never surfaced to the caller.
Errors
Status |
Cause |
|---|---|
400 |
|
Password Reset — GET / POST /auth/password-reset¶
Completes a password reset using the token emailed by POST /auth/password-forgot.
GET /auth/password-reset — serves the HTML reset form (the link target in the reset email).
Parameter |
Location |
Description |
|---|---|---|
|
Query, Required |
64-character lowercase hex string. An invalid/missing token returns |
POST /auth/password-reset — request body
Field |
Type |
Description |
|---|---|---|
|
String, Required |
64-character lowercase hex reset token from the email. Single-use, expires 1 hour after issuance. |
|
String, Required |
New password. Minimum 8 characters. |
Response — 200 OK: {}.
Errors
Status |
Cause |
|---|---|
400 |
|
Unregister (Self-Service Deletion) — POST / DELETE /auth/unregister¶
Self-service account freeze/deletion and recovery. Requires authentication (Token or Accesskey) and PermissionCustomerAdmin on the caller’s own customer account; direct (boot) tokens cannot call this endpoint. A condensed narrative version of this section, including the full status-lifecycle diagram and the cascade-delete resource list, lives in Customer — Account Deletion Lifecycle; this section is the field-level contract.
POST /auth/unregister — request body
Field |
Type |
Description |
|---|---|---|
|
String, Conditional |
Re-authentication password for password-based accounts. Mutually exclusive with |
|
String, Conditional |
Must be exactly |
|
Boolean, Optional |
Default |
Query parameters (both POST and DELETE)
Parameter |
Location |
Description |
|---|---|---|
|
Query, Optional |
Access-key token, as an alternative to a |
Response — 200 OK: the updated Customer object (see Customer), reflecting status: "frozen" (or "deleted" if immediate was true).
Errors
Status |
Cause |
|---|---|
400 |
Neither or both of |
401 |
Missing/invalid/expired token or access key (returned by the shared |
DELETE /auth/unregister — cancels a scheduled deletion and restores active status. No request body. Only works while the account is frozen within the 30-day grace period.
Response — 200 OK: the restored Customer object.
Errors
Status |
Cause |
|---|---|
400 |
Account is not currently in |
401 |
Missing/invalid/expired token or access key. |
Note
AI Implementation Hint — frozen accounts are also enforced globally
Once a customer account is frozen, every other authenticated /v1.0/* request from that customer (except from a PermissionProjectSuperAdmin, and except direct/boot tokens, which skip the check entirely) is rejected with 403 ACCOUNT_FROZEN by the shared authentication middleware — not just calls to resource endpoints that would otherwise mutate data. The error’s details[0] carries deletion_scheduled_at, deletion_effective_at (30 days after scheduling), and recovery_endpoint: "DELETE /auth/unregister" so client UIs (admin/talk consoles) can render a consistent “account frozen, recover here” screen. POST and DELETE /auth/unregister themselves are explicitly exempted from this block so a frozen customer can still self-recover.
Delegate (Superadmin Support Access) — POST /auth/delegate¶
Lets a platform superadmin (PermissionProjectSuperAdmin) issue a short-lived, audit-logged token that grants PermissionCustomerAdmin-equivalent access scoped to a specific target customer, for support/investigation without needing that customer’s own credentials. Fully documented with request/response examples in the Authentication quickstart; summarized here for completeness.
Request body
Field |
Type |
Description |
|---|---|---|
|
String (UUID), Required |
Target customer to act on behalf of. |
|
String, Required |
Justification, written to the audit log. Must be 10-200 printable-ASCII characters (0x20-0x7E), no control characters. |
Response — 200 OK
{
"token": "eyJ...",
"customer_id": "...",
"expire": "2026-05-19T06:00:00.000000Z"
}
The delegate token is valid for 8 hours and grants customer-admin-equivalent access scoped only to customer_id — no project-level permissions are carried over.
Errors
Status |
Cause |
|---|---|
400 |
Malformed or missing request body. |
401 |
Caller is not authenticated. |
403 |
Caller lacks |
404 |
Target customer does not exist or is already |
422 |
|
Note
AI Implementation Hint
Every delegate token issuance (and denial) is written to the audit log with audit=true, the issuer’s agent ID, target customer, reason, and expiry — this is the audit trail for superadmin account access. Do not build tooling that calls this endpoint without a genuine, specific support reason; the reason field is not free-form filler, it is the compliance record.