Skip to main content
The TypeScript SDK is WIP. Today, call the Relayer HTTP API directly: POST /recipient/register, GET /recipient/addresses, POST /recipient/derive-stealth-key. The shapes below mirror those endpoints.
Tachyon doesn’t require usernames, passwords, or accounts. A user is identified by their wallet.

The key model

The recipient’s viewing and spending keys are generated and held inside Tachyon’s secure enclave on POST /recipient/register. From then on, any action that needs those keys (listing stealth balances, deriving a stealth key to sweep funds, producing a disclosure record) is performed by the enclave after verifying a wallet signature from the user. Integrators don’t store viewing keys client-side. The enclave is the source of truth; the wallet signature is the authorization. This design means a lost device doesn’t lose the keys. A new device onboards by re-proving wallet ownership to the relayer.

Register a user

Idempotent: calling again for the same address returns existing public keys, it does not re-generate.

Read operations (all wallet-gated)

List the user’s stealth addresses

Derive a stealth key to sweep a specific delivery

The derived key lives only as long as your session needs it. Use it to sign a Safe transaction (or hand it to the relay-proxy sweep flow, which is gasless for the user).

What about client-side persistence?

Don’t, unless you have a specific reason. The common instinct is to cache a viewing key in the browser so the user “stays logged in”. We’d rather you didn’t:
  • Browsers leak. Any browser-side storage (localStorage, IndexedDB, even session storage) is within reach of XSS, extensions, or shared-device scenarios. The blast radius of a leaked viewing key is “everything this user ever receives”.
  • The enclave is always available. Re-fetching on demand with a fresh wallet signature is a single round trip.
  • The wallet is already the user’s identity. Asking them to sign once per session is a familiar UX pattern.
If you absolutely need to cache (e.g. a native mobile app with a long-lived session):
  1. Keep the derived stealth key, not the viewing key. Derived stealth keys are per-intent; one leaking compromises one delivery, not all future inflows.
  2. Encrypt with a key the user sets (PIN, biometric-unlock, wallet-signed KDF). Never in cleartext.
  3. On iOS/Android, use Keychain/Keystore; never raw app storage.

Backup and recovery

The enclave-resident keys are recoverable by re-registering with the same wallet signature. “Losing” a viewing key client-side is not a problem because there is no client-side source of truth. The user loses access only if they lose control of the wallet that registered the address. That’s the same failure mode as any other on-chain account, and your existing wallet-recovery UX covers it.
There is no separate recovery phrase for viewing keys. Wallet ownership is the recovery mechanism.

Multiple wallets per user

If a user wants to treat two wallets as separate identities (say, one per workspace), each wallet registers independently and the relayer stores distinct key material for each. Switching is a session-level signing operation.

What integrators do not manage

  • Encryption of intent payloads (enclave handles it)
  • Stealth address derivation (enclave handles it using the recipient’s enclave-held keys)
  • Sweep transactions from the stealth address (gasless via POST /recipient/relay-proxy)
You stick to wallet flows; the relayer and enclave handle the rest.

Submit an intent

Build, sign, and submit your first intent.