Check out working demo: Live Demo
Repo: privy-machines-cards-example
Repo: privy-machines-cards-example
- Partner API integration (
/partner/v1) only. - Server-side Privy wallet control for signing and sending transactions.
- Not a guide for Machines first-party web auth endpoints like
/v1/auth/email/exchange.
Architecture
- Your backend calls Machines Partner API.
- Your backend also calls Privy server APIs for embedded wallet signing/transaction execution.
- End users do not need wallet popups for embedded-wallet withdrawal execution paths.
Prerequisites
- Privy app configured for your environment.
- Privy embedded Ethereum wallets enabled.
- Privy authorization key configured for server-side wallet access.
- Machines partner API key.
- Partner backend can securely store:
- Machines partner key
- Privy app secret
- Privy authorization private key
Privy Embedded Wallet Checklist (Server-Side)
Before sending live traffic, confirm:- Wallet control path
- You can resolve each user’s Privy embedded Ethereum wallet.
- Your backend can sign/send on that wallet using an authorization context (authorization key, user JWT, or a custom sign function).
- Signer binding
- The wallet is configured with a signer path your backend can use (for example an authorization-key signer).
- The authorization private key is in a secrets manager, never in client code.
- Policy attachment
- Policy IDs for withdrawal execution are attached to the signer/wallet.
- Rules cover
eth_sendTransactionandeth_signTypedData_v4.
- Sponsorship setup
- Gas sponsorship is enabled in Privy Dashboard for the chains you support.
- Your backend passes
sponsor: truefor sponsored sends.
- Status monitoring
- You have webhook or polling support for transaction status reconciliation.
Recommended Data to Persist
Per user, persist at least:machinesUserId(your Machines partner user mapping)privyUserId(Privy user id)embeddedWalletAddress(andwalletIdif you store it)linkedAt/lastUsedAt
- partner idempotency key
- Privy
transaction_id/ user operation hash (if returned) - final onchain
transaction_hash - execution path (
controller_v1orcoordinator_v2)
End-to-End Partner Flow
1) Resolve or link the user
CallPOST /partner/v1/users/resolve from your backend.
2) Create a scoped partner session
CallPOST /partner/v1/sessions.
Use the smallest scope set needed for the current operation.
3) Run core Machines flows
Use the partner session token for:- KYC
- Agreements
- Cards
- Balances
- Deposits
4) Withdrawal flow (partner + Privy execution)
Call sequence:GET /partner/v1/withdrawals/assetsPOST /partner/v1/withdrawals/rangePOST /partner/v1/withdrawals/estimatePOST /partner/v1/withdrawals(includeadminAddress)- Execute onchain via Privy wallet APIs
Idempotency-Key when retrying POST /partner/v1/withdrawals after pending responses.
Execution Model and Contract Call Paths
Machines withdrawal create response includes:execution.callTargetexecution.callPath(controller_v1orcoordinator_v2)parameters(7-arg Rain executor payload)
execution.callTarget.
controller_v1:- Call 7-arg
withdrawAsset(...) - Selector:
0xe167d26a - Signature:
withdrawAsset(address,address,uint256,address,uint256,bytes32,bytes)
- Call 7-arg
coordinator_v2:- Build admin typed-data signature first
- Call 10-arg
withdrawAsset(...) - Selector:
0x4b268241 - Signature:
withdrawAsset(address,address,uint256,address,uint256,bytes32,bytes,bytes32[],bytes[],bool)
v2 Typed Data Shape
Partner-side Privy Execution (TypeScript)
Privy Method Allowances and Policy Design
For this flow, allow at minimum:eth_sendTransactioneth_signTypedData_v4(needed forcoordinator_v2)
- Do not hardcode a single contract address.
- Restrict
toto theexecution.callTargetvalues returned by Machines for supported chains/contracts.
ethereum_transaction:chain_idin allowed chainstoin your dynamically maintained allowlistvalue == 0
ethereum_calldata:- ABI for Rain withdrawal functions
function_name == "withdrawAsset"
ethereum_typed_data_domainandethereum_typed_data_message(for v2):- domain name/version chain checks
- typed message fields constrained to your expected flow
- Keep reusable condition sets per chain + function family.
- Compose those sets into authorization policies instead of duplicating large JSON blocks.
Example Policy Shape (Ethereum)
This is a concrete starting shape aligned with Privy’s Ethereum policy examples:- Use condition sets for
toaddresses and verifying contracts. - Keep policy values as strings matching Privy examples (
chain_id, hex values, address strings). - Treat this policy as an allowlist; add explicit
DENYrules only when needed.
Gas Sponsorship and Transaction Lifecycle
- Use
sponsor: truefor embedded wallet sends to sponsor gas. - For gas-sponsored EVM sends, backend responses can return before final onchain hash.
- Handle async status fields:
transaction_id(Privy transaction id)user_operation_hashhashmay be empty until confirmation.
- Track final status via:
- Privy webhooks (recommended)
- or transaction-status API polling by
transaction_id.
- Add operational monitoring:
- submission failures
- hash timeouts
- onchain confirmation delays
- spend anomalies and abuse patterns
Known Constraints and Gotchas
- Production destination coverage (BTC/SOL/EVM/etc.) depends on live relay routes. Always query:
GET /partner/v1/withdrawals/assetsPOST /partner/v1/withdrawals/rangePOST /partner/v1/withdrawals/estimatebefore quoting or creating withdrawals.
- Sandbox source is fixed to rUSD on Base Sepolia.
- If withdrawal signature response is
status: pending, retry with the same idempotency key.
Further Reading (Privy)
- Authorization keys overview:
- Server-side signing with authorization keys:
- Ethereum policy examples:
- Gas sponsorship setup:
- Transaction handling:
- Sponsorship security guidance: