Top-Up and Recharge System
The OmniCRM Top-Up system provides a self-service prepaid recharge portal for customers to add credit or extend service validity via the Self-Care Portal . This feature is commonly used for:
- Mobile data services - Prepaid SIM cards and data-only services
- Hotspot services - WiFi hotspot dongles and portable internet devices
- Fixed wireless services - Prepaid internet access
Overview
The top-up system allows customers to purchase additional days of service through a streamlined, multi-step checkout process with integrated Stripe payment processing.
Key Features:
- Self-service customer portal (no staff intervention required)
- Flexible duration selection (1-30 days)
- Real-time usage display before purchase
- Stripe-powered secure payment processing
- Automatic refunds if top-up fails
- Invoice and transaction generation
- Provisioning system integration for service activation
Access the Top-Up Portal
The top-up portal is accessed via a public URL that customers can visit without logging into the CRM:
How Customers Access It:
- Direct link sent via SMS when balance is low
- QR code on printed materials
- Link on self-care portal
- Shared via customer support
The portal automatically detects the customer's service based on their requesting IP address or IMSI.
Top-Up Process
The top-up flow consists of 4 steps:
Step 1: Data Selection
Customers select how many days of service they want to purchase.
Interface:
- Slider control - Select 1 to 30 days
- Live price calculation - Shows total cost based on selection
- Expiry date display - Calculates and shows when service will expire
- Current usage display - Shows remaining balance/expiry before top-up
Example Display:
Pricing Configuration:
- Price per day is configured via environment variable
REACT_APP_TOPUP_PRICE_PER_DAY - Default: $10 USD per day
- Currency is set via
REACT_APP_CURRENCY_CODE
Step 2: Billing Information
Customers provide their contact details for the transaction:
- First Name
- Last Name
- Email Address
This information is used for:
- Invoice generation
- Payment receipt email
- Transaction records
- Refund processing (if needed)
Step 3: Payment
Secure payment processing via Stripe Elements.
Payment Methods Supported:
- Credit cards (Visa, Mastercard, Amex)
- Debit cards
- Digital wallets (Apple Pay, Google Pay) if enabled in Stripe
Security Features:
- PCI-compliant Stripe integration
- No card details stored in OmniCRM
- 3D Secure authentication support
- Encrypted payment transmission
Payment Flow:
- Stripe Elements form displayed with card input
- Customer enters payment details
- Payment Intent created for the exact amount
- Card charged immediately
- Payment success/failure handled
::: note ::: title Note :::
If the payment succeeds but the top-up provisioning fails (e.g., network error, OCS unreachable), the system automatically initiates a full refund to the customer's payment method. :::
Step 4: Completion
Success Screen:
Your service has been extended. New expiry date: 17 Jan 2025
Receipt sent to: <customer@example.com> Transaction ID: TXN-123456
Failure Screen:
If top-up fails, the system displays an error and automatically processes a refund:
We were unable to complete your top-up. Your payment has been refunded.
Error: Unable to connect to billing system
Please try again or contact support.
Backend Processing
When a customer completes payment, the following happens automatically:
1. Payment Validation
The system validates:
- Payment Intent status is
succeeded - Payment amount matches selected days (
days × price_per_day) - Payment Intent hasn't been processed before (prevents double top-up)
2. Top-Up Operation
- API endpoint: POST /oam/topup_dongle
- Validates service_uuid and IMSI
- Calls OCS/CGRateS to add balance
- Creates provisioning job (play_topup_hotspot)
3. Record Creation
The system creates multiple database records:
- HotspotTopup record - Tracks the top-up transaction
- payment_intent_id
- service_uuid
- imsi
- days purchased
- topup_amount
- status (Success/Failed/Refunded)
- Transaction record - Financial transaction
- Title: "Hotspot Topup - 7 Days"
- Amount: topup_amount (positive)
- Linked to service_id and customer_id
- Invoice record - Payment invoice
- Contains the top-up transaction
- Marked as paid immediately
- Payment reference: Stripe payment_intent_id
- Payment transaction - Offsetting credit transaction
- Title: "Payment for [Invoice Title]"
- Amount: topup_amount (negative - credit)
- Links invoice payment to customer account
4. Provisioning Job
A provisioning job is created with playbook play_topup_hotspot which:
- Connects to OCS/CGRateS API
- Adds balance to the account
- Extends expiry date
- Creates activity log entry
- Sends confirmation notification (if configured)
The API waits for provisioning to complete (polling with 0.2s intervals, max 25 iterations) before returning success to the customer.
5. Automatic Refund on Failure
If any step fails after payment:
if topup_provisioning_failed:
refund = stripe.Refund.create(
payment_intent=payment_intent_id,
reason='requested_by_customer' # Automatic system refund
)
status_message = "Topup Failed. Refunding payment..."
The refund is processed automatically and the customer is notified on-screen.
API Endpoints
Top-Up Endpoint
POST /oam/topup_dongle
Content-Type: application/json
{
"service_uuid": "123e4567-e89b-12d3-a456-426614174000",
"imsi": "310120123456789",
"days": 7,
"payment_intent_id": "pi_1234567890abcdef",
"topup_amount": 70.00
}
Response (Success):
{
"result": "OK",
"status": 200,
"provision_id": 456,
"payment_intent_id": "pi_1234567890abcdef",
"service_uuid": "123e4567-e89b-12d3-a456-426614174000",
"invoice_id": 789
}
Response (Failure):
{
"result": "Failed",
"Reason": "OCS connection timeout",
"status": 500
}
Validation Checks:
- All required fields present (service_uuid, imsi, days, payment_intent_id, topup_amount)
- topup_amount matches days:
topup_amount × 100 == days × 1000(in cents) - Payment Intent exists in Stripe
- Payment Intent amount matches:
payment_intent.amount == topup_amount × 100 - Payment Intent status is
succeeded - Payment Intent not already processed (checks
HotspotTopuptable)
Usage Endpoint
Retrieves current usage and service information for the customer:
GET /oam/usage
Response:
{
"imsi": "310120123456789",
"service": {
"service_uuid": "123e4567-e89b-12d3-a456-426614174000",
"service_name": "Mobile Data - 0412345678",
"service_status": "Active"
},
"balance": {
"expiry": "2025-01-10T23:59:59Z",
"unlimited": true
},
"requestingIp": "203.0.113.45"
}
This endpoint uses the requesting IP address to identify the customer's service automatically.
Configuration
Environment Variables
Configure these in the OmniCRM-UI .env file:
# Top-Up Portal Configuration
REACT_APP_TOPUP_PRICE_PER_DAY=10
REACT_APP_CURRENCY_CODE=AUD
REACT_APP_SELF_CARE_NAME="YourCompany"
# Stripe Configuration
REACT_APP_STRIPE_PUBLISHABLE_KEY=pk_live_...
Stripe Configuration
The top-up system uses Stripe Payment Intents:
- Enable Payment Intents in your Stripe Dashboard
- Configure Webhook to receive payment status updates (optional but recommended)
- Set up payment methods (cards, wallets, etc.)
- Test mode - Use test keys for development
# Development
REACT_APP_STRIPE_PUBLISHABLE_KEY=pk_test_...
# Production
REACT_APP_STRIPE_PUBLISHABLE_KEY=pk_live_...
Playbook Configuration
The provisioning playbook play_topup_hotspot.yaml must be configured
to:
- Accept
daysvariable - Connect to OCS/CGRateS API
- Add balance to account
- Update service expiry date
Example playbook structure:
- name: Top up hotspot service
hosts: localhost
tasks:
- name: Add balance to OCS
uri:
url: "{{ ocs_api_url }}/add_balance"
method: POST
body:
imsi: "{{ imsi }}"
days: "{{ days }}"
service_uuid: "{{ service_uuid }}"
Low Balance Notifications
The system can send automatic notifications when customer balance is low:
SMS Notifications:
When triggered by OCS events (Action_Balance_Low,
Action_Balance_Out, Action_Balance_Expired):
Email Notifications:
Configured in the OCS/CGRateS action plans to send balance alerts.
Notification Triggers:
Action_Balance_Low- Balance below threshold (e.g., 2 days remaining)Action_Balance_Out- Balance exhaustedAction_Balance_Expired- Service expired
Each notification includes the top-up portal link for easy customer access.
Troubleshooting
Common Issues
"Payment system unavailable"
- Cause: Stripe library failed to load or invalid publishable key
- Fix:
- Check
REACT_APP_STRIPE_PUBLISHABLE_KEYis set correctly - Verify Stripe account is active
- Check browser console for JavaScript errors
- Check
"Top-up failed. Refunding payment..."
- Cause: Provisioning job failed (OCS unreachable, playbook error, etc.)
- Fix:
- Check provisioning logs:
GET /crm/provision/provision_id/<id> - Verify OCS/CGRateS API is accessible
- Review playbook
play_topup_hotspot.yamlfor errors - Check Ansible logs
- Check provisioning logs:
"Payment intent already processed"
- Cause: Customer attempting to reuse same payment (e.g., refresh after success)
- Fix: This is working as designed to prevent double billing. Customer should start a new top-up if needed.
"Payment intent amount does not match"
- Cause: Mismatch between UI calculation and backend validation
- Fix:
- Verify
REACT_APP_TOPUP_PRICE_PER_DAYmatches backend expectation (default $10) - Check currency configuration is consistent
- Clear browser cache and retry
- Verify
Monitoring Top-Ups
View Top-Up Records:
Query the HotspotTopup table to see all top-up attempts:
SELECT
hotspot_topup_id,
service_uuid,
days,
topup_amount,
status,
payment_intent_id,
created
FROM hotspot_topup
WHERE status = 'Failed'
ORDER BY created DESC;
Check Provisioning Status:
GET /crm/provision/provision_id/<provision_id>
Shows the detailed status of the top-up provisioning job.
Stripe Dashboard:
Monitor payments, refunds, and failed transactions in your Stripe Dashboard at <https://dashboard.stripe.com>
Security Considerations
Payment Security:
- All card data handled by Stripe (PCI Level 1 compliant)
- No sensitive payment data stored in OmniCRM database
- Payment Intents prevent unauthorized charges
- Amount validation on both client and server side
Fraud Prevention:
- Duplicate payment Intent detection prevents double billing
- IP address tracking for usage correlation
- IMSI validation ensures top-up goes to correct service
- Automatic refunds limit financial exposure
Access Control:
- Top-up portal is public (by design - customers need access)
- Usage endpoint requires valid service identification (IP or IMSI)
- Backend validation prevents arbitrary service top-ups
- Admin can view all top-up records via CRM interface
Best Practices
For Operators:
- Test refund flow - Regularly test failure scenarios to ensure refunds work
- Monitor failed top-ups - Set up alerts for high failure rates
- Keep playbooks simple - Top-up playbooks should be fast and reliable
- Verify OCS connectivity - Ensure OCS API is always accessible
- Review pricing - Update
REACT_APP_TOPUP_PRICE_PER_DAYas needed
For Customers:
- Bookmark the top-up URL - Quick access when needed
- Save low balance notifications - SMS contains direct link
- Keep email updated - Receipts sent to email on file
- Check expiry before travel - Top up before leaving coverage area
For Developers:
- Handle Stripe webhooks - Implement webhook handlers for payment status updates
- Implement idempotency - Always check payment_intent_id before processing
- Log extensively - Top-up failures need detailed troubleshooting info
- Test error paths - Verify refund automation works correctly
- Monitor performance - Provisioning polling should complete in <5 seconds
Related Documentation
payments_process- General payment processingconcepts_provisioning- Provisioning system overviewintegrations_stripe- Stripe integration detailspayments_transaction- Transaction managementpayments_invoices- Invoice handling