setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} catch(PDOException $e) {
die("Database connection failed: " . $e->getMessage());
}
}
// Get user data from session
$username = $_SESSION['username'];
$email = $_SESSION['email'];
$tier = $_SESSION['tier'];
$package = $_SESSION['package'];
$balance = $_SESSION['balance'];
$total_deposits = $_SESSION['total_deposits'];
$total_withdrawals = $_SESSION['total_withdrawals'];
$rewards = $_SESSION['rewards'];
$earnings = $total_deposits - $total_withdrawals;
$user_id = $_SESSION['user_id'];
// Get user's available balance (balance minus any holds)
$available_balance = $balance;
$pending_withdrawals = 0;
// Check for pending withdrawals
try {
$stmt = $pdo->prepare("SELECT SUM(amount) as pending_amount FROM withdrawals WHERE user_id = ? AND status IN ('pending', 'processing')");
$stmt->execute([$user_id]);
$result = $stmt->fetch(PDO::FETCH_ASSOC);
$pending_withdrawals = $result['pending_amount'] ?? 0;
$available_balance = $balance - $pending_withdrawals;
} catch (Exception $e) {
// Log error but continue
error_log("Error fetching pending withdrawals: " . $e->getMessage());
}
// Get withdrawal destinations for this user
$destinations = [];
try {
$stmt = $pdo->prepare("SELECT id, type, details, is_default FROM withdrawal_destinations WHERE user_id = ? AND is_active = 1 ORDER BY is_default DESC, created_at DESC");
$stmt->execute([$user_id]);
$destinations = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Exception $e) {
error_log("Error fetching withdrawal destinations: " . $e->getMessage());
}
// Process withdrawal request
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$data = json_decode(file_get_contents('php://input'), true);
$amount = floatval($data['amount']);
$destination_id = intval($data['destination_id']);
$idempotency_key = $data['idempotency_key'] ?? '';
// Validate input
if ($amount <= 0) {
echo json_encode(['success' => false, 'message' => 'Invalid amount.']);
exit;
}
if (empty($destination_id)) {
echo json_encode(['success' => false, 'message' => 'Please select a withdrawal destination.']);
exit;
}
if (empty($idempotency_key)) {
echo json_encode(['success' => false, 'message' => 'Security error. Please refresh and try again.']);
exit;
}
// Check if user has sufficient available balance
if ($available_balance < $amount) {
echo json_encode(['success' => false, 'message' => 'Insufficient available balance.']);
exit;
}
// Check minimum and maximum limits
$min_withdrawal = 100;
$max_withdrawal = 70000;
if ($amount < $min_withdrawal) {
echo json_encode(['success' => false, 'message' => "Minimum withdrawal amount is {$min_withdrawal} KES."]);
exit;
}
if ($amount > $max_withdrawal) {
echo json_encode(['success' => false, 'message' => "Maximum withdrawal amount is {$max_withdrawal} KES."]);
exit;
}
// Calculate fee (15 KES or 1.5%, whichever is higher)
$fee = max(15, $amount * 0.015);
$net_amount = $amount - $fee;
// Start transaction
$pdo->beginTransaction();
try {
// Check for idempotency (prevent duplicate requests)
$stmt = $pdo->prepare("SELECT id, status FROM withdrawals WHERE user_id = ? AND idempotency_key = ?");
$stmt->execute([$user_id, $idempotency_key]);
$existing_withdrawal = $stmt->fetch(PDO::FETCH_ASSOC);
if ($existing_withdrawal) {
// Idempotent response - return existing withdrawal
$pdo->commit();
echo json_encode([
'success' => true,
'idempotent' => true,
'withdrawal_id' => $existing_withdrawal['id'],
'status' => $existing_withdrawal['status'],
'message' => 'Withdrawal request already processed.'
]);
exit;
}
// Lock user row for update
$stmt = $pdo->prepare("SELECT balance FROM users WHERE id = ? FOR UPDATE");
$stmt->execute([$user_id]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$user || $user['balance'] < $amount) {
throw new Exception('Insufficient balance.');
}
// Deduct from user balance
$stmt = $pdo->prepare("UPDATE users SET balance = balance - ?, total_withdrawals = total_withdrawals + ? WHERE id = ?");
$stmt->execute([$amount, $amount, $user_id]);
// Create withdrawal record
$reference = "WDL-" . date('Ymd') . "-" . mt_rand(1000, 9999);
$stmt = $pdo->prepare("INSERT INTO withdrawals (user_id, destination_id, amount, fee, net_amount, status, idempotency_key, reference) VALUES (?, ?, ?, ?, ?, 'pending', ?, ?)");
$stmt->execute([$user_id, $destination_id, $amount, $fee, $net_amount, $idempotency_key, $reference]);
$withdrawal_id = $pdo->lastInsertId();
// Record transaction in ledger
$new_balance = $user['balance'] - $amount;
$stmt = $pdo->prepare("INSERT INTO ledger (user_id, change_amount, balance_after, type, reference, description) VALUES (?, ?, ?, 'withdrawal', ?, ?)");
$stmt->execute([$user_id, -$amount, $new_balance, $withdrawal_id, "Withdrawal request #{$withdrawal_id}"]);
// Commit transaction
$pdo->commit();
// Update session
$_SESSION['balance'] -= $amount;
$_SESSION['total_withdrawals'] += $amount;
echo json_encode([
'success' => true,
'withdrawal_id' => $withdrawal_id,
'reference' => $reference,
'message' => 'Withdrawal request submitted successfully! You will receive a confirmation message shortly.'
]);
} catch (Exception $e) {
$pdo->rollBack();
error_log("Withdrawal error: " . $e->getMessage());
echo json_encode(['success' => false, 'message' => 'Withdrawal failed: ' . $e->getMessage()]);
}
exit;
}
// Get recent withdrawals for this user
$recent_withdrawals = [];
try {
$stmt = $pdo->prepare("
SELECT w.*, wd.details, wd.type
FROM withdrawals w
LEFT JOIN withdrawal_destinations wd ON w.destination_id = wd.id
WHERE w.user_id = ?
ORDER BY w.created_at DESC
LIMIT 5
");
$stmt->execute([$user_id]);
$recent_withdrawals = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Exception $e) {
error_log("Error fetching recent withdrawals: " . $e->getMessage());
}
?>
Japanese Motors — Withdraw Funds
💵 Withdraw Your Earnings
Transfer your hard-earned money to your preferred payment method
Recent Withdrawals
View Full History
Quick Cashout
500 KES
1,000 KES
2,000 KES
5,000 KES
Withdrawal Information
What are the withdrawal limits?
Minimum withdrawal: 100 KES | Maximum per transaction: 70,000 KES | Daily limit: 70,000 KES | Weekly limit: 140,000 KES. Limits may vary based on your account level and verification status.
How long do withdrawals take?
M-Pesa withdrawals are typically processed within 24-72 hours. Bank transfers may take 1-3 business days. Delays can occur during weekends, holidays, or system maintenance.
Why was my withdrawal declined?
Withdrawals may be declined due to: insufficient balance, incorrect recipient details, security checks, exceeded limits, or account restrictions. Contact support if you need assistance.
Confirm Withdrawal
Amount:
0 KES
Fee:
0 KES
You'll Receive:
0 KES
To:
Not selected
Your withdrawal will be processed within 24-72 hours. You'll receive a confirmation message when completed.
Cancel
Confirm