Partners

Sample integration

A small payment example, the reference app's flow, and what to add before launch.

The Next.js reference demo follows the journey in these guides: raffle browsing, wallet checkout, tickets, collection, sellback and shipping. It uses external wallets and Verity-collected payments. Contact the integration team for access to the demo source; this page does not require repository access.

Payment submission example

Download ticket-payment.ts. It is a dependency-free TypeScript helper for the step after wallet signing: save → broadcast → register. It deliberately has no API key, wallet private key, or automatic replacement transaction.

Use the transaction construction and signature verification in Build the wallet payment. Then connect the helper to your own authenticated server:

Submit the already-verified signed ticket payment
import { submitTicketPayment } from './ticket-payment';

async function post(path: string, body: unknown) {
  const response = await fetch(path, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    credentials: 'same-origin',
    body: JSON.stringify(body),
  });
  if (!response.ok) throw new Error(`Request failed: ${response.status}`);
}

const result = await submitTicketPayment(savedPayment, {
  // These two /api/purchases routes are YOUR routes to implement, not Verity URLs.
  save: payment => post('/api/purchases/signed-payment', payment),
  broadcast: base64 => connection.sendRawTransaction(Buffer.from(base64, 'base64')),
  register: payment => post('/api/purchases/register-payment', {
    checkoutId: payment.checkoutId,
    raffleId: payment.raffleId,
    tx_signature: payment.signature,
  }),
});

// Always fetch this checkout's status. Neither a successful broadcast nor
// receipt registration confirms tickets. Retain the journal on any error.
// result.broadcastError / result.registrationError can drive a recovery notice.
// Use result.checkoutId to resume; never turn either error into another payment.

Your save route must commit to durable storage before responding. Both routes must authenticate the buyer, verify checkout ownership, validate the request and apply rate limits. The register route calls POST /raffles/{raffleId}/checkouts/{checkoutId}/payment with your server-side partner key.

This helper has no retry loop. After interruption, follow Recover purchases, inspect the current checkout and transaction validity, and only rebroadcast the same bytes when appropriate. A receipt-registration error is not a reason to call wallet signing again.

Where to look in the reference app

FileWhat it demonstrates
app/api/auth/route.tsWallet challenge verification and an HTTP-only app session
app/api/verity/[...path]/route.tsRestricted partner API proxy; buyer identity from the authenticated session
components/purchase.tsxQuantity checks, reserve, approve, submit, poll and buyer-facing errors
lib/wallet.tsNetwork and balance checks, exact USDC transfer, simulation and unchanged-message verification
lib/journal.tsSave checkout identity and signed payment before broadcast
components/collection.tsxWallet collection, offers, full shipping address, terms and order recovery
lib/preview.tsFictional data and simulated outcomes, isolated from live API mode

File names describe the shared demo source, not a required structure for your app. The payment guide uses @solana/web3.js; the demo uses @solana/kit. Both must follow the same transaction and recovery contract. You do not need both SDKs in your app.

Run the demo when you have the source

Use Node.js 24 and the included lockfile:

npm ci
cp .env.example .env.local
npm run dev

The example configuration starts in preview mode at http://localhost:3220. Use Connect wallet → Use preview account. Preview does not move funds. For API mode, follow the repository README and environment setup; a partner key, assigned raffle and registered origin are required.

Reference behaviour versus your production app

The demo providesYour production integration must provide
Browser journal and tab lockingDurable server purchase records, reconciliation and cross-device concurrency control
A restricted authenticated proxyYour account model, authorization and application rate limiting
External Wallet Standard connectionTested desktop and mobile wallet support; embedded wallets or deep links if your audience needs them
Local preview and deterministic browser testsTests with your own environment, approved funds and actual wallet journey
Quote review and terms checkboxYour configured Redemption Terms URL and consent record for the accepted order

On phones, the demo uses a compatible wallet's in-app browser. It does not implement automatic wallet-app handoff or embedded wallets. Check sign-message and sign-only transaction support before showing a flow that needs them.

Never distribute .env.local, partner keys, wallet keys, signed transactions or operational test records with your source. Use separate staging and production configuration.

On this page