Authentication
The V3 API uses OAuth2 bearer tokens. Every authenticated request sends:
Authorization: Bearer <accessToken>Tokens are minted by the SMS-PIN flow: the user proves they own a phone number, and the server issues a token tied to their account. No grant-type, client-id, or client-secret handling on the client side — the auth server takes care of all of that.
The flow
Section titled “The flow”POST /v3/auth/email-check
Section titled “POST /v3/auth/email-check”Submit the user’s email + a reCAPTCHA v3 token. The server:
- Looks up the user.
- If found: sends an SMS PIN to the phone on file. Responds with
{ exists: true }. - If not found: responds with
{ exists: false }so your UI can switch to the registration path.
{ "email": "alice@example.com", "captchaToken": "03AGdBq25..."}POST /v3/auth/register (new users only)
Section titled “POST /v3/auth/register (new users only)”For users who don’t exist yet, submit profile fields and a phone number. The server creates the account and sends the SMS PIN.
{ "firstname": "Alice", "lastname": "Smith", "email": "alice@example.com", "mobile": "3035551212", "countryCode": "US", "captchaToken": "03AGdBq25..."}POST /v3/auth/verify-pin
Section titled “POST /v3/auth/verify-pin”Submit the email + the PIN the user read from SMS. On success the response contains the bearer token.
{ "accessToken": "ad5e3f...", "refreshToken": "...", "expiresIn": 2592000}expiresIn is in seconds. Tokens live for 30 days.
Captcha gate
Section titled “Captcha gate”/v3/auth/email-check and /v3/auth/register expect a reCAPTCHA v3 token.
We’ve been the target of bot-driven SMS-cost attacks; the captcha is the
front line.
You don’t need to pay for a separate site key — request one from engineering@handbid.com and we’ll issue a Handbid-scoped key.
What if the captcha fails?
Section titled “What if the captcha fails?”Requests that arrive without a captcha token (or with an invalid one) fall back to a stricter rate limit — 10 requests per 5 minutes per IP per endpoint. This is the defense against bots that script the SMS-PIN flow at scale.
If you’re hitting that throttle in legitimate traffic, you’re probably missing the captcha token. Double-check the request body.
Storing the token
Section titled “Storing the token”The bearer token is sensitive. Treat it like a password.
- Mobile clients: iOS Keychain, Android EncryptedSharedPreferences, whatever your platform’s secure-storage primitive is.
- Web clients: httpOnly cookie scoped to your domain. Not localStorage.
- Server-to-server integrations: a secrets manager (1Password, Vault,
AWS Secrets Manager). Not a
.envfile checked into git.
If a token leaks, the only recourse is to mint a new one via the SMS flow. Revocation is on the roadmap; today, the practical mitigation is “make expiration short and rotate often.” 30 days is the current default but you can request a shorter window per-integration if your security posture requires it.
Refresh
Section titled “Refresh”The refreshToken returned alongside the access token can be exchanged for
a new access token without re-prompting the user for an SMS PIN. The endpoint
is /auth/refresh-token on the V1 surface — V3 hasn’t reimagined this yet.
If you need the V1 refresh contract, ping us.
Anonymous access
Section titled “Anonymous access”A small subset of V3 endpoints accept optional authentication —
mostly public discovery (/v3/auctions, /v3/auctions/{id}, /v3/item/{id}).
Anonymous callers get the same response shape minus user-scoped fields like
isFavorite.
Whether a request was anonymous or authenticated affects rate limits — see Rate limiting for the keying logic.
401 responses
Section titled “401 responses”A missing, expired, or malformed token returns:
{ "error": "unauthorized", "message": "Your request was made with invalid credentials."}If you see a 401 on what you expected to be a fresh token, the most common causes are:
- Token expired — check
expiresInand refresh proactively. - Token minted for the wrong OAuth client ID. V3 requires
ios,android,web,ogac,vt,connectNGo, orzap. - Bearer prefix missing or malformed (
Authorization: <token>instead ofAuthorization: Bearer <token>).
Reference
Section titled “Reference”POST /v3/auth/email-checkPOST /v3/auth/registerPOST /v3/auth/verify-pin
Each route’s exact request and response shape is documented in the API Reference.