Guide
How to verify a Solana payment
After you send SOL from a wallet or scan a Solana Pay QR, you get a transaction signature — an 87-character base58 string. Paste it below to confirm the payment landed on mainnet: status, amount, sender, and receiver.
Look up your transaction
Full-screen tool: transaction lookup. Format check only (no RPC): signature validator.
Where to find the signature
- Phantom / Solflare — open Activity or transaction history, tap the tx, copy signature.
- Solana Pay — after approving in your wallet app, copy the signature from the confirmation screen.
- Block explorer — search your wallet on Solscan and open the recent transfer.
Signatures are public — sharing one does not expose your private key. Anyone can look up the same transaction on mainnet.
What to check
- Status — should say confirmed / success. A failed tx means no SOL moved.
- Amount — match the SOL you intended (minus network fee, which is separate).
- Receiver — confirm the destination address is who you meant to pay.
- Time — block time should be recent if you just sent.
Mainnet confirmations are usually under a second, but RPC nodes can lag a few seconds. If lookup says "not found", wait and retry. For a deeper breakdown of timing and commitment levels, see our Solana confirmation times guide.
Processed, confirmed, and finalized
Solana exposes three useful commitment levels when you ask an RPC node about a transaction. They answer different questions — and merchants should not treat them as interchangeable.
- Processed — a validator voted on the block containing your transaction. Fastest signal, but a minority fork could still drop it.
- Confirmed — a supermajority of stake voted on the block. Good default for most consumer payments and in-browser lookups.
- Finalized — the block is rooted and will not be rolled back under normal network conditions. Use this before shipping high-value goods or irreversible on-chain actions.
Browser tools (including the lookup above) typically query at
confirmed. A game or shop may wait an extra second or two before
unlocking content even though your wallet already shows success — that is
conservative verification, not a bug. If you are building a flow yourself, pick
one commitment level and document it for users.
How merchants verify payments on-chain
A wallet saying "confirmed" is not proof for a server. Anyone can fake UI text in a browser; the only trustworthy source is an RPC call your backend makes (or a webhook provider you audit). The usual server-side checklist:
- Fetch the transaction — call
getTransaction(orgetSignatureStatusesfor a lighter check) at your chosen commitment level. - Confirm success —
meta.errmust benull. A signature that exists but failed moved no SOL. - Match amount — parse lamport transfers to your treasury address. Never trust the amount the client claims; read it from chain data.
- Match sender or memo — if you issued an order ID, confirm the memo or reference field matches (see below).
- Check freshness — reject transactions older than your order expiry window so someone cannot replay an old payment.
Two common integration styles:
- Polling — the client sends a signature; your server
re-fetches until matched or timeout. Simple, works everywhere, but hammers RPC
if you poll too aggressively. Back off on
429responses — see API rate limiting explained. - Address watch / webhook — subscribe to account changes or use an indexer that POSTs to your URL when lamports arrive. Lower RPC load at scale, but you still must fetch and validate the full transaction before crediting — a notification alone is not verification.
Garden's multi-chain shop uses server-side verification with unique expected amounts per order so two buyers paying the same nominal price do not collide. For RPC endpoint choice, failover, and health checks, see Solana RPC endpoints.
Idempotency: verify once, credit once
Users double-click. Networks retry. Mobile wallets resubmit. Your verify endpoint must be idempotent: calling it twice with the same transaction signature should not deliver the product twice or double-count a deposit.
Store processed signatures in a database keyed by signature (or by order ID once paid). On repeat verify:
- If the signature was already credited, return success with the original order state — do not error.
- If a different signature arrives for an already-paid order, reject or flag for manual review.
- If verification is in-flight, use a short lock so two parallel requests do not race.
Idempotency protects buyers too: tapping "verify" again after a slow RPC should not create a duplicate charge or a second mint. Settlement systems for provably fair games apply the same rule — one on-chain bet, one payout attempt.
Memos, references, and unique amounts
When many customers pay the same treasury address, you need a way to tell which payment belongs to which cart. Common patterns:
- Memo instruction — Solana Pay and many wallets support a
short UTF-8 memo (order ID, invoice number). Your server parses
Memoprogram instructions inside the transaction and matches the string. - Reference public key — Solana Pay can include a read-only reference account in the transaction; indexers can filter by that pubkey.
- Unique amount — issue an expected total like
0.01042 SOLinstead of0.01 SOLso only one open order matches. The buyer must send the exact lamports; rounding in the wallet UI is a common support ticket.
Always confirm you are on mainnet before matching — a devnet signature looks identical but paid fake SOL. Our devnet vs mainnet guide covers how to spot the wrong cluster in explorers and RPC URLs.
Transaction failed or not found?
A failed status means no SOL moved. Common causes: cancelled in wallet, wrong network (devnet vs mainnet), or insufficient spendable SOL when your total balance looks fine — rent can be locked in empty token accounts.
After paying Garden Dice
Paid via Solana Pay or wallet on a challenge page? Copy the signature, verify it here, then return to the dice page and tap I've paid — detect & roll (or paste the sig in the fallback field).