Intermediate · LESSON 05 OF 12
5. Build and reconcile Solana token payments
By the end, you can design a wallet-approved token checkout and verify its exact on-chain payment before fulfilling an order.
Look up Solana terms in the glossary
Optional reading history is saved only in this browser. It is not a scored checkpoint or exam result.
In this lesson8 field notes · practice · sources · checkpoint
Read a text version of this diagram
The merchant first stores an order with a cluster, recipient wallet, supported token mint and program, integer amount, expiry, and confirmation policy. The payer reviews and signs the exact transaction. The server then verifies the signature on that cluster, checks successful execution and the selected commitment, and parses the token transfer rather than trusting a browser callback. It compares the actual mint, program, destination account, and raw amount with the saved order. A processed result waits; a failure or mismatch does not fulfill. A correct payment is consumed through a durable cluster-and-signature key linked atomically to order fulfillment, so duplicate events cannot ship twice. Fees remain separate from the token amount.
- QUOTE · cluster, wallet, mint, raw amount, expiry
- REVIEW · token transfer and SOL costs separately
- SIGN · payer approves the exact transaction
- VERIFY · server checks cluster, status, error, and accounts
- MATCH · mint, program, destination, and raw amount
- FULFILL ONCE · persist cluster-plus-signature idempotently
DOWNLOADABLE DEVELOPER LAB · FICTIONAL FIXTURES
Reconcile a token payment before fulfilling an order.
This local workbook compares an order with a synthetic transaction observation: cluster, exact mint, token program, destination account, base-unit amount, transaction result, commitment, and duplicate signature. It does not call RPC, connect a wallet, sign, persist payment records, or submit transactions.
Download Payment Reconciliation Workbook 01Requires Node.js 20+. Unzip the package and run npm test. “Ready to fulfill” is only a local teaching classification; a real service needs durable, atomic idempotency and its own production review.
Model the payment as an application order plus chain evidence
A checkout has two related records. The application creates an order with an internal order ID, selected cluster, recipient wallet, supported token mint, token program, expected raw amount, expiration policy, and the commitment required before fulfillment. The chain later provides a transaction signature and account-state evidence. Keep the expected order immutable after the payer sees it; if price, recipient, token, or amount changes, issue a new quote and require a new approval. A signature returned by a wallet or payment component is a lookup key, not proof that the transfer landed. The server must fetch or index the transaction on the same cluster and compare it with the saved order. This separation makes delayed confirmations, duplicate notifications, wrong-network transfers, and support investigations legible.
Identify the asset by mint and token program, never by its label
A symbol such as “USDC” or “USD” is display text. The mint address identifies the on-chain asset, while the mint account’s runtime owner identifies the Token Program or Token-2022 program that controls it. A wallet has a token account for each supported mint; the associated token account is derived from the wallet, mint, and token program. Deriving the wrong program produces a different address. Maintain a server-side allowlist of exact cluster, mint, token program, and decimals, and verify the mint and token-account owners against it. Do not accept a user-supplied ticker as asset identity. Token-2022 extensions can change transfer behavior: review the actual mint configuration and relevant fee or hook behavior before supporting it. If the checkout only supports ordinary transfers, reject unsupported extensions and tell the learner why.
Create a quote that can be matched without guessing
For a fixed-price order, convert the requested token quantity into an integer string in the token’s base units using the verified mint decimals. Keep the display amount and raw integer together, but never parse the integer through JavaScript Number. Show the asset, network, destination, exact amount, quote expiry, and whether a token account may need creation. A public merchant wallet address is the receive identity; the payer or payment library can derive the appropriate token account. Do not publish a token-account address as if it were the wallet. If invoices share one merchant wallet, match payments using the full expected tuple and an application-generated order mapping; a memo can help correlation but is public transaction data and must not contain a person’s name, email, or sensitive order details. State how underpayments, overpayments, expired quotes, and unsupported assets are handled before checkout.
Let the wallet approve the exact transaction and every cost
The client may build a transaction that creates the receiver token account when needed and then transfers tokens. Solana executes the transaction atomically: either all instructions succeed or their state changes roll back. The fee can still be charged when execution fails. Present the token amount separately from the SOL network fee, optional priority fee, and any account-creation cost; do not call all of them “the price.” The user must review the transaction in their wallet and choose whether to sign it. A merchant application or RPC endpoint cannot substitute its own approval. If a fee payer sponsors the network fee, label that payer and the policy; never imply that sponsorship removes all costs. After any quote or transaction change, request a fresh approval for the new bytes rather than silently replacing the transaction.
Verify server-side at a policy-appropriate commitment
Treat the returned signature as a pointer to evidence. Query the intended cluster, require a successful transaction result with a null execution error, and enforce the order’s chosen commitment. A processed observation is provisional and may be dropped; an application can wait for confirmed for ordinary fulfillment or finalized where its stated risk policy requires stronger settlement. Those thresholds are policy choices, not a universal guarantee. Verify the transaction actually transferred the supported mint through the expected token program to the expected recipient account for the exact raw amount. A UI callback, block explorer label, event webhook, log line, or account-balance increase alone can be incomplete evidence. Preserve the signature, cluster, commitment, slot, transaction error, and parser version so a later reconciliation can explain what was checked.
Parse transfers carefully and separate amount from fee
A transaction can contain several instructions and inner program calls. Inspect the transaction’s program IDs, accounts, instruction effects, execution error, and pre/post token balances; pair token-balance records by account index and mint instead of comparing array positions. Confirm the destination token account belongs to the intended wallet and mint, and account for the correct token program. Raw amounts and decimals describe token units; transaction fees are lamports paid by the fee payer. Keep them in separate fields. Extensions such as transfer fees can make the recipient’s credited amount differ from the sender’s requested transfer amount, so a payment policy must define whether it requires an exact gross transfer, exact net receipt, or an unsupported-extension rejection. Do not infer the requested invoice amount from a rounded UI balance. If an RPC response lacks transaction metadata or is pruned, mark the payment unresolved and use another permitted evidence source.
Make fulfillment idempotent across retries and stream duplication
An indexer or webhook can deliver the same signature more than once, and a worker can crash after fulfillment but before acknowledging the event. Persist a unique key scoped to cluster and signature, link it to the order, and update the payment and fulfillment state in one database transaction or through a durable outbox. A duplicate must return the original result without shipping twice. A different signature may still be the same payer intent, so define whether one order can accept one payment, several partial payments, or a replacement transaction. Do not advance a history cursor until the corresponding records are durable. On a missing cursor, conflicting providers, unsupported transaction version, or pruned history, keep the order in review instead of marking it paid. Recovery policy should make refunds, late payments, and manual review explicit.
Choose an integration path and test failure cases before launch
Solana’s documented options include a payment component, Solana Pay for payment links or point-of-sale, and direct RPC integration; high-volume monitoring may require a dedicated indexing or streaming service. The current Commerce Kit quickstart labels its API as beta, so pin and review versions before relying on it. Whichever path you choose, the merchant server remains responsible for matching verified payment evidence to its order and ensuring exactly-once fulfillment. Test wrong cluster, lookalike mint, wrong Token Program, wrong destination, underpayment, overpayment, failed instruction, processed-only status, duplicate signature, missing history, stale quote, and worker restart. Use synthetic fixtures first, then a separately approved Devnet rehearsal with disposable test assets. A passing fixture proves only its encoded cases; production readiness also needs monitoring, reconciliation, support, and refund procedures.
A detail worth keeping.
Compare PaymentButton, Solana Pay, and direct RPC against one merchant requirement. Mark which component constructs the transaction, who verifies the signature, and which service decides that an order can be fulfilled.
Work through an example
Trace a Token-2022 transfer from mint configuration through program owner, destination account, raw transfer amount, and the recipient’s net balance. Identify the evidence needed when an extension changes the credited amount.
Use only the fictional records in the downloadable workbook. Given a fixed token order, label the expected cluster, mint, program, destination account, base-unit amount, and commitment. Classify an exact confirmed transfer, a processed notification, a wrong-mint transfer, an execution error, and a duplicate signature. For every case, say whether the application may fulfill, must wait, must reject, or needs operator review. Keep the token amount and SOL network fee in separate columns, and state which durable database operation prevents a retry from fulfilling the same signature twice.
GUIDED PRACTICE · INTERMEDIATE
Do the work, one step at a time.
Use fictional addresses and disposable test data. Do not enter a recovery phrase or private key. Most exercises work on paper or with a local test; only a lesson that clearly says “read-only Devnet” makes a public network request.
- Unzip the Payment Reconciliation Workbook and run `npm test`; every fixture is fictional and local.
- Compare the order and observation records field by field. Explain why the cluster and exact mint are part of identity.
- Change the observed token program, destination account, and raw amount separately; confirm each produces explicit mismatch evidence.
- Lower the observed commitment to processed. Keep the order awaiting confirmation even if the wallet already returned its signature.
- Replay a valid confirmed signature after recording it as processed. Confirm the workbook marks it already processed rather than ready to fulfill.
- Draw the durable production database transaction or outbox that would connect signature consumption to exactly-once fulfillment; identify the unresolved recovery path if that store is unavailable.
Before you move on, check your reasoning
- Write a payment state machine with quoted, awaiting-signature, submitted, confirmed, finalized, mismatch, failed, expired, and review states; specify which transitions require durable evidence.
- Design an atomic idempotency record keyed by cluster and signature and test a worker crash between database commit and webhook acknowledgement.
- Set a threshold for when your application requires confirmed versus finalized status, and document the user, inventory, reversal, and fraud costs behind that choice.
OPEN SELF-CHECK · UNGRADED
Pause and test your reasoning
Practice 1 of 3
A confirmed transfer reaches the merchant wallet but uses an unsupported mint with the familiar USDC symbol. May the fixed USDC order be fulfilled?
Reveal the answer and explanation
One best answer: No. Match the exact mint and token program.
A display symbol is not an asset identifier. Compare the on-chain mint and token program against the supported values on the specified cluster before considering the payment for an order.
Sources: How Payments Work on Solana · Verification Tools
Practice 2 of 3
The browser reports payment success, but the order requires confirmed commitment and RPC only reports processed. What should the server do?
Reveal the answer and explanation
One best answer: Wait for the saved commitment and verify the transaction details.
A callback and a signature do not establish the saved settlement threshold. Keep the order pending until the server retrieves successful transaction evidence at the required commitment on the order’s cluster.
Sources: Verification Tools · Indexing
Practice 3 of 3
A confirmed webhook for one valid payment is delivered twice after a timeout. What prevents a second shipment?
Reveal the answer and explanation
One best answer: Persist the cluster-scoped signature and fulfillment change atomically to stop duplicate shipping.
Delivery systems retry and subscriptions may replay records after reconnect. Persist the cluster-scoped signature and fulfillment change atomically so another delivery returns the previous result instead of repeating the side effect.
Sources: Verification Tools · Indexing
This practice is not scored, saved, or part of a certificate. Account-based lesson checkpoints and level exams remain separate.
Never enter a recovery phrase or private key into a learning site or lesson exercise.
READ THE SOURCE
Go deeper in the official docs
Reviewed on 2026-10-03. Protocol documentation can change; check the linked page’s current version as you use this material.
YOUR PROGRESS, SAVED
Ready for the checkpoint?
Make a free account to save your progress and unlock the quizzes.
Create free account