Automatic Refunds
The automatic refund system detects rides that likely failed or malfunctioned and automatically refunds customers to their wallet. This helps maintain customer satisfaction when vehicles malfunction, fail to unlock properly, or have other issues that result in very short, unsuccessful rides.
How It Works
The Automatic Refund Flow
When a ride ends, the system evaluates whether it qualifies for an automatic refund:
Ride Ends
Customer ends their ride through the mobile app
Metrics Calculated
System calculates ride metrics (duration, distance, cost)
Eligibility Evaluated
System checks if ride meets refund thresholds
Job Queued
If eligible, a refund job is queued in ride_auto_refund_jobs
Delay Period
Cron job waits the configured delay (recalc_gap_minutes)
Re-evaluation
System re-evaluates with latest telemetry data
Refund Issued
If still eligible, wallet is credited and customer notified
Why the Delay?
The system waits a configurable number of minutes before processing the refund. This delay allows:
- Late-arriving telemetry data to update ride metrics
- IoT data sync to complete with final distance/duration
- Backend processing to finalize ride calculations
This prevents premature refunds based on incomplete data.
Refund Destination
Automatic refunds always go to the customer's wallet, not back to their card. This ensures instant refunds with no transaction fees, and encourages continued use of the service.
Eligibility Criteria
A ride qualifies for automatic refund when ALL of the following are true:
| Criterion | Default Value | Description |
|---|---|---|
| Feature enabled | true | Automatic refunds toggle is on in settings |
| Duration within limit | ≤ 3 minutes | Ride duration is less than or equal to max |
| Distance within limit | ≤ 200 meters | Total distance traveled is within threshold |
| Has customer | Required | Ride is linked to a valid customer |
| No duplicate job | Required | No pending/processing job exists for this ride |
| Refundable balance | Required | Ride has an amount that can be refunded |
What Gets Checked
The eligibility evaluation uses the following ride data:
- Duration in seconds
- Distance in meters
- Total cost
- Amount charged
- Payment status
Configuration
Accessing Settings
Configure automatic refunds in the admin dashboard:
- Navigate to Settings
- Click the Rides tab
- Find the Automatic Refunds section
Configuration Options
| Setting | Type | Default | Description |
|---|---|---|---|
enabled | boolean | true | Master toggle for automatic refunds |
max_ride_duration_minutes | number | 3 | Maximum ride duration to qualify |
max_total_distance_m | number | 200 | Maximum distance in meters to qualify |
recalc_gap_minutes | number | 1 | Minutes to wait before processing |
Recommended Values by Use Case
Conservative (Fewer Refunds)
Use these settings if you want to minimize automatic refunds and prefer manual review:
| Setting | Value |
|---|---|
| enabled | true |
| max_ride_duration_minutes | 2 |
| max_total_distance_m | 100 |
| recalc_gap_minutes | 2 |
Standard (Balanced)
The default settings balance customer satisfaction with operational oversight:
| Setting | Value |
|---|---|
| enabled | true |
| max_ride_duration_minutes | 3 |
| max_total_distance_m | 200 |
| recalc_gap_minutes | 1 |
Generous (More Refunds)
Use these settings for maximum customer satisfaction:
| Setting | Value |
|---|---|
| enabled | true |
| max_ride_duration_minutes | 5 |
| max_total_distance_m | 300 |
| recalc_gap_minutes | 1 |
Finding the Right Balance
Start with the Standard settings and adjust based on your refund rates and customer feedback. Monitor the automatic refunds dashboard to see patterns.
Job Statuses
Automatic refund jobs progress through these statuses:
| Status | Description |
|---|---|
pending | Waiting to be processed |
processing | Currently being processed (locked) |
succeeded | Refund successfully applied |
failed | Processing failed (may be retried manually) |
cancelled | Job cancelled (ride no longer eligible) |
Cron Job Details
The automatic refunds cron runs every 5 minutes via Vercel Cron.
Processing Behavior
Each cron execution:
- Processes up to 25 jobs per run
- Only processes jobs where
scheduled_for ≤ NOW() - Uses optimistic locking to prevent double-processing
- Cleans up expired jobs older than 7 days
Response Format
The cron endpoint returns processing statistics:
{
"success": true,
"timestamp": "2025-01-19T12:00:00Z",
"duration_ms": 1234,
"processed": 15,
"succeeded": 12,
"cancelled": 2,
"failed": 1,
"total_refunded_usd": 24.50
}
Admin Dashboard
Access the automatic refunds dashboard at Dashboard > Refunds > Automatic.
Dashboard Features
Statistics Cards
- Pending Jobs - Number of jobs waiting to be processed
- Succeeded (24h) - Successful refunds in the last 24 hours
- Total Refunded (24h) - Dollar amount refunded
- Success Rate - Percentage of jobs that succeeded
Pending Jobs Table
- Ride link
- Customer link
- Ride metrics (duration, distance)
- Refund amount
- Scheduled processing time
- Cancel action
Failed Jobs Alert
- Prominently displayed when jobs need attention
- Retry and cancel actions
Recent Refunds Table
- Processed refunds from last 24 hours
- Amount, customer, ride details
- Job ID for troubleshooting
Available Actions
| Action | Description |
|---|---|
| Refresh | Reload all dashboard data |
| Cancel Job | Cancel a pending job (won't be refunded) |
| Retry Job | Retry a failed job |
Refund Process Details
What Happens During Refund
- Job Lock Acquired - Status set to
processing - Settings Validated - Check if auto-refund still enabled
- Ride Re-fetched - Get latest ride metrics
- Eligibility Re-evaluated - Confirm still within thresholds
- Refundable Amount Calculated - Actual paid minus already refunded
- Wallet Credited - Customer's wallet balance increased
- Wallet Transaction Created - Audit trail recorded
- Ride Updated - Marked as refunded if fully refunded
- Notification Sent - Push notification to customer
- Job Completed - Status set to
succeeded
Customer Notification
When an automatic refund is issued, customers receive:
Push Notification:
- Title: "Ride refund issued"
- Body: "A recent ride was automatically refunded to your wallet."
Wallet Transaction:
- Type: Credit
- Description: "Automatic ride refund"
- Reference: Ride UUID
Cancellation Reasons
Jobs may be cancelled for various reasons:
| Reason | Description |
|---|---|
automatic_refund_disabled | Feature was disabled after job created |
duration_exceeds_limit | Ride duration now exceeds threshold |
distance_exceeds_limit | Ride distance now exceeds threshold |
eligibility_failed | General eligibility check failed |
no_refundable_balance | Ride already fully refunded |
missing_customer_uuid | Customer not found |
Manual Refunds
In addition to automatic refunds, operators can manually issue refunds through the dashboard.
Refund Types
| Type | Description |
|---|---|
| Wallet Refund | Credits the customer's wallet balance instantly |
| Card Refund | Processes refund through Stripe back to original payment method |
Refund Modes
| Mode | Description |
|---|---|
| Full | Refunds the entire remaining refundable amount |
| Partial | Refunds a specific amount (card refunds only) |
Partial Refunds
Wallet refunds must always be full refunds. Partial refunds are only supported for card refunds.
Processing a Manual Refund
Navigate to Ride
Go to Dashboard > Rides and click on the ride
Click Refund
Click the Refund button on the ride details page
Choose Destination
Select wallet or card as the refund destination
Select Mode
For card refunds, choose full or partial
Enter Reason
Optionally enter a reason for the refund
Confirm
Review and confirm the refund
Permission Requirements
Refunds require the ride:refund permission. The following roles can process refunds:
- super_admin
- global_admin
- admin
- general_manager
- franchisee_manager
- fleet_manager
- customer_support
Note: Analysts and service technicians cannot process refunds.
Monitoring
View Pending Jobs
SELECT
id,
ride_uuid,
customer_uuid,
status,
scheduled_for,
attempts,
created_at
FROM ride_auto_refund_jobs
WHERE status = 'pending'
ORDER BY scheduled_for ASC;
View Recent Automatic Refunds
SELECT
r.id,
r.ride_uuid,
r.customer_uuid,
r.amount,
r.processed_at,
r.metadata->>'job_id' as job_id
FROM ride_refunds r
WHERE r.metadata->>'automatic_refund' = 'true'
AND r.processed_at > NOW() - INTERVAL '24 hours'
ORDER BY r.processed_at DESC;
Check Failed Jobs
SELECT
id,
ride_uuid,
customer_uuid,
attempts,
last_error,
created_at
FROM ride_auto_refund_jobs
WHERE status = 'failed'
ORDER BY updated_at DESC
LIMIT 20;
Troubleshooting
Jobs Not Being Created
Check 1: Is automatic refund enabled?
- Navigate to Settings > Rides > Automatic Refunds
- Verify the toggle is on
Check 2: Are ride metrics within thresholds?
- Check ride duration (must be
≤ max_ride_duration_minutes) - Check ride distance (must be
≤ max_total_distance_m)
Check 3: Does ride have a customer?
- Verify the ride is linked to a valid customer
Jobs Stuck in Pending
Check 1: Is the cron running?
- Verify Vercel cron is configured
- Check Vercel dashboard for cron execution logs
Check 2: Are jobs scheduled in the future?
- Jobs won't process until
scheduled_for ≤ NOW()
Check 3: Check Vercel function logs for errors
Jobs Failing
Common errors and solutions:
| Error | Cause | Solution |
|---|---|---|
customer_not_found | Customer was deleted | Cancel the job |
ride_not_found | Ride was deleted | Cancel the job |
no_refundable_balance | Already refunded | Job auto-cancels |
wallet_update_failed | Database issue | Retry the job |
Performance Tuning
High-Volume Fleets
For fleets with many rides, consider:
- Increasing cron frequency - Run every 2-3 minutes instead of 5
- Increasing batch size - Process 50-100 jobs per run
- Monitoring queue backlog - Set up alerts for pending job count
Database Optimization
Ensure these indexes exist for optimal performance:
-- Pending job lookup
CREATE INDEX CONCURRENTLY IF NOT EXISTS
idx_ride_auto_refund_jobs_pending_scheduled
ON ride_auto_refund_jobs (scheduled_for)
WHERE status = 'pending';
-- Customer wallet lookup
CREATE INDEX CONCURRENTLY IF NOT EXISTS
idx_customers_wallet
ON customers (id, wallet_balance);
Recommended Alerts
Set up alerts for:
- High Failure Rate - Alert when failed jobs > 10% of processed
- Queue Backlog - Alert when pending jobs > 100
- Processing Delay - Alert when jobs are overdue by > 30 minutes
- Execution Errors - Alert when cron endpoint returns 500
What's Next?
- Stripe Setup - Configure Stripe integration
- Payment Methods - Managing customer cards
- Damage Charges - Charging customers for damage
Automatic Refunds Active
With automatic refunds configured, your customers will receive instant refunds for failed rides, improving satisfaction and reducing support tickets. Monitor the dashboard regularly to ensure the system is working correctly.