Security and Reliability Best Practices
Bitnob is designed to be programmable financial infrastructure. With stablecoins, you’re interacting with real money over public blockchains—so security, permission management, and reliability must be treated as core parts of your integration. This section outlines how to build a production-grade, fault-tolerant setup.
API Key Management
All access to Bitnob’s APIs is authenticated using HMAC signatures generated with your secret keys. These keys are powerful and must be handled with care — a ready-made signing function is available in the API reference.
Best Practices:
Use separate keys for production, staging, and development
Rotate keys regularly via the Bitnob Dashboard
Never expose keys in frontend code, GitHub, or client apps
Keys are tied to a company account. You can generate and manage them in the API section of your dashboard, and confirm a new key works with Validate Authentication.
Role-Based Scopes
A scope is a named permission attached to an API key that decides which endpoints the key may call. A key missing a scope still authenticates — it simply cannot reach the endpoints behind that scope, so a compromised read-only key cannot be used to move funds.
Scopes are named resource:action: the part before the colon is what is being acted on (wallet, transfer, webhook) and the part after it is how much power you are granting (read looks, write creates, create moves value). Each one maps directly to endpoints — wallet:read covers Get Balances, wallet:write covers Generate Addresses, and transfer:create covers Create Withdrawal:
scope | capability | blast radius if leaked |
|---|---|---|
wallet:read | View wallet balances and metadata | Low — cannot create anything or move funds. The right scope for reporting, reconciliation and internal dashboards. |
wallet:write | Create deposit addresses | Medium — creates places to receive funds, but cannot send any. Needed by whatever service onboards users. |
transfer:create | Send stablecoins to addresses | High — this is the only scope that moves money. Grant it to the single service that initiates payouts, and nothing else. |
webhook:read | View configured webhooks | Low — read-only view of your webhook configuration. Note that receiving webhooks needs no scope at all; Bitnob calls you. |
Apply least privilege: only give keys the permissions required for a specific service or microservice. To confirm what a key actually carries, call Validate Authentication and inspect data.permissions — an unscoped key returns null there, meaning full account-level access. Treat that as a development-only setting.
Webhook Security
Bitnob signs all webhook requests using a shared secret with HMAC SHA-256. The reference implementation lives under Verifying Events.
To verify a webhook:
Get the X-Bitnob-Signature header from the request
Hash the raw request body using your webhook secret
Compare the result with the header value (use constant-time comparison)
Why it matters: Prevents spoofed or replayed webhook attacks.
If your infrastructure also restricts inbound traffic by IP, allowlist the addresses published under Source IPs. Treat the allowlist as a second layer only — signature verification remains the authoritative check.
Transfer Integrity and Idempotency
Always use a unique reference per outbound transfer — see the withdrawal request fields
Never initiate a second transfer until you’ve confirmed failure or completion of the first — the withdrawal status lifecycle defines which states are final
Listen for transfer.failed and transfer.success events for final state
Use internal locking if your app supports concurrent withdrawals
Access Control Recommendations
Enforce 2FA on all admin dashboards
Segment sensitive operations (like transfer:create) into separate services
Log all internal actions on your infrastructure: who initiated a transfer, who changed keys, etc.
If you operate a multi-tenant platform, make sure tenants cannot trigger transfers outside their scope
Reliability Patterns
failure | pattern |
|---|---|
API downtime | Queue and retry writes with backoff |
Webhook outage | Allow replays or trigger from dashboard |
Chain congestion | Alert on delayed confirmation, auto-prioritize fees |
Transfer failure | Automatically trigger re-attempt logic only after validation |
Monitoring and Alerting
We recommend tracking the following for observability:
Transfer success and failure rates, per chain
Webhook delivery latencies and error rates
Wallet balance health (per token, per chain) via Get Balances
Key usage: high-frequency access or abuse patterns
Integrate these metrics into your monitoring stack (e.g., Datadog, Prometheus, Sentry).
Fraud Prevention Tips
Check every user-provided wallet address with Validate Address before you submit the transfer, so it matches the token standard expected on that chain (e.g., ERC-20 for Ethereum)
Require users to confirm high-value transfers with 2FA or passkeys
Set thresholds for withdrawals per account per day
Use reference checks to prevent double submission
Automatically flag withdrawals to newly created or unverified addresses
Validating an address
POST /api/addresses/validate takes an address and a chain and answers one question: is this string a well-formed address on that network? The response returns valid as a boolean, echoes back the address and chain it checked, and adds an error string explaining the failure when valid is false.
Two limits are worth stating plainly to your team: it is a format check only — it does not assign, persist or fund anything, and it cannot tell you whether the recipient actually controls the address, so it stops typos and wrong-chain pastes, not social engineering. Because it is a plain POST, it costs nothing to call it on every address a user types in.
The full request and response fields, with a signed example, are documented under Validate Address in the Addresses API reference.