Docs

Wallet providers

Build a self-custody Torq Earn program from product discovery through canonical deposit and redemption completion.

Build an Earn tab that stays inside your wallet, exposes institutional tokenized-credit products, and lets the user retain transaction control. This is a complete integration path, not an RPC or contract-call recipe.

Developer Preview. Obtain an approved test application, an origin-bound publishable key, the supplied SDK package, and Sepolia access before following the live steps.

Wallet-native Earn

Discovery, wallet consent, canonical completion

01Discover

Load deep vault, market, liquidity, and eligibility state.

02Review

Show the exact product, amount, fees, and prepared intent.

03Sign

The customer wallet simulates and submits the transaction.

04Confirm

Wait for final_success, then reread the position.

01Wallet UI

Catalog, vault detail, position, and redemption views.

02Wallet session

Origin-bound challenge and short-lived customer authority.

03Torq workflow

Prepare, register, and canonical transaction tracking.

04Reconciliation

Signed events plus canonical resource rereads.

What you will build

  • Earn catalog with asset, market, vault, allocation, liquidity, fee, activity, and risk details.
  • Vault detail and eligibility view for the connected wallet.
  • Origin-bound wallet session with no reusable custody secret in the browser.
  • partnerWrapperDeposit and partnerWrapperRedeem review, prepare, simulate, sign, and track flows.
  • Position, activity, redemption, failure, and canonical completion states.
  • Optional backend for signed webhooks, analytics, and recovery after the browser closes.

The user wallet is the customer-controlled signer. Torq never receives the private key or seed phrase, and the frontend never receives a Torq secret key.

Prerequisites

  1. A Torq Developer Preview organization, Sepolia application, approved wallet-provider program, allowed browser origin, and test publishable key.
  2. A supported EIP-1193 wallet or embedded wallet signer that can report chain ID, simulate where required, and submit exact prepared transactions.
  3. A server-side durable event inbox if users must resume workflows across devices or sessions.
  4. Product review for disclosures, eligibility, fees, redemption timing, and jurisdiction rules.

Keep TORQ_PUBLISHABLE_KEY origin-bound. Put TORQ_SECRET_KEY and TORQ_WEBHOOK_SECRET only in a server secret store. Never copy them into frontend environment variables.

Project files

Start from the checked-in, dependency-free reference:

examples/developer-platform/earn-program-reference/
├── .env.example                 # documented server/test configuration
├── src/config.mjs               # HTTPS and chain validation
├── src/torq-api.mjs             # API and wallet-session client
├── src/catalog.mjs              # complete catalog and deep product loader
├── src/workflows.mjs            # prepare, sign, register, final_success
├── src/webhooks.mjs             # raw-body signature verification
├── src/use-cases.mjs            # wallet-provider boundary profile
└── test/reference.test.mjs      # request and signature regressions

In your application, split the browser and server boundaries explicitly:

src/earn/catalog.ts              # browser: canonical read-only resources
src/earn/wallet-session.ts       # browser: challenge and wallet signature
src/earn/workflow.ts             # browser: proposal, prepare, simulate, submit
src/earn/views/                  # catalog, vault, position, activity, redeem
server/torq/events.ts            # server: signed webhook inbox
server/torq/reconcile.ts         # server: canonical resource rereads

Complete data contract

Do not render every product with a generic sample object. Load the exact schemas from these API pages and use returned freshness evidence in the UI:

PurposeOperations
CatalogGET /v1/assets, GET /v1/markets, GET /v1/vaults, GET /v1/tranches, GET /v1/funds
Product detailGET /v1/assets/{resourceId}, GET /v1/markets/{resourceId}, GET /v1/vaults/{resourceId}
EconomicsGET /v1/vaults/{resourceId}/allocations, GET /v1/vaults/{resourceId}/liquidity, GET /v1/fees, GET /v1/partner-programs, GET /v1/wrappers
Activity and mobilityGET /v1/markets/{resourceId}/activity, GET /v1/vaults/{resourceId}/activity, GET /v1/vaults/{resourceId}/share-mobility
Customer stateGET /v1/positions, GET /v1/eligibility, GET /v1/activity
WorkflowPOST /v1/workflows/prepare, POST /v1/workflows/{requestId}/transactions, GET /v1/workflows/{requestId}

Complete credit lifecycle

Apply the complete credit lifecycle inside the same Earn tab:

