Issue tickets against a settled USDC payment
Existing payment-first flow. Submit the signature of a finalized USDC transfer and receive ticket codes.
Building the payment
import { createTransferCheckedInstruction, getAssociatedTokenAddressSync } from "@solana/spl-token";import { PublicKey, Transaction, TransactionInstruction, sendAndConfirmTransaction } from "@solana/web3.js";const MEMO_PROGRAM_ID = new PublicKey("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr");// Public payment details fetched by your server. Never expose your partner API key.const { treasury_ata, usdc_mint, decimals, memo_prefix } = detail.data.payment;// 2. Exact amount, fixed-point. Floats will drift you off by base units.function decimalToBaseUnits(value, decimals = 6) { const match = /^(\d+)(?:\.(\d+))?$/.exec(value); if (!match || !Number.isInteger(decimals) || decimals < 0 || decimals > 9) { throw new Error("Invalid token amount"); } const fraction = match[2] ?? ""; if (fraction.length > decimals && /[1-9]/.test(fraction.slice(decimals))) { throw new Error("Amount exceeds token precision"); } return BigInt(match[1]) * 10n ** BigInt(decimals) + BigInt(fraction.slice(0, decimals).padEnd(decimals, "0") || "0");}const baseUnits = decimalToBaseUnits(detail.data.ticket_price_usd, decimals) * BigInt(qty);// 3. transferChecked (NOT transfer) + exactly one memo.const mint = new PublicKey(usdc_mint);const tx = new Transaction().add( createTransferCheckedInstruction( getAssociatedTokenAddressSync(mint, payer.publicKey), mint, new PublicKey(treasury_ata), payer.publicKey, baseUnits, decimals, ), new TransactionInstruction({ keys: [], programId: MEMO_PROGRAM_ID, data: Buffer.from(`${memo_prefix}:${externalUserRef}`, "utf8"), }),);// 4. Wait for FINALIZED before submitting to Verity.const signature = await sendAndConfirmTransaction(connection, tx, [payer], { commitment: "finalized",});Timing
Verity verifies the transaction at finalized commitment. Network confirmation
can take time; a client timeout does not prove the purchase failed.
- Wait for
finalizedyourself before calling this endpoint. - Set your HTTP timeout to at least 30 seconds. This is not a fast call.
409 TX_NOT_FOUNDmeans "not visible yet, retry", not "invalid".
Two 200 outcomes
replayed: false — tickets issued now. replayed: true — this signature was
already issued and you are receiving the original result. Both are successes.
Retry only with the same signature, raffle, quantity and buyer. A changed purchase identity returns IDEMPOTENCY_KEY_REUSED. Do not send this payment through the checkout API as well.
PartnerApiKeyAuthorizationBearer <token>Authorization: Bearer <your_api_key>
Keep this credential on your server, never in browser or mobile app code.
A missing, invalid or disabled key returns 401 PLATFORM_KEY_INVALID.
Ask Verity to replace a lost or exposed key.
raffleId*integer1 <= valueapplication/json- body
tx_signature*stringBase58 signature of the finalized USDC transfer. This doubles as the
idempotency key — do not send an Idempotency-Key header.
^[1-9A-HJ-NP-Za-km-z]+$64 <= length <= 88external_user_ref*stringYour stable, unique, permanent id for this buyer — it is their identity for tickets, winning, buyback and refunds. A Rarible user id is ideal; an email or display name is not.
No leading or trailing whitespace: "alice" and " alice" would otherwise
collide onto one memo but two different users.
^\S(.*\S)?$1 <= length <= 255display_name?|Optional. Shown on public leaderboards.
length <= 64qty*integerThe paid amount must equal ticket_price_usd × qty exactly.
1 <= value <= 1000Tickets issued, or replayed from a previous identical request.
application/json- response
success*booleandata*curl -X POST 'https://api-staging.theverity.xyz/api/v1/platform/raffles/77/tickets' \ -H 'Authorization: Bearer <your_partner_api_key>' \ -H 'Content-Type: application/json' \ -d '{ "tx_signature": "5NxJZ8bTqf9vK2mR7wYpL4dHnQ3sXcV6aB1eG8tU9yWfM2kPjR5hN7xC4vD6zA3bQ8sT1mL9pK2wY7nH4gF6", "external_user_ref": "usr_8812", "display_name": "alice", "qty": 5}'{ "success": true, "data": { "purchase_id": 9134, "raffle_id": 77, "qty": 5, "total_usd": 250, "tickets": [ "R077-T00410", "R077-T00411", "R077-T00412", "R077-T00413", "R077-T00414" ], "replayed": false }}