Skip to content
barcoder

Standards/solana-pay

Solana Pay

TypeQR Data Format
Completeness71%high

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]

  1. GET → the application returns {"label": "<string>", "icon": "<url>"}, where icon is an SVG, PNG or WebP image, so the wallet can show who it is about to transact with.
  2. 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 reference keys 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?params shape from bip-21 and EIP-681 but targets Solana's account/SPL-token model and adds the reference indexing 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
source · docs/standards/solana-pay/index.md