zuuppaDEV
Swift SDK

In-app wallet payments

If your app holds its own crypto keys (i.e. it is a wallet), you can let buyers pay for tickets with a single tap — no QR codes, no copy-pasting an address. You supply one closure; the SDK calls it with the exact payment details, your wallet signs and submits the transfer, and the SDK confirms the payment on-chain.

This is entirely optional and additive. When you provide a handler, a “Pay with app wallet” button appears on the ticket-selection screen for crypto-enabled events, alongside the built-in card and QR options.

1. Provide the handler

Pass onWalletPayment to the tickets screen or modifier:

SwiftUI
.zuuppaTickets(
    isPresented: $showTickets,
    eventId: "your-event-uuid",
    onWalletPayment: { request in
        // Send EXACTLY request.amountBaseUnits of the token
        // to request.depositAddress on request.chain ("solana").
        //
        // request.tokenMint == nil  -> native SOL
        // request.tokenMint != nil  -> SPL token at that mint
        let signature = try await myWallet.sendTransfer(
            to: request.depositAddress,
            amountBaseUnits: request.amountBaseUnits,
            mint: request.tokenMint
        )
        return signature   // display-only; return nil if unavailable
    }
)

2. What happens next

As soon as the buyer taps Pay with app wallet, the SDK shows a processing screen and, in the background:

  1. Creates the order and gets a unique per-order deposit address.
  2. Calls your handler with a ZuuppaCryptoPaymentRequest.
  3. Polls the backend until the payment is confirmed on-chain.
  4. Advances to the confirmation screen — tickets are issued to the buyer.
Your handler must send exactly request.amountBaseUnits to request.depositAddress. No memo or reference is required — the backend matches the payment purely by the unique deposit address.

The request object

swift
public struct ZuuppaCryptoPaymentRequest: Sendable, Equatable {
    public let orderID: String        // Zuuppa order id (your records/logging)
    public let chain: String          // currently always "solana"
    public let token: String          // display symbol, e.g. "SOL" / "USDC"
    public let tokenMint: String?     // SPL mint base58; nil = native SOL
    public let decimals: Int          // token decimals
    public let amountBaseUnits: String // EXACT amount, integer string, base units
    public let depositAddress: String  // where to send the funds
}
ParameterTypeDescription
orderIDStringThe Zuuppa order id, for your own records and logging. Not sent on-chain.
chainStringThe chain to pay on. Currently always "solana".
tokenStringDisplay symbol only (e.g. "SOL", "USDC").
tokenMintString?Base58 SPL mint address, or nil for native SOL.
decimalsIntToken decimals, for interpreting amountBaseUnits.
amountBaseUnitsStringThe exact amount to send, as an integer string in the token's base units.
depositAddressStringThe unique per-order destination address. Send the funds here.

The handler type

swift
public typealias ZuuppaWalletPaymentHandler =
    @Sendable (ZuuppaCryptoPaymentRequest) async throws -> String?
  • Return value: an optional transaction signature/hash. This is display-only and never sent to Zuuppa — the backend confirms by watching the deposit address. Return nil if a signature isn’t available.
  • Throwing: throw if the wallet fails or the buyer cancels. The SDK treats this as “payment not completed” and returns the buyer to ticket selection so they can retry or choose another method.
The handler is @Sendable and async. Do your signing and network submission inside it and simply return once the transfer is broadcast — you don’t need to wait for on-chain confirmation, the SDK polls for that.

Next

→ Configuration