Overview
The RefundService class handles full and partial refunds of approved payments. Refunds return money to the customer and update the payment status accordingly.
Source : src/Services/RefundService.php:9
Only payments with approved status can be refunded. Refund availability depends on the payment method and time elapsed since approval.
Constructor
public function __construct (
private MercadoPagoClientFactory $clientFactory ,
) {}
Dependencies
clientFactory
MercadoPagoClientFactory
required
Factory for creating and configuring MercadoPago SDK clients. Automatically injected by Laravel’s service container.
Methods
create()
Creates a full or partial refund for an approved payment.
public function create ( string $paymentId , array $payload = []) : mixed
Source : src/Services/RefundService.php:15
Parameters
The MercadoPago payment ID to refund (must be an approved payment)
Optional refund configuration. Partial refund amount. If omitted, a full refund is processed.
For partial refunds : Include the amount to refund
For full refunds : Omit the amount field or pass an empty array
Implementation detail (src/Services/RefundService.php:21-28): When amount is present in the payload, the service calls refund() with the specific amount. Otherwise, it calls refundTotal() for a complete refund.
Returns
MercadoPago refund object containing: Refund status (typically “approved”)
ISO 8601 refund creation timestamp
Refund source information
Usage
Full refund
Partial refund
Controller injection
With order update
use Fitodac\LaravelMercadoPago\Services\ RefundService ;
$service = app ( RefundService :: class );
// Full refund - omit amount or pass empty array
$refund = $service -> create ( '123456789' );
// or
$refund = $service -> create ( '123456789' , []);
$refundId = data_get ( $refund , 'id' );
$refundedAmount = data_get ( $refund , 'amount' );
Full vs Partial Refunds
Full Refund
Refunds the entire payment amount:
// Original payment: $100.00
$refund = $refundService -> create ( $paymentId );
// Refunds: $100.00
After a full refund:
Payment status changes to refunded
Customer receives the complete payment amount
No additional refunds can be processed
Partial Refund
Refunds a portion of the payment:
// Original payment: $100.00
$refund = $refundService -> create ( $paymentId , [ 'amount' => 30.00 ]);
// Refunds: $30.00, Remaining: $70.00
Partial refund rules:
You can process multiple partial refunds
Total refunds cannot exceed original payment amount
Payment status may change depending on total refunded
Common Patterns
Refund with validation
Validate payment status before refunding:
use Fitodac\LaravelMercadoPago\Services\ PaymentService ;
use Fitodac\LaravelMercadoPago\Services\ RefundService ;
$paymentService = app ( PaymentService :: class );
$refundService = app ( RefundService :: class );
// Check payment status
$payment = $paymentService -> get ( $paymentId );
if ( data_get ( $payment , 'status' ) !== 'approved' ) {
throw new \Exception ( 'Only approved payments can be refunded' );
}
// Process refund
$refund = $refundService -> create ( $paymentId );
Refund with reason tracking
Store refund details in your database:
use Fitodac\LaravelMercadoPago\Services\ RefundService ;
use App\Models\ Refund ;
$refund = app ( RefundService :: class ) -> create ( $paymentId , [
'amount' => 50.00 ,
]);
Refund :: create ([
'order_id' => $orderId ,
'mercadopago_payment_id' => $paymentId ,
'mercadopago_refund_id' => data_get ( $refund , 'id' ),
'amount' => data_get ( $refund , 'amount' ),
'reason' => request () -> input ( 'reason' ),
'processed_by' => auth () -> id (),
'processed_at' => now (),
]);
Automatic refund on order cancellation
use Fitodac\LaravelMercadoPago\Services\ RefundService ;
public function cancelOrder ( Order $order )
{
if ( $order -> status === 'paid' && $order -> mercadopago_payment_id ) {
try {
$refund = app ( RefundService :: class )
-> create ( $order -> mercadopago_payment_id );
$order -> update ([
'status' => 'refunded' ,
'refund_id' => data_get ( $refund , 'id' ),
]);
} catch ( \ Exception $e ) {
\ Log :: error ( 'Refund failed during order cancellation' , [
'order_id' => $order -> id ,
'payment_id' => $order -> mercadopago_payment_id ,
'error' => $e -> getMessage (),
]);
throw new \Exception ( 'Could not process refund' );
}
}
$order -> update ([ 'status' => 'cancelled' ]);
}
Calculate refundable amount
Check how much can still be refunded:
use Fitodac\LaravelMercadoPago\Services\ PaymentService ;
$payment = app ( PaymentService :: class ) -> get ( $paymentId );
$totalAmount = data_get ( $payment , 'transaction_amount' );
$refundedAmount = data_get ( $payment , 'transaction_amount_refunded' , 0 );
$refundableAmount = $totalAmount - $refundedAmount ;
if ( $refundableAmount > 0 ) {
// Can still refund up to $refundableAmount
}
Error Handling
MercadoPagoConfigurationException
Thrown when:
MercadoPago SDK is not installed
Required SDK classes are not found
SDK methods are unavailable
Thrown by the MercadoPago SDK for API errors:
Invalid credentials
Payment not found
Payment not refundable (wrong status)
Refund amount exceeds available amount
Refund window expired
Network errors
Error handling example
use Fitodac\LaravelMercadoPago\Exceptions\ MercadoPagoConfigurationException ;
try {
$refund = $refundService -> create ( $paymentId , $payload );
return response () -> json ([
'success' => true ,
'refund_id' => data_get ( $refund , 'id' ),
]);
} catch ( MercadoPagoConfigurationException $e ) {
return response () -> json ([ 'error' => 'Service misconfigured' ], 500 );
} catch ( \ Exception $e ) {
$message = $e -> getMessage ();
if ( str_contains ( $message , 'not found' )) {
return response () -> json ([ 'error' => 'Payment not found' ], 404 );
}
if ( str_contains ( $message , 'status' )) {
return response () -> json ([ 'error' => 'Payment cannot be refunded' ], 422 );
}
\ Log :: error ( 'Refund failed' , [
'payment_id' => $paymentId ,
'error' => $message ,
]);
return response () -> json ([ 'error' => 'Refund processing failed' ], 500 );
}
Refund Limitations
Refund availability depends on several factors:
Payment method : Some methods have limited refund windows
Time elapsed : Refunds may not be available after a certain period
Payment status : Only approved payments can be refunded
Amount : Partial refunds cannot exceed remaining balance
Typical refund windows
Credit cards : Up to 180 days
Debit cards : Up to 90 days
Cash payments : Varies by provider
Check MercadoPago documentation for specific refund policies by payment method.
PaymentService Create and retrieve payments
WebhookService Handle refund notifications
Additional Resources
Refunds Guide Complete guide to processing refunds
MercadoPago API Documentation Official refunds API reference