Skip to main content
GatePass supports multiple payment methods including fiat (via Paystack/Flutterwave), cryptocurrency, and mobile money (M-Pesa) to maximize accessibility for global audiences.

Overview

GatePass provides a flexible payment infrastructure that allows event organizers to accept payments through various channels, catering to different audience preferences and geographic locations.

Supported Payment Methods

Fiat Payments

Credit/debit cards via Paystack and Flutterwave

Cryptocurrency

Direct on-chain payments using MATIC or other tokens

Mobile Money

M-Pesa and other mobile payment providers

Payment Architecture

Order Model

All payments flow through the Order model which tracks payment status across different methods:
schema.prisma
model Order {
  id     String @id @default(cuid())
  
  // Payment info
  totalAmount    Float
  quantity       Int
  currency       String
  paymentMethod  String
  paymentStatus  String @default("PENDING")
  
  // Payment processor data
  stripePaymentId    String?
  coinbaseChargeId   String?
  blockchainTxHash   String?
  paystackReference  String?
  flutterwaveReference String?
  mpesaCheckoutRequestId String?
  paymentTxId        String?
  
  // Customer info
  customerEmail  String
  customerName   String?
  billingAddress String? // JSON string
  
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  // Relations
  user    User   @relation(fields: [userId], references: [id])
  userId  String
  
  event   Event  @relation(fields: [eventId], references: [id])
  eventId String
  
  tickets Ticket[]

  @@map("orders")
  @@index([paymentStatus])
}

Payment Gateway Integration

Environment Configuration

Configure payment gateway credentials in your .env file:
.env.example
# Payment gateways (required for initiating fiat checkouts)
VITE_PAYSTACK_PUBLIC_KEY=pk_test_your_paystack_key
VITE_FLUTTERWAVE_PUBLIC_KEY=FLWPUBK_TEST-your_flutterwave_key

# Blockchain options used by ticketing and wallet UX
VITE_CHAIN_ID=137
VITE_RPC_URL=https://polygon-rpc.com

# Notes:
# - Paystack and Flutterwave keys are required for fiat payments from the browser.
# - If you plan to use M-Pesa, you need a server-side endpoint; the client will display a message until configured.

Payment Methods

1. Fiat Payments (Paystack & Flutterwave)

Paystack is integrated for card payments, particularly popular in Nigeria and other African countries.

Initialize Payment

router.post(
  '/initialize',
  authenticate,
  asyncHandler(async (req: AuthenticatedRequest, res: any) => {
    const { eventId, tierId, quantity, paymentMethod, gateway, customerEmail, customerName } = req.body

    // Calculate total with platform fee
    const subtotal = Number(tier.price) * quantity
    const totalAmount = calcTotal(subtotal) // Adds 2.5% platform fee
    const reference = `GP-${eventId}-${Date.now()}-${crypto.randomBytes(4).toString('hex')}`

    const order = await prisma.order.create({
      data: {
        totalAmount,
        quantity,
        currency: 'NGN',
        paymentMethod,
        paymentStatus: 'PENDING',
        customerEmail: customerEmail || req.user?.email || '[email protected]',
        customerName: customerName || req.user?.name || 'Guest',
        userId: req.user?.id || 'guest',
        eventId: eventId,
        paystackReference: reference
      }
    })

    res.json({ ok: true, orderId: order.id, reference })
  })
)
Paystack automatically handles card verification and 3D Secure authentication.

2. Cryptocurrency Payments

Direct on-chain payments using cryptocurrency wallets:
1

Connect Wallet

User connects their Web3 wallet (MetaMask, WalletConnect, etc.)
2

Approve Transaction

User approves the transaction with the exact ticket price in MATIC or configured token
3

Mint Tickets

Smart contract mints tickets directly to the user’s wallet address
4

Record Transaction

Backend records the blockchain transaction hash for verification
// Crypto payment flow
const mintTickets = async (eventContract: string, quantity: number, price: string) => {
  const contract = new ethers.Contract(eventContract, EventTicketABI, signer)
  
  const tx = await contract.mint(quantity, {
    value: ethers.parseEther(price)
  })
  
  await tx.wait()
  
  // Update order with transaction hash
  await prisma.order.update({
    where: { id: orderId },
    data: {
      paymentStatus: 'COMPLETED',
      blockchainTxHash: tx.hash
    }
  })
}
Cryptocurrency payments provide instant settlement and eliminate chargeback risk.

3. Mobile Money (M-Pesa)

