Last updated: June 4, 2026
Refund captured payments to customers after an initial transaction. Common scenarios include:
This integration uses the Payments API v2 to process full or partial refunds with the capture ID from the original payment. Add refund endpoints to your existing PayPal integration with comprehensive error handling and negative testing capabilities.
Add the following to your existing server file from the quick start integration.
# Refund a captured payment
curl -X POST https://api-m.sandbox.paypal.com/v2/payments/captures/CAPTURE_ID/refund \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-d '{
"amount": {
"value": "25.00",
"currency_code": "USD"
},
"note_to_payer": "Refund processed"
}'
# Get refund status
curl -X GET https://api-m.sandbox.paypal.com/v2/payments/refunds/REFUND_ID \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ACCESS_TOKEN"# Test full refund (replace with actual capture ID)
curl -X POST http://localhost:3000/api/captures/3C679366HH908993F/refund \
-H "Content-Type: application/json"
# Expected success response:
# {"id":"WH4YN4SYEDZJA","status":"COMPLETED","amount":"100.00"}
# Test partial refund with note
curl -X POST http://localhost:3000/api/captures/3C679366HH908993F/refund \
-H "Content-Type: application/json" \
-d '{"amount": "25.00", "note": "Partial refund for damaged item"}'
# Test refund status check
curl http://localhost:3000/api/refunds/WH4YN4SYEDZJA
# Expected response:
# {"id":"WH4YN4SYEDZJA","status":"COMPLETED","amount":"25.00"}Use the following best practices to ensure refunds are processed safely, accurately, and in compliance with operational and regulatory requirements.
note_to_payer field for customer clarity.capture.result.id when you capture a payment. Store this value in your database immediately. You'll need it for any future refunds on that transaction.PAYMENT.CAPTURE.REFUNDED events for real-time status updates. Always verify webhook signatures for security.Make sure you have sandbox account credentials for both buyer and seller roles. Complete a test payment to get a valid capture ID.
| Test scenario | Setup | Expected result |
|---|---|---|
| Full refund success | Default settings | Entire payment amount refunded. |
| Partial refund success | Default settings | Specified amount refunded. |
| Multiple partial refund success | Default settings | Each refunds succeeds until limit. |
| Invalid capture ID | Fake IDL XXX123 | 404 error: capture not found. |
| Refund after 3 days | Wait 3 days | Success if within 180 days |
For negative testing:
.env file, set ENABLE_NEGATIVE_TESTING=true and set NEGATIVE_TEST_TYPE to one of the error codes in the table..env file: node server.js.| Test scenario | Error code | Expected result |
|---|---|---|
| Exceed original amount | REFUND_AMOUNT_EXCEEDED | Error: refund amount exceeds capture. |
| Already fully refunded | CAPTURE_FULLY_REFUNDED | Error: already fully refunded. |
| Refund after 180 days | REFUND_NOT_ALLOWED_AFTER_180_DAYS | Error: refund period expired. |
| Permission denied | PERMISSION_DENIED | 403 error: no refund permission. |
| Internal server error | INTERNAL_SERVER_ERROR | Error: 500 error occurred at refund. |
These values are suggested monitoring thresholds for your integration, not performance guarantees from PayPal.
| Metric | Target | Action if below target |
|---|---|---|
| Refund success rate | 98% | Check API errors and validate capture IDs. |
| Refund processing time | <5 seconds | Optimize database queries. |
| Failed refund rate | <2% | Review error logs, check amounts. |
| Refund-to-payment ratio | <5% | Analyze if high - may indicate quality issues. |
| API response time | <2 seconds | Check PayPal API status. |