Account Credentials
Your account is protected by a username and password. Both are validated on the server, so the rules below are the ones that actually apply -- a client that skips its own checks still gets rejected.
- Username: 3 to 32 characters, must start with a letter, and may otherwise contain only letters, numbers, underscores, and dots
- Password: at least 8 characters, with at least one uppercase letter, one lowercase letter, one digit, and one special character
- Anything that is not a letter, a number, or whitespace counts as a special character -- +, =, ~ and backtick all qualify
- Usernames are unique. Registering a name that is taken is rejected with a 409 response
How Your Password Is Stored
SEND does not store your password. It stores an Argon2id hash with a fresh random salt per hash, in standard PHC format. The parameters are fixed in the build -- there is no setting, environment variable, or account tier that weakens them.
- Algorithm: Argon2id
- Memory cost: 65536 KiB (64 MiB)
- Time cost: 3 iterations
- Parallelism: 4 threads
- Output: 32-byte hash, 16-byte salt
Failed Sign-In Lockout
Consecutive failed password attempts lock the account, with the wait doubling each time. The lock is evaluated before the password is verified, so a locked account cannot be probed at all.
- Third consecutive failure: locked for 1 minute
- Fourth: 2 minutes. Fifth: 4 minutes. Sixth: 8 minutes -- doubling, with no upper bound
- A successful sign-in resets the counter to zero and clears the lock
- While locked, sign-in returns 403 and states the exact unlock time in UTC
Two Ways to Authenticate
The web app signs in with a username and password and receives a bearer token. Programmatic clients can present an API key instead. Both travel in the same Authorization header, and the server tells them apart by prefix.
- A credential beginning with ck_ is an API key: ck_ followed by 64 hexadecimal characters
- Only a SHA-256 hash of the key is stored, so SEND cannot show you the key again after it is created
- Settings > API Keys lists the first 8 characters of each key, when it was last used, and a revoke action
- Anything not prefixed with ck_ is validated as a JWT access token
Rate Limits
Requests are metered per account in three tiers, with a separate per-IP tier for traffic that is not signed in. The quotas are compile-time constants and are identical for every account.
- Read (any GET): 120 requests per minute
- Write (POST, PUT, PATCH, DELETE): 60 requests per minute
- Heavy write: 5 requests per minute -- batch wallet generation, dev-wallet creation, and project launch
- Not signed in: 30 requests per minute per IP address
- Exceeding a limit returns 429 with a Retry-After header (in seconds) and the error code RATE_LIMITED
Real-Time Connection Security
The live data feed is a WebSocket, and it is not authenticated by putting your token in the URL. You request a ticket over the authenticated API, then present that ticket during the connection handshake.
- A ticket is valid for 30 seconds
- A ticket is single-use and is consumed atomically, so a replayed ticket is rejected even when two connections race with it
- Open connections are re-validated every 5 minutes; a deactivated account, or one whose password has changed, is disconnected
- The connection heartbeats every 30 seconds and is dropped after a 10-second missed response
What SEND Holds on Your Behalf
SEND generates and holds the private keys for your trading wallets and signs transactions for you. That makes your account credentials the practical boundary around your funds -- there is no separate wallet password and no seed phrase you hold independently.
Private Key Security covers exactly how key material is stored, who can decrypt it, and what is deliberately not available.