Standards/solana-pay
Solana Pay
Overview
Solana Pay is a URL/URI standard for encoding Solana payment and transaction requests so they can be presented to a wallet — most commonly rendered as a qr-code for scan-to-pay.[1][2] The scheme uses the solana: URI prefix and comes in two flavours: a transfer request, a static, non-interactive URI describing a SOL or SPL-token transfer that the wallet composes locally, and a transaction request, an interactive form in which the URI points at an HTTPS endpoint that the wallet calls to obtain a server-built transaction.[1][2] The specification explicitly draws on Bitcoin's bip-21 and Ethereum's EIP-681 for its URI design.[1][2]
History
Solana Pay was introduced as an open standard for encoding Solana transaction requests within URLs.[1] The reference repository was originally published under the Solana Foundation and is now maintained in the anza-xyz/solana-pay repository (Rust-majority, ~1.7k stars, active 2026).[2] The spec records that "rough consensus" on the format had been reached with early implementations in wallets such as Phantom, FTX and Slope, and notes that the design was inspired by bip-21 and EIP-681.[1]
Technical specification
Transfer request (non-interactive)
A transfer-request URI has the form:[1]
solana:<recipient>?amount=<amount>&spl-token=<spl-token>&reference=<reference>&label=<label>&message=<message>&memo=<memo>
| Field | Required | Meaning / constraints |
|---|---|---|
recipient |
yes (path) | base58-encoded public key of a native SOL account (not an associated token account) |
amount |
optional | non-negative integer or decimal in user units (SOL, or the token's display units — not lamports); leading 0 required for values < 1; no scientific notation; if absent the wallet prompts |
spl-token |
optional | base58 SPL-Token mint address; presence makes the transfer an SPL-token transfer and triggers associated-token-account derivation |
reference |
optional, repeatable | base58 32-byte values used as read-only keys so the transaction can later be located via getSignaturesForAddress |
label |
optional | URL-encoded UTF-8 string identifying the request source (brand, store, person) |
message |
optional | URL-encoded UTF-8 string describing the transfer (item, order ID, note) |
memo |
optional | URL-encoded UTF-8 string placed in an SPL Memo instruction in the transaction |
The wallet builds the transaction locally, appending a SystemProgram.Transfer (for SOL) or a TokenProgram Transfer/TransferChecked (for SPL tokens) as the final instruction.[1]
Transaction request (interactive)
A transaction-request URI wraps a single HTTPS link:[1]
solana:<link>
where <link> is a (conditionally URL-encoded) HTTPS URL. The wallet then performs a two-step HTTP exchange with that endpoint:[1]
- GET → the application returns
{"label": "<string>", "icon": "<url>"}, whereiconis an SVG, PNG or WebP image, so the wallet can show who it is about to transact with. - POST with body
{"account": "<base58 pubkey>"}(the user's chosen account) → the application returns{"transaction": "<base64>", "message": "<optional string>"}, a fully serialized Solana transaction.
For an unsigned transaction (empty signatures) the wallet overrides the feePayer and recentBlockhash; for a presigned (partially signed) transaction it verifies the existing signatures and rejects the request if they are invalid or if a non-account signer is required. The wallet signs only with the requested account.[1] This server round-trip lets a merchant return any transaction — not just a simple transfer — which is the key difference from the static transfer request.[1][3]
Use cases
- Merchant point-of-sale QR: a store renders a
solana:transfer-request as a qr-code; the customer scans and pays in SOL or a stablecoin SPL token.[1][3] - Interactive checkout / mints: transaction-request URIs let a backend compose arbitrary transactions (NFT mint, multi-instruction checkout, discounts) on demand.[1][3]
- Transaction indexing: the
referencekeys let a merchant detect that a specific invoice has been paid without putting identifying data on-chain in a readable field.[1]
Implementations
- anza-xyz/solana-pay — the reference specification and JS/Rust libraries; Rust-majority, ~1.7k stars, active 2026.[2]
- Wallets: the spec cites early support in Phantom, FTX and Slope; Solana Pay is widely supported across the Solana wallet ecosystem.[1]
Comparison
- Solana Pay vs static URIs: the transfer request is a static, self-contained URI (like bip-21), but the transaction request adds an interactive server flow with no analogue in bip-21 — the wallet fetches a server-built transaction rather than constructing it from URI fields alone.[1][2]
- Solana Pay vs bip-21 / EIP-681: Solana Pay borrows the
scheme:recipient?paramsshape from bip-21 and EIP-681 but targets Solana's account/SPL-token model and adds thereferenceindexing keys and the transaction-request callback.[1] - vs Lightning request formats: where bolt11 / LNURL encode a single Lightning invoice or a callback to obtain one, Solana Pay encodes either a self-contained transfer or a callback that returns a complete signed-or-unsigned Solana transaction.[1]
Status
Solana Pay is an active, openly specified standard with wallet support across the Solana ecosystem and an actively maintained reference repository (2026).[1][2]
Sources
1 Solana Pay Specification — Solana Pay Docs, 2026 2 anza-xyz/solana-pay — GitHub, 2026 3 Solana Pay Overview — Solana Pay Docs, 2026
Deployments
No country reports mention this standard by name.
Regions / aggregations not mapped to a single country
- Universal