ZPay protocol
Zcash settlement documentation
ZPay defines a non-custodial payment initiation flow for exchanging ZEC into an off-chain payout. The sender constructs and signs the Zcash transaction inside a compatible wallet. A settlement operator verifies the payment and releases the corresponding bank, card, or cash-pickup payout.
Key boundary: the web application never receives a seed phrase or spending key. It creates a payment request; the wallet remains responsible for transaction construction, review, signing, and broadcast.
Transaction flow
An order joins two independently finalized legs: an on-chain Zcash payment and an off-chain payout. Implementations should keep these legs in an explicit state machine rather than treating wallet handoff as successful payment.
- The client requests an executable quote for an amount and payout route.
- The quote service returns the exact ZEC amount, fees, expiration, required confirmations, and a unique recipient or order reference.
- The client encodes those fields as a ZIP-321 payment request.
- The sender reviews and signs the transaction inside their Zcash wallet.
- A chain observer detects the transaction using the operator's incoming viewing capability and associates it with the order.
- After the required confirmation threshold, the settlement service submits the payout instruction.
- The order becomes complete when the payout provider returns a final success state.
Submitting a transaction identifier is not enough to release funds. The observer independently verifies recipient, amount, network, expiry, and confirmation status.
Wallet connection
Zcash does not currently expose a broadly adopted, production browser-provider interface equivalent to EIP-1193. ZPay therefore separates address linking from payment authorization.
Address linking
A user may provide a public Unified Address for order association and refunds. The web client stores that address locally on the user's device. Address linking does not prove ownership and must not be treated as authentication.
Payment authorization
Authorization uses a standards-based zcash: URI. Clicking the payment action hands the request to an installed compatible wallet. On a second device, the same URI should be encoded as a QR code. The wallet parses the request, displays the recipient and amount, and asks the user to approve the transaction.
| Data | Website | Wallet |
|---|---|---|
| Public Unified Address | Stores locally | Provides address |
| Order amount and memo | Creates request | Displays and verifies |
| Seed phrase / spending key | Never | Local only |
| Transaction signature | Never | Created locally |
| Broadcast | Observed afterward | Submitted by wallet |
ZIP-321 payment requests
ZIP-321 defines URI-encoded Zcash payment requests. A single-recipient request can contain a Zcash address, decimal ZEC amount, label, human-readable message, and a base64url-encoded shielded memo.
Amounts are decimal ZEC with no more than eight fractional digits. Implementations should use Unified Addresses for new integrations. Any memo must be base64url encoded without padding and remain within the shielded memo size limit.
Request validation
- Reject expired quotes before opening a wallet.
- Validate that the address belongs to the expected network.
- Canonicalize the decimal amount before URI construction.
- Do not place personally identifying payout data in a memo.
- Bind each order to a high-entropy identifier and make request creation idempotent.
- Require an explicit user action before opening a wallet application.
Settlement
The settlement operator maintains liquidity for supported payout rails. A quote accounts for market price, operator spread, payout-provider fees, and the risk window between quote creation and confirmed receipt.
Confirmation policy
The required confirmation count is a risk decision. Low-value orders may use a lower threshold while larger orders wait longer. The interface must show the threshold before payment and must not describe an unconfirmed transaction as settled.
Payout initiation
Once payment verification succeeds, the operator submits an idempotent payout request. The provider reference is stored separately from the Zcash transaction identifier. Retrying a timed-out request must reuse the same idempotency key to prevent duplicate payouts.
Refunds and exceptions
Every order should collect a valid refund address before payment. Refund logic must cover expired quotes, underpayment, overpayment, duplicate payment, unsupported source pools, payout rejection, and provider failure.
- Underpayment: hold the order for review rather than silently reducing the payout.
- Overpayment: settle the quoted amount and return the excess according to policy.
- Expired payment: never apply a stale rate. Offer a new quote or return the ZEC.
- Failed payout: retry only after the provider confirms the original instruction did not complete.
- Refund: record the Zcash transaction identifier in the order receipt.
Privacy model
Shielded Zcash can conceal sender, recipient, and amount from the public ledger, but the settlement operator still processes information needed to deliver an off-chain payout. A bank transfer necessarily reveals information to the bank and payout provider.
Implementations should minimize correlation by issuing unique order references, separating wallet data from payout identity, limiting log retention, excluding sensitive payout details from memos, and restricting viewing-key access to the payment observer. Analytics must never receive full wallet addresses or payment-request URIs.
Privacy on the Zcash ledger does not make the off-chain payout anonymous. Product language must distinguish blockchain privacy from legal identity requirements imposed by payout providers.
Security model
The website is not a wallet and should never embed transaction signing. Its responsibilities are quote authenticity, request integrity, safe wallet handoff, correct order states, and protection of payout credentials.
Required controls
- Sign executable quotes server-side and reject any modified amount, destination, or expiration.
- Generate recipient addresses or order references from controlled wallet infrastructure.
- Keep spending keys outside the application tier; use view-only infrastructure for detection.
- Verify transactions from independent chain data rather than client-submitted claims.
- Encrypt payout-provider credentials and rotate them independently from wallet infrastructure.
- Apply rate limits and abuse monitoring to quote and order creation.
- Require manual review for policy thresholds and anomalous payout patterns.
Integration API
A production deployment exposes quote, order, and status resources. The browser must never be permitted to choose an arbitrary operator recipient after a quote is signed.
Create quote
{
"sell": { "asset": "ZEC", "amount": "1.25" },
"receive": { "asset": "USD", "method": "ach" },
"refund_address": "u1…"
}
Create order
{ "quote_id": "qt_01HX…", "payout_token": "ptok_…" }
201 Created
{
"id": "ord_01HX…",
"expires_at": "2026-09-20T20:10:00Z",
"payment_uri": "zcash:u1…?amount=1.25&…",
"required_confirmations": 2
}
Read status
{
"status": "payment_confirming",
"confirmations": 1,
"required_confirmations": 2
}
Webhooks should be signed, versioned, replay-protected, and delivered at least once. Consumers must deduplicate events by event identifier.
Order state machine
Transitions must be monotonic except for explicitly modeled exception handling. A provider timeout is not a failed payout; it is an unknown result requiring reconciliation. Likewise, a wallet handoff is not a detected payment.
Operational requirements
Operators need continuous monitoring across the chain observer, quote engine, wallet infrastructure, liquidity accounts, and payout provider. Reconciliation should compare every completed order against both a verified Zcash payment and a final provider record.
- Monitor chain-observer height and alert on synchronization lag.
- Track quote expirations, unmatched payments, and confirmation delays.
- Reconcile operator wallet balances against order liabilities.
- Maintain payout liquidity thresholds by currency and provider.
- Record administrative actions in an immutable audit log.
- Test refund procedures and provider outage playbooks regularly.
Current limitations
A static web client can link a public address and construct standards-compliant wallet handoffs, but it cannot independently provide executable exchange quotes, verify Zcash payments, perform identity checks, or deliver bank and cash payouts. Those functions require a settlement backend and regulated payout integrations.
Wallet support for URI handling varies. Always display the recipient and amount as a copyable fallback and encourage the sender to verify both inside the wallet before signing. A future broadly adopted Zcash WalletConnect implementation could add session-based capabilities without changing the non-custodial model.