Set up in the portal
For a server-created Deposit, the merchant needs ansk_ key stored on a
server and a destination wallet for the person being funded. Add Payer
choices in the portal only when the payer should choose among configured
destination chain/token pairs; it does not replace the recipient on a simple
server-authored Deposit. Payout addresses are not required for this
merchant-managed recipient flow.
For a partner that Hypermid has enabled, a publishable key can create an open Deposit
directly in the browser with @hypermid/sdk/publishable-deposit, without a
merchant backend. The browser must use one destination-binding artifact; it
cannot name an arbitrary chain, token, or recipient. The production rollout is
partner-gated: configure the key’s exact origin yourself, then ask Hypermid to
enable the partner; otherwise use this server-created flow, a registered
destination, or a payment link. Verify success
from a server-side session read or a signed webhook, not from the payer’s
browser.
Omitting amount is what makes it open. minAmount / maxAmount bound it.
Fees
A Deposit uses the same two-fee policy as Checkout and Withdrawal: the Hypermid fee plus an optional developer fee on the same payer-input amount. The developer fee defaults to 0 and is limited to 0–100 basis points. A partner Hypermid override replaces the global rate outright. Same-token EVM transfers are the zero fee exception because a plain transfer cannot collect a fee. On EVM routes, developer earnings are held by Hypermid and settled periodically by manual transfer. On the Near deposit-address rail, the provider keeps half of each declared app fee and pays the developer leg directly to the configured recipient.Let the payer choose what they receive
If your customer can receive funds on more than one chain, create the deposit withdestinations instead of one top-level destination. Each candidate binds
a chain, token, and recipient chosen by your server. The hosted payment page
shows the candidates in the same order you send them.
Each candidate needs its own recipient for that chain. A Solana destination
needs a Solana address, a Sui destination needs a Sui address, and an EVM
destination needs an address on that EVM chain. Never reuse one address across
ecosystems merely because the same customer owns all of the wallets.
The same destinations power browser-created Deposits
The destination candidates configured for a server-created Deposit are also the choices a browser can select with a publishable key when Method 2 is enabled. The browser submits the candidate’s opaquecandidateId; it does not submit a
replacement chain, token, or recipient. This keeps the destination bound to the
same merchant-controlled configuration instead of trusting a public key to name
where funds should go.
The other binding artifacts are a payer-signed SIWE challenge, which is
EVM-only, or a single-use grant minted by a merchant server. A grant therefore
does not provide a no-backend integration. See Payments for
the three choices and the current 403 rollout errors, and the
publishable-key SDK reference for exact types.
The chain inside each candidate is a decimal string, not a JavaScript
number. Keep it as a string end to end. Sui’s chain ID,
"9270000000000000", exceeds Number.MAX_SAFE_INTEGER; JavaScript does not
guarantee exact integer handling in that range, and other IDs can silently
round. Use BigInt(chain) only if you genuinely need arithmetic.
Mixed Base, Solana, and Sui example
This example creates one open deposit that lets the payer choose USDC on Base, native SOL on Solana, or native SUI on Sui. The three recipient variables must be addresses from their respective ecosystems.Configure the destinations once, in the portal
destinations names the candidates on every request. If your accepted
(chain, token) pairs are the same for every payer, configure them once in
the partner portal and pass only a payer-owned recipient per chain with
destinationRecipients instead:
- A recipient is required for every configured chain. Omit one and the request fails.
- Each recipient is validated against its chain. An EVM address on the Bitcoin row is rejected.
destinationRecipientsis mutually exclusive withchain/token/recipient/amount/minAmount/maxAmountand withdestinations. Sending either alongside it is a400.- One configured pair produces an ordinary session directly — no intent, no picker, no selection call.
destinations: the response is an intent
with status: "awaiting_destination", and the payer selects one before funding
(next section).
Selecting and freezing a destination
Both multi-destination shapes (destinations and multi-pair
destinationRecipients) return an intent, not a session:
status: "awaiting_destination". GET /v1/payments/:id/public returns its
destinationCandidates, each with an opaque id. Two endpoints move the payer
from an intent to a frozen session — mind which one you use:
Use
PUT while the payer is still deciding — a picker that highlights the
current choice can call it as often as the payer changes their mind:
POST once, when the payer commits, to freeze the session:
POST freeze is irreversible. Repeating it with the same candidateId
is idempotent, but POSTing a different candidate after the first success
returns 409 — as does any PUT once the session is frozen. The freeze happens
before the flow issues a deposit address, because letting the destination change
after an address is shown could strand funds at an address the session no longer
tracks.
After the freeze, quote, payment, settlement, webhook, and session-read behavior
is the same as for any other deposit.
Existing integrations do not need to change. A request with top-level
chain / token / recipient still creates the same single-destination
session as before. A one-item destinations array also creates an ordinary
session directly: no intent, no destination picker, and no selection call.Funding from a non-EVM chain
If the payer holds BTC, SOL, TON or similar, there is no wallet that can sign an EVM transaction — the session takes the deposit flow instead. Mint an address withPOST /v1/payments/{id}/deposit, supplying
originAsset and refundTo.
Want a quote without reserving an address? GET /v1/payments/{id}/deposit-quote
prices it without minting.