Skip to main content

Manual Transfer Confirmation with GUI

Learn how to create transfers that require user confirmation through the Paysera web interface - perfect for user-initiated payments where verification is needed.

Overview​

Manual confirmation creates transfers that User must approve through the Paysera web interface. This is ideal when:

  • User needs to verify payment details
  • Additional security verification required
  • Compliance requires user confirmation
  • Two-factor authentication needed
User-Friendly

Manual confirmation provides users with a familiar Paysera interface for reviewing and approving transactions.

Prerequisites​

Before you begin:

  • ✅ Standard API credentials
  • ✅ Understanding of Transfer Statuses
  • ✅ Callback URL configured (recommended)

Workflow​

1. Create Transfer
↓
2. Redirect User to confirmation_url
↓
3. User Reviews & Approves Transfer
↓
4. User Redirected to redirect_url
↓
5. Transfer Status: done

Step-by-Step Guide​

Create a transfer without auto_confirm:

POST /transfer/rest/v1/transfers HTTP/1.1
Host: wallet.paysera.com
Content-Type: application/json
Authorization: MAC id="client_id", ts="...", nonce="...", mac="..."

{
"amount": {
"amount": "100.00",
"currency": "EUR"
},
"beneficiary": {
"type": "bank",
"name": "John Doe",
"bank_account": {
"iban": "LT123456789012345678"
}
},
"payer": {
"account_number": "EVP9876543210"
},
"purpose": {
"details": "Payment for invoice #12345"
},
"redirect_url": "https://your-site.com/payment/success"
}

Key Parameters:

  • redirect_url - Where to send user after confirmation (optional)
  • NO auto_confirm parameter (or set to false)

Complete Code Examples​

<?php
use Paysera\Client\TransferClient;

// Initialize client
$client = TransferClient::create([
'auth' => [
'mac' => [
'mac_id' => getenv('PAYSERA_CLIENT_ID'),
'mac_secret' => getenv('PAYSERA_MAC_KEY'),
],
],
]);

try {
// Create transfer for manual confirmation
$transfer = $client->createTransfer([
'amount' => [
'amount' => '100.00',
'currency' => 'EUR',
],
'beneficiary' => [
'type' => 'bank',
'name' => 'John Doe',
'bank_account' => [
'iban' => 'LT123456789012345678',
],
],
'payer' => [
'account_number' => 'EVP9876543210',
],
'purpose' => [
'details' => 'Payment for invoice #12345',
],
'redirect_url' => 'https://your-site.com/payment/success',
]);

echo "Transfer created: " . $transfer->getId() . "\n";
echo "Status: " . $transfer->getStatus() . "\n";
echo "Confirmation URL: " . $transfer->getConfirmationUrl() . "\n";

// Redirect user to confirmation page
header("Location: " . $transfer->getConfirmationUrl());
exit;

} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
// Show error to user
showErrorPage($e->getMessage());
}

Use Cases​

User pays for order with manual confirmation:

function processCheckout($orderId, $userId) {
$order = getOrder($orderId);
$user = getUser($userId);

// Create transfer
$transfer = $client->createTransfer([
'amount' => [
'amount' => $order->total,
'currency' => $order->currency,
],
'beneficiary' => [
'type' => 'paysera',
'name' => 'Your Shop Name',
'paysera_account' => [
'account_number' => config('shop.account'),
],
],
'payer' => [
'account_number' => $user->paysera_account,
],
'purpose' => [
'details' => "Order #" . $orderId,
],
'redirect_url' => url("/orders/{$orderId}/success"),
]);

// Store transfer ID
$order->transfer_id = $transfer->getId();
$order->save();

// Redirect to confirmation
return redirect($transfer->getConfirmationUrl());
}

Handling Callbacks​

Set up callback endpoint to receive status updates:

// callback.php
<?php

$transferId = $_POST['transfer_id'] ?? null;
$status = $_POST['status'] ?? null;
$date = $_POST['date'] ?? null;

if (!$transferId || !$status) {
http_response_code(400);
exit('Invalid callback data');
}

try {
// Get transfer from database
$order = Order::where('transfer_id', $transferId)->first();

if (!$order) {
logger()->warning("Callback for unknown transfer: {$transferId}");
http_response_code(200);
exit('OK');
}

// Update order based on status
switch ($status) {
case 'done':
$order->status = 'paid';
$order->paid_at = now();
sendOrderConfirmation($order);
break;

case 'rejected':
$order->status = 'payment_rejected';
sendPaymentRejectedEmail($order);
break;

case 'failed':
$order->status = 'payment_failed';
break;
}

$order->save();

// Return success
http_response_code(200);
echo 'OK';

} catch (Exception $e) {
logger()->error('Callback error', [
'transfer_id' => $transferId,
'error' => $e->getMessage(),
]);
http_response_code(500);
exit('Error');
}

Error Handling​

Handle when user rejects payment:

// In your success/return handler
if ($transfer->getStatus() === 'rejected') {
// User cancelled payment
logger()->info("User cancelled transfer: {$transfer->getId()}");

// Show friendly message
return view('payment.cancelled', [
'message' => 'You cancelled the payment. You can try again anytime.',
'retry_url' => route('checkout'),
]);
}

Security Considerations​

// Whitelist allowed redirect URLs
$allowedDomains = ['your-site.com', 'shop.your-site.com'];

$redirectUrl = $request->input('redirect_url');
$domain = parse_url($redirectUrl, PHP_URL_HOST);

if (!in_array($domain, $allowedDomains)) {
throw new SecurityException('Invalid redirect URL');
}

Comparison Table​

FeatureManual ConfirmationAutomatic Confirmation
User InteractionRequiredNone
SecurityUser verifiesSystem controlled
SpeedUser dependentInstant
Use CaseUser paymentsBackground automation
PermissionsStandardSpecial permission
User ExperienceFamiliar Paysera UISeamless

Additional Resources​

Support​

Need help with complex integrations?

Contact: tech_support@paysera.com