Skip to content

Transfers

The TransferResource resource allows you to automate sending money to your customers. This is useful for payouts, payroll, and withdrawals.

The Transfer Process

You can transfer money in four easy steps:

  1. Create a transfer recipient: A beneficiary on your integration that you can send money to.
  2. Generate a transfer reference: A unique identifier to track and reconcile the transfer.
  3. Initiate a transfer: Send the money using the recipient code and reference.
  4. Listen for transfer status: Use webhooks to confirm the final status (success, failed, reversed).

Initiate Transfer

Send money to a customer.

Method Signature

php
paystack()->transfer()->initiate(array $payload): array

Parameters

ParameterTypeDescription
sourcestringSource of funds (default: balance).
amountintAmount in kobo/pesewas.
recipientstringRecipient code (e.g., RCP_...).
referencestringUnique transfer reference.
reasonstring(Optional) Reason for transfer.
currencystring(Optional) Currency (default: NGN).

Transfer Reference

A transfer reference is a unique identifier that lets you track, manage and reconcile each transfer request.

  • Format: Lowercase letters (a-z), digits (0-9), underscore (_), and dash (-).
  • Length: 16 to 50 characters.
  • Recommendation: Use a v4 UUID or a unique string prefixed with your app identifier.

Example

php
$transfer = paystack()->transfer()->initiate([
    'source' => 'balance',
    'amount' => 500000, // 5,000 NGN
    'recipient' => 'RCP_gd9vgag7n5lr5ix',
    'reference' => 'your_unique_ref_' . time(),
    'reason' => 'Monthly Payout'
]);

Finalize Transfer

Finalize an initiated transfer (required if OTP is enabled).

Method Signature

php
paystack()->transfer()->finalize(string $transferCode, string $otp): array

Example

php
// After initiating, if status is 'otp', collect OTP from user
$result = paystack()->transfer()->finalize('TRF_vsyqdmlzble3uii', '123456');

Bulk Transfer

Batch multiple transfers in a single request. Note: You must disable "Transfers OTP" in your Paystack Dashboard to use this.

Method Signature

php
paystack()->transfer()->bulk(array $transfers, string $source = 'balance', string $currency = 'NGN'): array

Example

php
$transfers = [
    [
        'amount' => 20000,
        'recipient' => 'RCP_gd9vgag7n5lr5ix',
        'reference' => 'ref_001',
        'reason' => 'Staff Bonus'
    ],
    [
        'amount' => 30000,
        'recipient' => 'RCP_zpk2tgagu6lgb4g',
        'reference' => 'ref_002',
        'reason' => 'Vendor Payment'
    ]
];

$response = paystack()->transfer()->bulk($transfers);

List Transfers

List all transfers made on your integration.

Method Signature

php
paystack()->transfer()->list(array $filters = []): array

Example

php
$transfers = paystack()->transfer()->list(['perPage' => 20, 'page' => 1]);

Fetch Transfer

Get details of a single transfer.

Method Signature

php
paystack()->transfer()->fetch(string|int $idOrCode): array

Example

php
$details = paystack()->transfer()->fetch('TRF_v5tip3zx8nna9o78');

Verify Transfer

Verify the status of a transfer using its reference.

Method Signature

php
paystack()->transfer()->verify(string $reference): array

Example

php
$status = paystack()->transfer()->verify('your_unique_ref_123');

Use Cases

1. Automated Payout System

A typical flow for an automated payout system where OTP is disabled for seamless transactions.

php
// 1. Ensure recipient exists
$recipientCode = $user->recipient_code;

// 2. Initiate Transfer
try {
    $response = paystack()->transfer()->initiate([
        'amount' => 100000, // 1,000.00
        'recipient' => $recipientCode,
        'reference' => 'payout_' . uniqid(),
        'reason' => 'Withdrawal Request'
    ]);
    
    if ($response['data']['status'] === 'success' || $response['data']['status'] === 'pending') {
        // Mark withdrawal as processing in your DB
    }
} catch (\Exception $e) {
    // Handle insufficient balance or other errors
}

2. Handling OTP Transfers

If your integration requires OTP (e.g., for security on manual triggers), you need a two-step process.

php
// Step 1: Initiate
$response = paystack()->transfer()->initiate([
    'amount' => 50000,
    'recipient' => 'RCP_xxxx',
    'reference' => 'ref_otp_test'
]);

if ($response['data']['status'] === 'otp') {
    // Redirect user to a page to enter the OTP sent to their phone/email
    $transferCode = $response['data']['transfer_code'];
    return view('enter_otp', compact('transferCode'));
}

// Step 2: Finalize (in your controller handling the OTP form)
public function submitOtp(Request $request) {
    $result = paystack()->transfer()->finalize(
        $request->transfer_code, 
        $request->otp
    );
    
    return response()->json($result);
}

Released under the MIT License.