Skip to main content
Trustodian uses two independent credentials, and both are needed for anything that touches key material: An API key alone is enough for read-only calls (wallet lists, portfolio, orders, history). It can never sign: without the user’s wallet password the SDK cannot derive the key that decrypts a share.
Server-side only. Neither credential may reach a browser or mobile client.

API key

1

Create the key

Sign in to the Trustodian app, open Settings → API Keys, and create a key with the permissions your integration needs. A key can also carry an IP whitelist and a per-minute rate limit.This is the one step the SDK cannot do for you. An API key cannot issue another API key, and there is no registration or login call in the SDK.
2

Store it as a secret

Keep it in your secret manager or environment, never in source control.
3

Pass it to the constructor

The key is sent as the x-api-key header on every request. The backend resolves the key to a user account, so userRef for that account comes from the key itself. See userRef below.

Passkey / 2FA step-up

changeWalletPassword accepts an optional stepUp object carrying a passkey assertion and a 2FA code.
For API-key transport the operation is gated by the key’s own permissions instead, so stepUp is optional for SDK integrations.

The wallet-password session

Before createWallet, importWallet, sendTransaction, signOrder, or any other operation that reconstructs a key, the user’s wallet password must have unlocked a session. The password itself is never sent. Unlocking derives an in-memory session key, and the session must be unlocked before any operation that reconstructs a key. See Key Management for what the derived keys encrypt and why some calls still take a password argument even when the session is open.

Lifecycle methods

The password itself was set during app onboarding, since an account cannot be issued an API key before that. getEncTokenStatus() and getWalletPasswordHint() are there if you need to check state or help a user who has forgotten theirs.

Session TTL

A session lives for keyTtlMs milliseconds, 5 minutes by default, after which the session key is wiped. Configure it on the constructor:
Sessions are keyed by userRef, so one SDK instance can hold several users unlocked at once. Do not lean on the TTL as a security control. Call lockWalletSession(userRef) as soon as the request that needed it is finished.

Password status and lockout

Repeated wrong passwords lock the account: the API answers 423 Locked with lockedUntil and retryAfterMs, and the SDK raises a wallet-password lock error carrying both. Surface the wait rather than retrying in a loop.

Changing the password

changeWalletPassword is a full re-encryption pass over every share the account has. See Key Management for the result shape and the step-up rule.

userRef

userRef is the stable Trustodian account id the API key resolves to. It scopes session keys, shareStore rows, and every crypto call.
Use the same value everywhere for a given account. Two ways to supply it:
runWithUserRef keeps concurrent requests isolated from one another on Node.js, so you can set the userRef once per request instead of threading it through every call.

Account and platform info

hasRecoveryPhrase and recoveryPhraseVerified drive the seed flow, described in Recovery Phrase. getRecoveryPhraseStatus() reads them fresh; getSdkUser() may serve a cached profile.

Authentication failures

Auth failures arrive as UnauthorizedError, PermissionDeniedError or RateLimitError. For the HTTP status mapping, the full class list and recovery guidance, see Errors.
An invalid API key returns 403, not 401. A 401 means the header was absent, or the account behind a valid key could not be resolved. Branch on both when handling auth failures.

Security checklist

apiKey: process.env.TRUSTODIAN_API_KEY!, never in source control and never in a client bundle. Use the key’s IP whitelist so a leaked key is still unusable from elsewhere.
Take it from the authenticated user per request, use it, and drop it. It does not belong in env vars, config files, your database, or shareStore. Never write it to a log, not even at debug level, and the same goes for a device share or a reconstructed key.
InMemoryShareStore loses every device share on restart. Persist device shares per (userRef, walletId) in encrypted storage. See Key Management.
lockWalletSession(userRef) in a finally block beats waiting out keyTtlMs.
Separate keys per environment and per service keep permissions tight and make revocation cheap.
Last modified on September 8, 2026