API Reference Overview
Base URL: https://api.hasapay.com/api/v1
Authentication tiers
| Tier | Header(s) | Used for |
|---|---|---|
| JWT | Authorization: Bearer <token> |
User/org/team management, API key CRUD, settings |
| HMAC | X-API-Key, X-Signature, X-Timestamp, X-Request-ID |
Sensitive financial writes (wallet create, sends, address writes) |
| Dual-auth | Either JWT or HMAC | Every read endpoint + most config writes |
Full details in Authentication.
Response shapes
Success
Single resource:
{ "data": { /* resource */ } }
Lists:
{
"data": [ /* resources */ ],
"meta": { "limit": 50, "offset": 0, "count": 132 }
}
Pagination uses
limit+offset. There is nopage/total_pagesstyle.
Some endpoints (notably the create-style write routes) also include a message and the resource at the top level rather than under data — those are documented per-route.
Error
Standard error envelope:
{
"error": {
"code": "validation_error",
"message": "Invalid request data",
"details": "..."
}
}
Some routes return a flat { "error": "..." } (the simpler Gin form). Both are valid — check the error key first, treat it as the failure signal.
HTTP status codes
| Code | Meaning |
|---|---|
200 |
Success |
201 |
Created |
400 |
Bad request — body validation, invalid IDs |
401 |
Unauthorized — missing/invalid auth |
403 |
Forbidden — caller lacks permission, org suspended (ORG_SUSPENDED), wrong-mode network (MODE_MISMATCH), or live not yet approved (LIVE_MODE_LOCKED) |
404 |
Not found |
409 |
Conflict — e.g. duplicate_request on HMAC replay |
422 |
Unprocessable — domain validation failed |
429 |
Rate limited |
500 |
Server error |
Rate limits
Rate limits apply per organization. Headers included on every response:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1713260460
Limits scale with plan. Exceeding them returns 429.
Supported chains
| Chain | Test network | Live network |
|---|---|---|
| Ethereum | Sepolia | Mainnet |
| Polygon | Amoy | Mainnet |
| Solana | Devnet | Mainnet |
| Tron | Shasta | Mainnet |
| Bitcoin | Testnet | Mainnet |
Solana sweeps use the protocol-native fee-payer sponsored flow — child addresses never need to hold SOL. Tron uses fund-and-sweep for TRC-20s (master sends TRX to child, child broadcasts the token transfer). Bitcoin is native UTXO (SegWit bc1… / tb1…).
Test vs Live mode
Every request runs in Test mode (testnet) or Live mode (mainnet), and the two never share data. For API keys, mode is fixed by the key's environment — sandbox keys (tk_…) are test, production keys (pk_…) are live. For dashboard/JWT sessions, send X-HasaPay-Mode: test|live (default test). Live mode requires an approved + KYC-verified organization.
Full details in Live & Test Mode.
Endpoint sections
🔐 Auth
User registration, login, multi-org selection, password reset, invite handling. Public + JWT-protected.
| Method | Path | Auth |
|---|---|---|
| POST | /auth/register |
Public |
| POST | /auth/verify-email |
Public |
| POST | /auth/resend-code |
Public |
| POST | /auth/login |
Public |
| POST | /auth/select-org |
Public |
| POST | /auth/forgot-password |
Public |
| GET | /auth/reset-password/:token |
Public |
| POST | /auth/reset-password/:token |
Public |
| GET | /auth/invite/:token |
Public |
| POST | /auth/invite/:token/accept |
Public |
| POST | /auth/switch-org |
JWT |
| GET | /auth/my-organizations |
JWT |
| POST | /auth/invite/:token/accept-existing |
JWT |
| POST | /auth/invite/:token/decline |
JWT |
| GET | /auth/pending-invites |
JWT |
| PUT | /auth/change-password |
JWT |
→ See Auth flow
👛 Wallets
| Method | Path | Auth |
|---|---|---|
| POST | /wallets |
HMAC |
| GET | /wallets |
Dual |
| GET | /wallets/:walletId |
Dual |
| GET | /wallets/:walletId/balance |
Dual |
| GET | /wallets/:walletId/balances |
Dual |
| GET | /wallets/:walletId/fee-wallet |
Dual |
| POST | /wallets/:walletId/fee-wallet |
Dual |
→ See Wallets
🔐 Co-Custody
| Method | Path | Auth |
|---|---|---|
| POST | /wallets/:walletId/enable-cocustody |
JWT (owner/admin + MFA) or HMAC (cocustody:manage) |
| POST | /wallets/:walletId/fragments |
JWT (owner/admin + MFA) or HMAC (cocustody:manage) |
| POST | /wallets/:walletId/recover |
JWT (owner/admin + MFA) or HMAC (cocustody:recover) |
→ See Co-Custody
📍 Addresses
| Method | Path | Auth |
|---|---|---|
| POST | /wallets/:walletId/address (singular!) |
HMAC |
| GET | /wallets/:walletId/addresses |
Dual |
| GET | /wallets/:walletId/addresses/:addressId |
Dual |
| PUT | /wallets/:walletId/addresses/:addressId |
HMAC |
| PUT | /wallets/:walletId/addresses/:addressId/auto-sweep |
HMAC |
| GET | /addresses |
Dual |
→ See Addresses
💸 Transactions
| Method | Path | Auth |
|---|---|---|
| GET | /transactions |
Dual |
| GET | /transactions/:id |
Dual |
| GET | /transactions/:id/status |
Dual |
| GET | /transactions/hash/:hash |
Dual |
| POST | /wallets/:walletId/send |
HMAC |
| POST | /wallets/:walletId/addresses/:addressId/send |
HMAC |
| POST | /wallets/:walletId/addresses/:addressId/estimate-gas |
HMAC |
| POST | /payouts |
JWT (dashboard, approval-gated) |
| GET | /payouts |
JWT |
→ See Transactions
🪙 Assets
| Method | Path | Auth |
|---|---|---|
| GET | /assets/supported |
Dual |
| GET | /assets |
Dual |
| POST | /assets/enable |
Dual |
| DELETE | /assets/:asset_id |
Dual |
→ See Assets
🔔 Webhooks
| Method | Path | Auth |
|---|---|---|
| GET | /webhooks/events |
Dual |
| POST | /webhooks |
Dual |
| GET | /webhooks |
Dual |
| GET | /webhooks/:id |
Dual |
| PUT | /webhooks/:id |
Dual |
| DELETE | /webhooks/:id |
Dual |
| POST | /webhooks/:id/secret/regenerate |
Dual |
| POST | /webhooks/:id/test |
Dual |
| GET | /webhooks/:id/deliveries |
Dual |
| GET | /webhooks/:id/deliveries/:deliveryId |
Dual |
| POST | /webhooks/:id/deliveries/:deliveryId/retry |
Dual |
| GET | /deliveries |
Dual |
→ See Webhooks
🔑 API Keys
| Method | Path | Auth |
|---|---|---|
| GET | /api-keys |
JWT |
| POST | /api-keys |
JWT |
| GET | /api-keys/:id |
JWT |
| PUT | /api-keys/:id |
JWT |
| DELETE | /api-keys/:id |
JWT |
→ See API Keys
👥 Team
| Method | Path | Auth |
|---|---|---|
| GET | /team/me |
JWT |
| PUT | /team/me |
JWT |
| GET | /team/members |
JWT |
| GET | /team/invites |
JWT |
| POST | /team/invite |
JWT |
| POST | /team/invites/:id/resend |
JWT |
| DELETE | /team/invites/:id |
JWT |
| PUT | /team/members/:id/role |
JWT |
| POST | /team/members/:id/deactivate |
JWT |
| POST | /team/members/:id/reactivate |
JWT |
| DELETE | /team/members/:id |
JWT |
| POST | /team/leave |
JWT |
→ See Team
⚙️ Settings
| Method | Path | Auth |
|---|---|---|
| GET | /settings/organization |
JWT |
| PUT | /settings/organization |
JWT |
→ See Settings
📊 Stats
| Method | Path | Auth |
|---|---|---|
| GET | /stats |
Dual |
| GET | /stats/volume |
Dual |
| GET | /stats/chains |
Dual |
→ See Stats
💰 Fees
| Method | Path | Auth |
|---|---|---|
| GET | /fees/config |
Dual |
| GET | /fees/addresses |
Dual |
| GET | /fees/addresses/:addressId |
Dual |
| PUT | /fees/addresses/:addressId |
Dual |
| DELETE | /fees/addresses/:addressId |
Dual |
| GET | /fees/estimate |
Dual |
| GET | /fees/deposit/estimate |
Dual |
| GET | /fees/summary |
Dual |
| GET | /fees/history |
Dual |
| GET | /fees/sources |
Dual |
| GET | /fees/sources/:source_id |
Dual |
| GET | /fees/transactions/:id |
Dual |
| GET | /fees/gas |
Dual |
→ See Fees
🧹 Sweep
| Method | Path | Auth |
|---|---|---|
| GET | /sweep/config |
Dual |
| PUT | /sweep/config |
Dual |
| GET | /sweep/config/:chain/:network |
Dual |
| PUT | /sweep/config/:chain/:network |
Dual |
| DELETE | /sweep/config/:chain/:network |
Dual |
| GET | /sweep/addresses |
Dual |
| PUT | /sweep/addresses/:addressId |
Dual |
| POST | /sweep/addresses/:addressId/trigger |
Dual |
| GET | /sweep/history |
Dual |
→ See Sweep
Postman collection
The most up-to-date endpoint reference outside this doc lives in the HasaPay repo: docs/postman/orgapi.json. Import that into Postman to test the org-facing API end-to-end.
Need help?
- Authentication — signing requests, dual-auth, JWT, HMAC, replay protection
- Quickstart — wallet → address → deposit in 5 minutes
- support@hasapay.com