Multi-Carrier Bulk SIM Activation Platform
Turning a 20-carrier activation maze into one bulk-upload dealer workflow.
Wireless dealers and distributors needed to activate SIMs and eSIMs across a dozen-plus disparate carrier and MVNO backends one line at a time; I built a bulk CSV-driven activation engine inside the existing CelleUp dealer platform that validates multi-tier dealer funds, routes each row to the correct carrier API, processes activations asynchronously with retries, and streams live progress back to the dealer.
Client
Ayaz
Founder, Company
Role
Lead Backend Engineer (Laravel)
Year
2026
Category
Telecom · MVNO Platform · Dealer POS
Confidential Enterprise Project (Protected Under NDA)
Proprietary source code, database architectures, and internal endpoint credentials are confidential. This case study highlights non-proprietary architectural patterns, technical solutions, and verified outcomes.
Executive Overview & The Problem#
CelleUp is an established wholesale/retail wireless distribution back office: a Super Admin → Distributor → Dealer/Store → Sales Rep hierarchy that already handled single-line activations, point-of-sale transactions, device leasing/financing, and reporting across a long list of carrier and payment integrations (T-Mobile, AireSpring, Surge, PrepaidIQ, Emida, CellPay, Bitrefill, Acima, and more - each with its own bespoke Service class).
As MVNO and prepaid volume grew, dealers and kiosks needed to activate SIMs in bulk - dozens or hundreds of lines in a single sitting, or migrate a batch of existing customers as part of a SIM-swap campaign - rather than one line at a time through the existing single-activation screens. The obstacle was that every carrier speaks a different language: T-Mobile, Rogue Mobile and Nexio Mobile each have distinct plan-code and inventory rules, while a separate Nexus/ISPWN wholesale layer exposes a full GSMA/GSMT porting, SIM, and eSIM lifecycle (port add/status/MDN-change, SIM add/suspend/reconnect/plan-change, eSIM download/confirm/QR) behind yet another auth scheme. Years of incremental, carrier-by-carrier scripting (two multi-thousand-line Helper classes) meant there was no unified way to say "activate these 500 SIMs" without hand-rolling the logic per carrier every time. Getting this wrong is expensive in both directions: a botched bulk activation either burns non-refundable wholesale SIM cost or leaves a customer without service, and any new workflow had to keep the platform's multi-tenant wallet accounting (distributor funds a dealer, a dealer funds its own store) correct under concurrent, long-running jobs.
Architectural Approach & System Design#
Provider abstraction. Each upstream carrier/MVNO gets its own Service class (NexusService, ISPWNService, RogueMobileService, NexioMobileService, and siblings for the platform's other integrations). NexusService handles bearer-token login/refresh plus bulk-activation submission and batch-status polling; ISPWNService switches between sandbox and production credential sets and exposes the full port/SIM/eSIM lifecycle as discrete methods (portsAdd, simsChangePlan, simsSuspend, simsGetEsim, etc.). Each service normalizes a differently-shaped upstream response into one internal activation result, so the rest of the application never has to know which carrier it's talking to.
Data model. The platform uses a star-schema-style Laravel/MySQL layer (dimension/fact table naming) for accounts, dealers, distributors, products, carriers, and transactions. SwapPad's own tables - SwappadProduct, StoreSwappadProduct, SimBank, ISPActivationBatch/ISPActivation - were added on top of that existing schema rather than requiring a rewrite, so the new bulk-activation product line inherits the platform's existing reporting and billing views.
Bulk pipeline. A dealer uploads a CSV; the header shape is auto-detected (ICCID + ZipCode, or ZipCode + Quantity), then a provider-specific preflight runs before anything is charged - for example, Nexio Mobile activations are checked against zip-level plan-code coverage up front so a bad row fails the whole batch atomically instead of charging and refunding after the carrier rejects it. Funds are then validated up the wallet chain (distributor → dealer → store) before the batch is persisted to ISPActivationBatch and handed to ProcessSwapPadBatchJob, a queued job (2-hour timeout, since some carrier sandboxes are slow) that activates each row against the right carrier, updates row-level status, and records the cost split for each tier.
Real-time feedback. Rather than have the dealer's browser poll for status, a Server-Sent-Events endpoint (streamStatus) watches the batch record every two seconds and pushes completed / failed / total counters directly to the UI, closing automatically once the batch finishes, fails, or a 5-minute connection cap is hit.
Access control & tenancy. Spatie laravel-permission plus a custom Distributor/Dealer/Team role hierarchy scope what each tier can see and act on - a distributor can view every batch beneath it; a dealer sees only its own.
Reporting & ops. Yajra DataTables-driven transaction views, PDF export via DomPDF, Excel export of batch results, Slack alerting on failures, and scheduled Artisan commands reconcile status with each carrier independently of the request/response cycle.
Key Technical Challenges & Solutions#
1. Reconciling incompatible carrier semantics inside one CSV workflow. Some carriers need an ICCID+ZIP pair per row; Nexio Mobile needs ZIP+quantity and a hard check that inventory exists for that zip before anything is charged. Solved with header-based CSV shape detection plus a dedicated preflight step (performNexioPreflight) that validates provider-specific constraints and fails the entire batch before any wallet hold is placed - avoiding a charge/refund dance when a downstream API would have rejected the row anyway.
2. Keeping multi-tier wallet accounting correct across long, asynchronous jobs. A single batch can run for up to two hours against rate-limited carrier sandboxes, and cost has to land on the right tier (distributor-funded vs. self-funded store) without double-charging on retry. Solved by holding the full estimated charge at submission time (calculateTotalStoreChargeForCsv / calculateTotalDistributorChargeForCsv) and reconciling actual per-row cost as the queue worker completes each activation, with a separate retryBatch path that only re-submits the rows that actually failed.
3. Giving dealers live visibility into a long-running batch without overloading the server. Implemented an SSE stream instead of client-side polling, with a bounded connection lifetime and automatic close-on-completion, so a dealer watching a 500-row activation gets sub-2-second updates without generating hundreds of redundant HTTP requests.
Results & Business Impact#
- Replaced manual, one-line-at-a-time carrier activation with a single CSV-driven bulk workflow spanning T-Mobile, Rogue Mobile, Nexio Mobile, and the Nexus/ISPWN wholesale MVNO layer (porting, new SIM, eSIM, plan changes, suspend/reconnect) behind one dealer-facing screen.
- Extended a years-old, single-carrier-at-a-time back office with an entirely new bulk-activation product line without a schema rewrite, by layering new tables cleanly onto the existing dimensional model.
- Gave distributors and dealers real-time batch visibility and self-service retry, reducing reliance on support tickets to find out whether a bulk order went through.
- Preserved the platform's existing multi-tier wallet/commission model across the new bulk path, so distributor → dealer → store accounting stayed correct without standing up a parallel billing system.
Gallery









Tech stack
Timeline & Milestones
Schema & Provider Extension
(Q2 2026)Designed Product/SimBank/ISPActivationBatch tables and the carrier-service abstraction layered onto the existing CelleUp data model
Multi-Tenant Hierarchy & Permissions
(Jul 2026)Added the distributor role, Spatie-based permission tables, and cost/price history tracking across the dealer hierarchy
Bulk Activation Engine & Live Status
(Aug–Sep 2026)Built the CSV bulk-activation pipeline, queued batch processing, SSE progress streaming, and carrier-specific preflight validation
Stabilization & Hardening
(Sep 2026)Ongoing fixes to activation edge cases, SIM bank availability, T-Mobile quantity-based processing, product/pricing corrections
Outcomes & Impact
4+ carriers unified
Provider Coverage
T-Mobile, Rogue Mobile, Nexio Mobile and the Nexus/ISPWN wholesale MVNO layer routed through one bulk activation workflow
One-by-one → CSV batch
Activation Model
Replaced manual single-line activation with CSV upload, provider-aware preflight validation, and queued batch processing
Polling → live SSE stream
Visibility
Real-time completed/failed/total counters pushed to the dealer UI as each row activates, instead of manual refresh
3-tier wallet accounting preserved
Data Integrity
Distributor → dealer → store fund holds and cost splits stay consistent across long-running async batches with row-level retry
Technical Insights
Related Architecture & Engineering Articles

Laravel Queue Architecture: Jobs That Survive Production
dispatch() is one line. Making that job safe to retry, cheap to scale, and impossible to double-run is the actual engineering problem.

Building a Reliable Webhook Delivery System in Laravel
A webhook that fires once and hopes isn't an integration. It's a support ticket waiting to happen the first time a customer's server is down.

Redis Caching Architecture for Laravel SaaS at Scale
A cache with no invalidation story isn't a performance win. It's stale data waiting to embarrass you in front of a customer.

Building Full-Text Search in Multi-Tenant Laravel SaaS
WHERE title LIKE '%term%' works until customers expect search that's fast, relevant, and never leaks another tenant's records.