DevCareer x Nomba Hackathon

TicketPay

Campus transport, paid instantly.

Welcome to the evaluation panel for TicketPay. Below is the sandbox portal directory, pitch documentation, credentials, and walkthrough steps to audit the system.

The Problem

Friction in Campus Transport

Every day, thousands of students at Obafemi Awolowo University (OAU) rely on campus shuttles and buses. Yet, payments remain stuck in the past: physical paper tickets bought in advance and handed to drivers who manage moving vehicles while handling paper slips simultaneously.

  • Students: Need to buy paper tickets beforehand, cannot track transport spending, and have no digital proof of rides.
  • Drivers: Waste transit time collecting and tearing paper slips, face ticket fraud or loss, and struggle to manually reconcile earnings.
  • Guestimate & OAU Body: Zero real-time visibility into ridership stats, fleet performance, or total revenue.
OAU has already experienced student boycotts due to transport system inefficiencies.
The Solution

Digital Transit Ticketing Layer

TicketPay replaces physical paper tickets with driver-displayed QR codes backed by secure student digital wallets settled in real-time. No new hardware, no complex behavior change. Just the same ride, paid digitally.

1
Instant Nomba Accounts

Students get a dedicated virtual account on sign-up to fund their wallets instantly via bank transfers.

2
Driver QR Display

Drivers generate a unique ride QR code (or display a static route QR card) representing the fare.

3
Scan & Payout

Students scan the driver's QR code via the student web app, instantly transferring the fare from their wallet to the driver.

Why This, Why Now?

Infrastructure Ready

Powered by Nomba's robust APIs. We plug directly into live virtual account rails and HMAC-verified webhooks without bank overhead.

Institutional Buy-In

Directly aligned with Guestimate and OAU Office of Student Affairs. Pilot agreements and payment service terms are already drafted.

Proven Demand Signal

The recent transport strike proves the campus is actively seeking a resolution to current ticketing and payment problems.

Edge Cases Solved

Raspberry Pi Zero 2W kiosk designed for non-smartphone drivers ensures 100% digital, paperless coverage across the entire fleet.

Business Model & Pilot

TicketPay sits in the flow of existing transport spend, monetizing transaction efficiency:

  • Micro-transaction fees on wallet-funded rides.
  • SaaS platforms for campus analytics and fleet tooling.
  • Non-exclusive terms with Guestimate to expand to other universities.
The Ask: Pilot Launch

We are seeking to activate our drafted agreement with Guestimate into a live campus pilot on designated routes.

Team & Traction

Status: Sandbox product complete (student wallet, driver scan page, admin dashboard). Endorsement letters and OAU Student Affairs briefs ready.

Founded by Builders

Built by a 3rd-year OAU Industrial Chemistry student with a full-stack engineering background, alongside a CS/Engineering co-founder.

School Feedback: Offline NFC Cards

To address concerns raised by school management regarding campus network stability, we are proactively expanding our roadmap to support **NFC-enabled physical cards** for offline ride validation. This turns connectivity constraints into an opportunity for greater inclusion.

System Architecture & Data Flow

How TicketPay bridges students, drivers, the OAU transport body, and Nomba's API infrastructure:

1. Student Onboarding

Student signs up. Express backend calls Nomba API to provision a dedicated Virtual Account.

Nomba Account API
2. Instant Funding

Student transfers funds to Virtual Account. Nomba triggers an HMAC-SHA256 verified webhook to credit wallet.

HMAC Webhooks
3. Fare Payment

Driver displays unique QR code. Student scans driver's QR code from their mobile web app to authorize and deduct fare instantly.

Client Scan Payment
4. Fleet Analytics

Admin console monitors ridership metrics, updates fares, and tracks active driver earnings logs.

Admin console

Evaluator Portal Directory

Student Web Portal

Register, fund wallets via instant Nomba virtual accounts, scan driver ride QR codes to pay, and review transaction history.

Driver mobile-first Portal

Track earnings real-time (30s auto-refresh), view transaction feeds, generate QR codes, and resolve student disputes.

Admin Management System

Register campus drivers, monitor analytics, update ticket pricing, and download QR transit pass cards.

Sandbox Testing Credentials

Admin Access

Super Admin Credentials

Use this to log into the Admin portal to manage drivers and view analytical stats.

URL
admin.ticketpay.com.ng
Username
admin
Password
password
Driver Access

Driver Authentication

To test a driver account, create a new driver in the Admin panel. The system will automatically return a Driver Code and a temporary password once.

URL
ticketpay.com.ng/driver/login
Driver Code Generated by Admin (e.g. DRV001)
Password Displayed once upon creation

Step-by-Step Testing Flow

1

Admin Setup: Register a Driver

Log into the Admin Panel using the credentials above. Navigate to Driver Management, register a new driver, and copy the generated Driver Code and temporary password. You can also print or download their QR transit ID card here.

2

Student Registration & Onboarding

Open the Student Web Portal and sign up with any email address. Complete the verification block (OTP sent via Resend/Mailtrap integration) to activate the student profile and gain access to the dashboard.

3

Wallet Funding (Nomba Virtual Account)

Upon registration, a unique Nomba Virtual Account is instantly provisioned and displayed in the student's wallet card. Copy this account number and make a simulated transfer (or trigger a simulated webhook repush) to verify the instant real-time credit.

4

Driver Displays Ride QR

In a separate/incognito tab, open the Driver Portal and log in using the Driver Code and temporary password. The driver portal generates and displays a unique QR code representing the transit route fare.

5

Student Scans QR to Pay

Return to the Student Web Portal. Click the **Scan Ride** button to open the device camera and scan the driver's displayed QR code. The fare is debited from the student's wallet and credited to the driver instantly.

6

Admin Audit & Analytics

Return to the Admin Panel. You can immediately see the transaction recorded in the real-time activity log, check update statistics on the analytics charts, and monitor overall active driver earnings across the campus network.

Nomba API Integration Highlights

Instant Provisioning on Sign-Up

We integrated Nomba's Virtual Account API so that every student gets a personal bank account numbers linked directly to their TicketPay wallet during onboarding. No manuals deposits required.

// Virtual Account Generation Flow
const result = await axios.post(`${NOMBA_BASE_URL}/v1/virtual-accounts/{SUB_ACCOUNT_ID}`, {
    accountRef: `TP-${uuidv4()}`,
    accountName: studentFullName,
    ...
});

HMAC-SHA256 Webhook Cryptographic Validation

We engineered signature verification to validate requests sent to /api/wallets/webhook/nomba using Nomba's custom colon-delimited parameters rather than raw body strings, protected by crypto.timingSafeEqual.

// Signature calculation
const hashingPayload = `${eventType}:${requestId}:${userId}:${walletId}:${transactionId}:${transactionType}:${transactionTime}:${transactionResponseCode}:${timestamp}`;
const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET);
const expectedSignature = hmac.update(hashingPayload).digest('base64');
const isValid = crypto.timingSafeEqual(Buffer.from(sig, 'base64'), Buffer.from(expectedSignature, 'base64'));

Redis-backed Token Rotation Strategy

Nomba tokens expire every 30 minutes. To prevent API rate limits and token expirations, we implemented a dual-key cache in Redis. The active token expires in 25 minutes, triggering background renewal using the refresh_token grant before the absolute expiration.

// Redis Cache & Expiry Check
const cachedToken = await redis.get("nomba:access_token");
if (!cachedToken) {
    const expiredToken = await redis.get("nomba:expired_access_token");
    const refresh = await redis.get("nomba:refresh_token");
    // Call Nomba /v1/auth/token/refresh using refresh_token...
}