Refunds
A Refund returns all or part of a paid payment to the customer's original payment method. Only a payment whose status is paid can be refunded. You can refund one payment several times, as long as the refunds together do not exceed what was paid.
Every method lives on Paymongo::refunds(), and a single refund comes back as a Refund. For every attribute PayMongo accepts, see its Refund reference and Refunds guide.
Refund a payment
create() takes the payment to refund, the amount, and why:
use Luigel\Paymongo\Enums\RefundReason;
use Luigel\Paymongo\Facades\Paymongo;
$refund = Paymongo::refunds()->create([
'payment_id' => 'pay_i7tdqnmwdszWo5B4Xqk2ogX5',
'amount' => 50050, // PHP 500.50 of a PHP 1,500.50 payment, in centavos
'reason' => RefundReason::Others, // or Duplicate, Fraudulent
'notes' => 'Order 1234: one item out of stock', // up to 255 characters
'metadata' => ['order_id' => '1234'],
], idempotencyKey: 'order-1234-refund-1');
$refund->status; // ?RefundStatus: usually Pending at first
amountis integer centavos, at least100(PHP 1.00). The full payment amount refunds it in full, and anything less refunds part of it.reasonis required: aLuigel\Paymongo\Enums\RefundReasoncase (Duplicate,Fraudulent, orOthers) or its string value. PayMongo's reference also listsrequested_by_customer, which you can pass as a string. The enum does not have it yet, so$refund->reasonreadsnullfor it. Read the raw value with$refund->attribute('reason').notes(up to 255 characters) andmetadataare for you.idempotencyKey:makes a retried request return the same refund instead of refunding twice. Use a key unique to this refund of this order.
How long a refund may be made after the payment, whether partial refunds are allowed, and how soon the customer sees the money all depend on the payment method. Card refunds are allowed for 60 days, and UnionBank online banking payments cannot be refunded at all. See PayMongo's Refunds guide for the table.
The money comes out of your upcoming payout. If that balance cannot cover the refund, the refund does not go through until it can. A refund of a payment already paid out to you is deducted from your next payout.
Retrieve a refund
retrieve() returns a refund with its status:
use Luigel\Paymongo\Enums\RefundStatus;
use Luigel\Paymongo\Facades\Paymongo;
$refund = Paymongo::refunds()->retrieve('ref_vPSqdAPD2pmtKj6Ac5SRfXjs');
$refund->status === RefundStatus::Succeeded;
$refund->reason; // ?RefundReason
$refund->paymentId; // "pay_..."
$refund->money()?->format(); // "₱500.50"
$refund->refundedAt(); // ?CarbonImmutable
$refund->attribute('payout_id'); // the payout it was deducted from, or null
$refund->status is a Luigel\Paymongo\Enums\RefundStatus:
| Case | Value | Meaning |
|---|---|---|
Pending |
pending |
Being processed. It rarely stays here for more than a few minutes. |
Succeeded |
succeeded |
Refunded. |
Failed |
failed |
Did not go through. Try the refund again. |
PayMongo also documents a processing status, which reads as null here. Like pending, it rarely lasts. Contact PayMongo support about a refund that stays in either.
List refunds
list() returns a page of refunds. Pass payment_id for the refunds of one payment:
use Luigel\Paymongo\Facades\Paymongo;
$refunded = 0;
foreach (Paymongo::refunds()->list(['payment_id' => 'pay_i7tdqnmwdszWo5B4Xqk2ogX5']) as $refund) {
$refunded += $refund->amount; // centavos
}
The page is a Luigel\Paymongo\Pagination\CursorPage. Iterate it for its refunds, check hasMore, and call nextPage() for the next one, or lazy() to walk every page.
When it fails
A refund PayMongo rejects throws a Luigel\Paymongo\Exceptions\PaymongoException, usually an InvalidRequestException, and $e->firstError()?->code says why. PayMongo's Refunds guide names refund_amount_exceeds_payment when the amount is more than is left to refund, payment_not_refundable when the payment is not paid, and payment_not_found. See PayMongo's refund errors for the rest.
Know when it went through
PayMongo sends payment.refunded and payment.refund.updated, which the package dispatches as Luigel\Paymongo\Events\PaymentRefunded and PaymentRefundUpdated. See Webhooks.