Customer momentWallet implementation
Deposit and tranche selectionShow Single Share, Senior, or Junior only when returned for the selected vault; review the wrapper deposit with the connected wallet.
Position, yield, and liquidityUse server GraphQL vaultHolderPerformanceCurrent for the selected vault holder; keep vault detail, allocations, liquidity, and activity current, and treat GET /v1/positions only as additional wallet market-position context.
Redemption and claimable cashPreserve the Torq redemption lifecycle and show immediate, queued, blocked, and claimable states instead of promising instant withdrawal.
Impairment monitoringReread GET /v1/liquidation-recovery, GET /v1/vaults/{resourceId}/activity, and the server event cursor when the selected vault or market changes materially.
Recovery centerShow GET /v1/funds, GET /v1/funds/{resourceId}, GET /v1/funds/{resourceId}/holdings, and wallet-specific recovery GraphQL beside the affected position.
Distressed-fund decisionMake it a separate capital allocation. An affected vault position does not automatically create eligibility, subscribe the wallet, compensate a loss, or create a fund claim.
Customer actionRequire explicit customer approval in the same customer-controlled signer. If the approved Preview executor is absent, keep monitoring available and show capability_not_ready.
Final reconciliationKeep the original vault position and optional fund position in separate UI and records; reconcile each from canonical state and signed events.

Use src/credit-lifecycle.mjs from the reference implementation. GET /v1/events and POST /graphql belong on the optional backend with a secret key; never expose them through the browser publishable-key client.

Build the integration

1. Configure the browser client

Set the Sepolia chain ID, Torq API origin, approved application origin, and publishable key. Reject a mismatched API origin or chain before asking the wallet to sign anything. Create the Torq client once per origin and environment; never fall back from hosted to localhost.

2. Create a wallet session

Request POST /v1/wallet-sessions/challenges, display the Torq challenge unchanged, ask the user wallet to sign it, then confirm with POST /v1/wallet-sessions/confirm. Validate the challenge audience, API origin, chain, application, wallet, purpose, expiry, and nonce before signer invocation. Use the returned short-lived wallet session only for its declared scopes.

3. Load the full Earn catalog

Call the list operations, then use loadEarnProduct() from src/catalog.mjs for the selected asset, market, vault, and optional fund. Show the underlying asset, vault strategy, market exposure, allocations, liquidity, fees, recent activity, share-mobility policy, freshness, and limitations. Do not invent APY, liquidity, risk labels, or availability from partial fields.

4. Check the connected wallet

Read GET /v1/eligibility and GET /v1/positions using the wallet and selected vault. If the resource is stale, the wallet is ineligible, share mobility is blocked, or the capability is not ready, show the governed reason and keep the action disabled.

5. Build a human-readable proposal

For a deposit, propose workflow role.investor.partnerWrapperDeposit; for an exit, use role.investor.partnerWrapperRedeem. Show product, asset, amount, wrapper, partner attribution, estimated fees, signer, network, and possible approvals before calling prepare.

6. Prepare and review exact transaction intent

Send the typed body to POST /v1/workflows/prepare with a stable idempotency key. Require preflight passed. Show every returned target, calldata summary, value, ordering, simulation requirement, expiry, and blocked reason. The user must approve this exact prepared payload, not only the earlier friendly proposal.

7. Simulate and submit with the user wallet

Reread GET /v1/workflows/{requestId} immediately before signing and confirm the snapshot and transaction intents are unchanged. Verify chain and expiry. Simulate each required transaction, then pass its exact to, data, and value to the user wallet in declared order.

8. Register and wait for canonical success

Register each hash through POST /v1/workflows/{requestId}/transactions. Poll the transaction resource and workflow until both return final_success. A wallet receipt, confirmation count, or event alone is not customer-visible completion. On success, reread positions, vault liquidity, and activity before updating the UI.

9. Reconcile signed events

On your server, verify the timestamp, delivery ID, signature, and exact raw request bytes using src/webhooks.mjs. Insert each delivery once, acknowledge quickly, then reread the referenced canonical resource. Deduplicate delivery and event identifiers. Never credit state from the event body alone.

10. Render explicit lifecycle states

StateWallet UI
proposedUser can inspect and cancel before preparation
preparedExact network, targets, value, and expiry are visible
awaiting_signatureWallet is the only signing boundary
submitted / mined_unconfirmedPending; balance is not yet credited
final_successReread canonical position and show completion
blocked or failedShow stable reason, request ID, and safe retry guidance

Test the complete journey

Run node --test examples/developer-platform/earn-program-reference/test/*.test.mjs, then test a Sepolia deposit and redemption with: wrong origin, wrong chain, expired challenge, denied signature, failed simulation, replaced transaction, duplicate register request, webhook replay, stale resource, closed browser, and successful resume from the server inbox.

Production checklist

  • Publishable key is restricted to exact hosted origins; no Torq secret is shipped to clients.
  • Challenge audience and prepared workflow are validated before every wallet signature request.
  • Every catalog field comes from the documented canonical API schema.
  • Eligibility and freshness fail closed at proposal and signing time.
  • The wallet sees exact target, value, network, action, fees, and expiry.
  • Customer balance changes only after workflow and transaction final_success plus resource reread.
  • Signed webhooks enter an idempotent durable inbox and trigger reconciliation.
  • Deposit, redemption, reload, retry, reorg, and error cases pass on Sepolia.
  • Private Preview labels, disclosures, support route, and status link remain visible.

Continue with the API reference, SDK reference, and webhook guide.

On this page