
PNTSH is a Laravel 12 API powering a group-based contributions product. It supports group creation and membership, invite flows, fee creation, member payments via Paystack, and owner withdrawals with OTP-verified payout accounts — with notifications delivered via email and push.
My Role
Backend Developer
Duration
2026
Context
Backend API Project
Outcome
Group invites + fee payments · Paystack verification webhooks · OTP-verified withdrawals
Stack
Context
Group contributions need simple, reliable flows: create a group, invite members, collect payments, and let owners withdraw funds safely — all while keeping accounting accurate.
The Pain
Without strong payment verification, idempotent callbacks, and safe withdrawal controls, financial flows become inconsistent and risky. Small edge cases (duplicate webhooks, partial payments, unverified payout accounts) cause big issues.
Why It Mattered
Payments must be trustworthy and auditable. Users need confidence that their contributions are recorded correctly, and group owners need safe withdrawals with clear checks and balances.
Technical Goals
Constraints
A layered Laravel API (routes → controllers → services → Eloquent/MySQL) with dedicated modules for groups, invites, fees, payments, withdrawals, and notifications. Payments and withdrawals integrate with Paystack, payout account verification uses Hubtel SMS OTP, and notifications fan out to email + Firebase FCM.

Scroll horizontally on smaller screens to view full diagram
Auth (Laravel Sanctum)
Secures API access for mobile clients and admins.
Groups & Membership
Group creation, membership joins, and ownership permissions.
Invites
Direct invites and invite links for onboarding members into groups.
Fees
Fee lifecycle (create, active/closed) and aggregate totals for collection/withdrawal.
Payments (Paystack)
Initialize and verify fee payments and record durable payment state transitions.
Withdrawals + Payout Accounts
OTP verification for payout accounts and Paystack transfers for withdrawals.
Notification Service
Triggers push notifications (FCM) and email updates for key events.
Admin Panel (Filament)
Operational visibility and moderation of groups, fees, payments, and withdrawals.
MySQL
Primary datastore for users, groups, fees, payments, and withdrawals.
→Service layer for business logic
Keeps controllers thin and concentrates payment/withdrawal rules in testable, reusable services.
→Webhook verification + idempotency mindset
Paystack can retry events; the API must safely handle duplicate callbacks without double-counting payments.
→OTP for withdrawal account verification
Withdrawals are high-risk; requiring OTP via SMS reduces fraud and prevents misdirected payouts.
→Filament for admin tooling
Accelerates internal dashboards and operations without building a separate admin frontend.
API routes are organized around the product’s core modules (groups, invites, fees, payments, withdrawals).
flowchart TB
subgraph LaravelAPI[Laravel API]
auth[Auth & Sanctum]
groups[Groups & Membership]
invites[Invites/Invite Links]
fees[Group Fees]
payments[Payments]
withdrawals[Withdrawals]
notify[Notification Service]
adminc[Admin/Filament Modules]
end
db[(MySQL)]
paystack[Paystack]
hubtel[Hubtel SMS]
fcm[Firebase]
mail[SMTP]
auth --> db
groups --> db
invites --> db
fees --> db
payments --> db
withdrawals --> db
adminc --> db
payments --> paystack
withdrawals --> paystack
withdrawals --> hubtel
notify --> fcm
notify --> mailPayments are created as PENDING, verified against Paystack, then finalized with consistent DB updates.
sequenceDiagram
participant U as User (Member)
participant API as Laravel API
participant Pay as Paystack
participant DB as Database
participant O as Group Owner
U->>API: POST /groups/{groupId}/fees/{feeId}/pay
API->>DB: Create/Update payment (PENDING, reference)
API->>Pay: Initialize transaction
Pay-->>API: authorization_url
API-->>U: payment link/reference
Pay-->>API: Webhook charge.success
API->>Pay: Verify transaction
Pay-->>API: success
API->>DB: Update payment=SUCCESS, paid_at
API->>DB: Update fee totals (total_collected, total_paid_members)
O->>API: POST /withdrawal/request-otp
API->>O: OTP sent (Hubtel SMS)
O->>API: POST /withdrawal/verify-otp
API->>Pay: Create transfer recipient
API->>DB: Save withdrawal_account(recipient_code)
O->>API: POST /group/{groupId}/fee/{feeId}/withdraw-funds
API->>DB: Validate owner, closed fee, available amount
API->>Pay: Transfer funds
Pay-->>API: transfer reference/status
API->>DB: Insert group_withdrawals
API->>DB: Increment group_fees.total_withdrawn (on success)
API-->>O: Withdrawal resultWithdrawals validate ownership, fee closure rules, and available balance before initiating a transfer.
Event-driven notifications keep members informed about invites, fees, payments, and withdrawals.
The Problem
Payment providers may send duplicate webhooks, and users may retry checkout. Without protections, totals can drift.
The Fix
Model payments as a state machine (PENDING → SUCCESS/FAILED) and verify against Paystack before finalizing. Treat webhook handling as idempotent and only apply fee total updates once per reference.
The Problem
Allowing withdrawals without strong verification can lead to misdirected funds or fraud.
The Fix
Require OTP verification (Hubtel SMS) to create/activate a payout recipient, then perform Paystack transfers only for verified accounts.
A complete backend foundation for group contributions with reliable payment verification and safe withdrawal flows.
Before → After
Payment verification
Withdrawal safety
Operations
Business Outcome
Members can pay fees confidently, owners can withdraw safely, and admins can monitor activity with clear records for support and auditing.
Would Do Differently
Key Takeaways
Next Project
Full-Stack Engineering
