Skip to main content
An embedded wallet lets you and your users hold and move on-chain assets without learning the chain underneath. Nobody constructs a transaction, manages a sequence number, holds gas, or opens a trustline. We build every transaction. The network gas and account reserves are part of the quote fee: they come out of the assets you ramp and show up as fee lines in the quote, so the wallet never holds a balance for fees.
Integrate server-side. Run registration, quoting and ordering from your backend with your API key. The signature that approves an order comes from whoever holds the signer key. For a copy-paste sandbox script, see the sandbox onramp.
An embedded wallet is non-custodial. Each wallet has a single signer key, a P-256 key. When an order needs to move the wallet’s funds, we put an authorization on the order. The key holder signs it, and only then do we move the funds. We can never sign or move funds on our own, and we can refuse to relay a transaction.
Embedded wallets run on Stellar, so the wallet’s chain is stellar. All endpoints use the raw API key in the Authorization header (no Bearer prefix); see Authentication. You do not need Stellar’s rules (trustlines, reserves, transaction expiry) to use an embedded wallet; we handle them for you.

Who holds the key

You, the integrating partner, choose who holds the signer key:
  • You hold the signer key yourself, on behalf of your program; or
  • Your end customer holds and controls the signer key, so only the customer can approve an order and you never hold or see the customer’s private key.
Control of the funds follows control of the key. A party that cannot move funds without the keyholder does not control them, so only the holder of the signer key can approve moving the wallet’s assets.
Whether holding the key makes you a custodian or money transmitter depends on your own facts, activities, and jurisdiction. This is not legal advice; determine your own obligations with your legal and compliance advisors.

Register the wallet

We create the embedded wallet when you register it. First, the key holder generates a P-256 key pair and keeps the private key. Then you register the public key with POST /organization/{organizationId}/payment_account. Use the id of the organization that owns the wallet: your own organization’s id from GET /me, or the customer organization’s id. The examples below set it as $ORGANIZATION_ID, and the quote and order use the same id. See Organizations in the route. Send kind embeddedWallet, and accountDetails of kind signerPublicKey with the chain and the signerPublicKey. signerPublicKey is the hex-encoded P-256 public key in SEC1 form, compressed (33 bytes) or uncompressed (65 bytes). The chain is stellar today.
The response is the payment account. Keep its id: you pass it to every quote that moves money into or out of the wallet.
To find a wallet you registered earlier, list the organization’s accounts with GET /organization/{organizationId}/payment_accounts.

Quoting and ordering

You quote and order an embedded wallet like any other wallet. Pass the wallet’s payment account id as destination on an onramp quote, or as source on an offramp quote. The other side is the bank account’s payment account. Both accounts must belong to the organization in the route.
Take destinationAsset from a token’s asset in GET /supported_assets?chain=stellar. The quote prices the account reserve and trustline a new wallet needs into its fee lines, so a new wallet gets its first funds from its first onramp and you never send XLM. Create the order with POST /organization/{organizationId}/order and the quoteId. The order’s id is the quoteId. For the rest of each direction, see Onramps and Offramps.

Order authorization

When an order needs the key holder to approve moving the wallet’s funds, the order’s authorization field holds the request. Otherwise authorization is null. Read it from GET /organization/{organizationId}/order/{id} or from the orderUpdated webhook.
reason tells you why we need the approval: The order status does not change while the authorization waits. The order stays created (for funding) or claimable (for claim). We send orderUpdated when authorization appears or changes. An order has at most one pending authorization at a time. An offramp or swap funded from an embedded wallet has no address to send to. Its fundingInstructions.destination carries the authorization id:
Approve that authorization to fund the order.

Sign the message

The key holder signs method.message with the signer key:
  • es256: ECDSA over P-256 with SHA-256.
  • Sign the UTF-8 bytes of method.message exactly as we return it.
  • Hex-encode the signature. We accept DER, or the 64-byte r||s form (128 hex characters) that WebCrypto produces.
In Node.js or a browser, WebCrypto does this directly:

Submit the approval

Send the authorization id and the signature to POST /organization/{organizationId}/order/{id}/authorization:
The response is the order. We move the funds, and the order continues through its normal statuses.

Errors and expiry

Each authorization expires at expiresAt. When one expires, we replace it with a new authorization that has a new id and a new message, and we send orderUpdated. Always sign the authorization you just read, and never reuse an old signature. See Errors for the error body format.

Claiming funds

The first time an embedded wallet receives an asset, it has no trustline for it. The asset arrives as a Stellar claimable balance, and the order moves to claimable. This comes from how Stellar works, not from Etherfuse. The order’s claimInstructions describes the balance:
To accept the funds, call POST /organization/{organizationId}/order/{id}/claim with no body. For an embedded wallet we return the id of the order’s claim authorization:
Read the order, then sign and submit the authorization with that id. Once the key holder approves, we open the trustline and claim the balance in one transaction, and the order moves to completed. A self-held wallet gets kind stellarTransaction with an xdr to sign and submit instead.
Sign the claim authorization soon after you read it. It expires at expiresAt. If it expires, we replace it with a new one with a new id, so read the order again and sign the new message.

Tracking the order

Subscribe to orderUpdated with POST /webhook_subscription. Each delivery carries the full order, so you see a new or replaced authorization, the move to claimable, and then the move to completed without polling. GET /organization/{organizationId}/order/{id} is the fallback. See Webhooks.

Sandbox onramp

Minimal server-side onramp script for sandbox

Stellar

Onramps

Offramps

Embedded Wallets Sandbox Onramp

A minimal server-side script that runs an embedded-wallet onramp in sandbox, from wallet registration to the signed claim authorization.