intermediate
refunds
automatic
wallet

Automatic Refunds

Complete guide to the automatic refund system that detects failed rides and automatically refunds customers to their wallet

Levy Fleets Team25 de diciembre de 202518 min read

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:

1

Ride Ends

Customer ends their ride through the mobile app

2

Metrics Calculated

System calculates ride metrics (duration, distance, cost)

3

Eligibility Evaluated

System checks if ride meets refund thresholds

4

Job Queued

If eligible, a refund job is queued in ride_auto_refund_jobs

5

Delay Period

Cron job waits the configured delay (recalc_gap_minutes)

6

Re-evaluation

System re-evaluates with latest telemetry data

7

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:

  1. Late-arriving telemetry data to update ride metrics
  2. IoT data sync to complete with final distance/duration
  3. 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:

CriterionDefault ValueDescription
Feature enabledtrueAutomatic refunds toggle is on in settings
Duration within limit≤ 3 minutesRide duration is less than or equal to max
Distance within limit≤ 200 metersTotal distance traveled is within threshold
Has customerRequiredRide is linked to a valid customer
No duplicate jobRequiredNo pending/processing job exists for this ride
Refundable balanceRequiredRide 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:

  1. Navigate to Settings
  2. Click the Rides tab
  3. Find the Automatic Refunds section

Configuration Options

SettingTypeDefaultDescription
enabledbooleantrueMaster toggle for automatic refunds
max_ride_duration_minutesnumber3Maximum ride duration to qualify
max_total_distance_mnumber200Maximum distance in meters to qualify
recalc_gap_minutesnumber1Minutes to wait before processing

Conservative (Fewer Refunds)

Use these settings if you want to minimize automatic refunds and prefer manual review:

SettingValue
enabledtrue
max_ride_duration_minutes2
max_total_distance_m100
recalc_gap_minutes2

Standard (Balanced)

The default settings balance customer satisfaction with operational oversight:

SettingValue
enabledtrue
max_ride_duration_minutes3
max_total_distance_m200
recalc_gap_minutes1

Generous (More Refunds)

Use these settings for maximum customer satisfaction:

SettingValue
enabledtrue
max_ride_duration_minutes5
max_total_distance_m300
recalc_gap_minutes1

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:

StatusDescription
pendingWaiting to be processed
processingCurrently being processed (locked)
succeededRefund successfully applied
failedProcessing failed (may be retried manually)
cancelledJob cancelled (ride no longer eligible)

Cron Job Details

The automatic refunds cron runs every 5 minutes via Vercel Cron.

Processing Behavior

Each cron execution:

  1. Processes up to 25 jobs per run
  2. Only processes jobs where scheduled_for ≤ NOW()
  3. Uses optimistic locking to prevent double-processing
  4. 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

ActionDescription
RefreshReload all dashboard data
Cancel JobCancel a pending job (won't be refunded)
Retry JobRetry a failed job

Refund Process Details

What Happens During Refund

  1. Job Lock Acquired - Status set to processing
  2. Settings Validated - Check if auto-refund still enabled
  3. Ride Re-fetched - Get latest ride metrics
  4. Eligibility Re-evaluated - Confirm still within thresholds
  5. Refundable Amount Calculated - Actual paid minus already refunded
  6. Wallet Credited - Customer's wallet balance increased
  7. Wallet Transaction Created - Audit trail recorded
  8. Ride Updated - Marked as refunded if fully refunded
  9. Notification Sent - Push notification to customer
  10. 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:

ReasonDescription
automatic_refund_disabledFeature was disabled after job created
duration_exceeds_limitRide duration now exceeds threshold
distance_exceeds_limitRide distance now exceeds threshold
eligibility_failedGeneral eligibility check failed
no_refundable_balanceRide already fully refunded
missing_customer_uuidCustomer not found

Manual Refunds

In addition to automatic refunds, operators can manually issue refunds through the dashboard.

Refund Types

TypeDescription
Wallet RefundCredits the customer's wallet balance instantly
Card RefundProcesses refund through Stripe back to original payment method

Refund Modes

ModeDescription
FullRefunds the entire remaining refundable amount
PartialRefunds 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

1

Navigate to Ride

Go to Dashboard > Rides and click on the ride

2

Click Refund

Click the Refund button on the ride details page

3

Choose Destination

Select wallet or card as the refund destination

4

Select Mode

For card refunds, choose full or partial

5

Enter Reason

Optionally enter a reason for the refund

6

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:

ErrorCauseSolution
customer_not_foundCustomer was deletedCancel the job
ride_not_foundRide was deletedCancel the job
no_refundable_balanceAlready refundedJob auto-cancels
wallet_update_failedDatabase issueRetry the job

Performance Tuning

High-Volume Fleets

For fleets with many rides, consider:

  1. Increasing cron frequency - Run every 2-3 minutes instead of 5
  2. Increasing batch size - Process 50-100 jobs per run
  3. 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);

Set up alerts for:

  1. High Failure Rate - Alert when failed jobs > 10% of processed
  2. Queue Backlog - Alert when pending jobs > 100
  3. Processing Delay - Alert when jobs are overdue by > 30 minutes
  4. Execution Errors - Alert when cron endpoint returns 500

What's Next?

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.