M-Pesa integration for mobile-first markets in Africa:
// M-Pesa payment initialization (server-side)
const initializeMpesaPayment = async ({
  phoneNumber,
  amount,
  accountReference,
  transactionDesc
}: MpesaPaymentParams) => {
  const timestamp = new Date().toISOString().replace(/[^0-9]/g, '').slice(0, -3)
  const password = Buffer.from(
    `${MPESA_SHORTCODE}${MPESA_PASSKEY}${timestamp}`
  ).toString('base64')

  const response = await axios.post(
    'https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest',
    {
      BusinessShortCode: MPESA_SHORTCODE,
      Password: password,
      Timestamp: timestamp,
      TransactionType: 'CustomerPayBillOnline',
      Amount: amount,
      PartyA: phoneNumber,
      PartyB: MPESA_SHORTCODE,
      PhoneNumber: phoneNumber,
      CallBackURL: `${process.env.API_URL}/webhooks/mpesa`,
      AccountReference: accountReference,
      TransactionDesc: transactionDesc
    },
    {
      headers: {
        Authorization: `Bearer ${await getMpesaAccessToken()}`
      }
    }
  )

  return response.data
}

Platform Fees

GatePass applies a 2.5% platform fee on all ticket sales:
function calcTotal(amount: number) {
  const platformFee = amount * 0.025
  return Number((amount + platformFee).toFixed(2))
}
Platform fees are automatically distributed during organizer withdrawals:
EventTicket.sol
function withdraw() external onlyOwner nonReentrant {
    uint256 balance = address(this).balance;
    
    // Calculate platform fee (250 basis points = 2.5%)
    uint256 platformFee = (balance * platformFeeBps) / 10000;
    uint256 organizerAmount = balance - platformFee;

    // Transfer platform fee
    if (platformFee > 0) {
        payable(platformFeeRecipient).transfer(platformFee);
    }

    // Transfer remaining to organizer
    payable(owner()).transfer(organizerAmount);
}

Payment Status Flow

Currency Support

GatePass supports multiple currencies based on payment method and location:

NGN

Nigerian Naira for Paystack/Flutterwave

USD

US Dollar for international cards

MATIC

Polygon native token for crypto payments

KES

Kenyan Shilling for M-Pesa

ETH

Ethereum for cross-chain payments

USDC

Stablecoin for crypto payments

Webhook Handling

Handle payment confirmations from payment gateways:
webhooks.ts
router.post('/paystack', asyncHandler(async (req, res) => {
  const event = req.body
  
  // Verify webhook signature
  const hash = crypto
    .createHmac('sha512', process.env.PAYSTACK_SECRET_KEY!)
    .update(JSON.stringify(req.body))
    .digest('hex')
  
  if (hash !== req.headers['x-paystack-signature']) {
    return res.status(400).send('Invalid signature')
  }
  
  if (event.event === 'charge.success') {
    const reference = event.data.reference
    
    const order = await prisma.order.findFirst({
      where: { paystackReference: reference }
    })
    
    if (order && order.paymentStatus === 'PENDING') {
      await prisma.order.update({
        where: { id: order.id },
        data: { 
          paymentStatus: 'COMPLETED',
          paymentTxId: event.data.id
        }
      })
      
      // Mint tickets
      await mintTicketsFor(order)
    }
  }
  
  res.status(200).send('OK')
}))

Best Practices

Never trust client-side payment confirmations. Always verify transactions server-side using webhook callbacks or direct API queries.
Ensure payment webhooks are idempotent to prevent duplicate ticket minting if the same webhook is received multiple times.
Set payment expiration times (e.g., 15 minutes) to free up reserved tickets if payment is not completed.
Keep users informed about payment status through notifications and real-time UI updates.
Implement a clear refund policy and process for handling payment disputes and event cancellations.

Security Considerations

Never expose secret keys or API credentials in client-side code. All payment processing should occur server-side.

Webhook Verification

Always verify webhook signatures to ensure requests are from legitimate payment gateways

PCI Compliance

Use payment gateways’ hosted checkout pages to avoid PCI compliance requirements

Secure Storage

Never store full credit card numbers. Only store payment gateway references

Amount Validation

Always validate payment amounts server-side to prevent price manipulation

Testing

Test Credentials

# Test Public Key
pk_test_xxxxxxxxxxxxxxxxxxxxxxxx

# Test Secret Key
sk_test_xxxxxxxxxxxxxxxxxxxxxxxx

# Test Card
Card Number: 4084 0840 8408 4081
CVV: 408
Expiry: Any future date
PIN: 0000
OTP: 123456

Next Steps

Event Management

Learn how to create and configure events with different payment options

NFT Tickets

Understand how tickets are minted after successful payment

Build docs developers (and LLMs) love