# What does paypal.refund.recorded prove?

> Prove that PayPal holds a refund of the intended captured payment. Version 1.0.0, certification Provisional.

Canonical: https://provely.sh/verify/paypal/paypal.refund.recorded  
Last reviewed: 2026-09-05  
Skill version: 0.1.0  
Certification: provisional  

**Prove that PayPal holds a refund of the intended captured payment. The refund exists with the intended amount and currency, and an event ties it to the intended captured payment. It proves no money went back.**

*Contract identity.*

| Fact | Value |
| --- | --- |
| Contract id | `paypal.refund.recorded` |
| Version | `1.0.0` |
| Hash | `7d45cbc2d30f5005` |
| Completion level | `refund_recorded` |
| Publisher | Built and signed by Provely. |
| Certification | Provisional |
| Skill | [PayPal REST API 0.1.0](/verify/paypal) |
| Valid for provider API versions | `v2` |

## What is the intent?

Refund the captured payment to the payer.

## What is the subject and the action?

| Member | Value |
| --- | --- |
| Subject type | `paypal.refund` |
| Subject identity | refund_id = `$action.result.id` |
| Canonical effect | `money.refund` |
| Provider operation | `POST /v2/payments/captures/{capture_id}/refund` |
| Idempotency | idempotency_key through `PayPal-Request-Id`, retry is safe |

## How does the evidence correlate with this operation?

| Strategy | Assurance | Keys | Required |
| --- | --- | --- | --- |
| `resource_id` | strong | refund_id from `$action.result.id` | no |
| `resource_id` | weak | capture_id from `$input.capture_id` | no |
| `fingerprint` | weak | capture_id from `$input.capture_id`; amount from `$input.amount` | no |

## Which evidence does the contract require?

Minimum evidence level `E2`. An independent channel is required. Minimum channels: 1.

| Channel | Level | Independence | Verifier | Description |
| --- | --- | --- | --- | --- |
| `refund_readback` | E2 | provider readback | `http` | Read the refund from the Payments API. A condition path is $observed.refund_readback.status, and the amount sits at $observed.refund_readback.amount.value as a string. |
| `capture_refunded_events` | E3 | provider event | `webhook` | The PAYMENT.CAPTURE.REFUNDED events of the intended captured payment, since the operation started. The webhook verifier returns {events, count, latest, earliest, types, duplicates_dropped}. A count above one shows a second refund of the same capture. |

## Which conditions must all hold for VERIFIED?

| Condition | Meaning | Path | Operator | Expected | Evidence |
| --- | --- | --- | --- | --- | --- |
| `refund_present` | The Payments API holds the refund that the refund response named. | `$observed.refund_readback.id` | `eq` | `$action.result.id` | `refund_readback` |
| `refund_amount_matches` | The refunded amount equals the requested amount. PayPal states the value as a string, so this is a string comparison and it normalizes nothing. | `$observed.refund_readback.amount.value` | `eq` | `$input.amount` | `refund_readback` |
| `refund_currency_matches` | The currency of the refunded amount equals the requested currency. | `$observed.refund_readback.amount.currency_code` | `eq` | `$input.currency_code` | `refund_readback` |
| `refund_created_in_window` | PayPal made the refund after the operation started. | `$observed.refund_readback.create_time` | `time_after` | `$operation.created_at` | `refund_readback` |
| `refund_on_intended_capture` | At least one PAYMENT.CAPTURE.REFUNDED event names the captured payment that the intent named. The refund resource names no capture, so this event is the only tie between the two. | `$observed.capture_refunded_events.count` | `gte` | `1` | `capture_refunded_events` |

## Which conditions give CONTRADICTED?

| Condition | Class | Reason | Path | Operator | Expected |
| --- | --- | --- | --- | --- | --- |
| `refund_amount_mismatch` | wrong amount | PayPal refunded a different amount than the intent stated. | `$observed.refund_readback.amount.value` | `ne` | `$input.amount` |
| `refund_currency_mismatch` | wrong amount | PayPal refunded a different currency than the intent stated. | `$observed.refund_readback.amount.currency_code` | `ne` | `$input.currency_code` |
| `refund_predates_operation` | pre existing state | The refund is older than the operation. It proves nothing. | `$observed.refund_readback.create_time` | `time_before` | `$operation.created_at` |
| `duplicate_refund_present` | duplicate side effect | PayPal refunded the captured payment more than once since the operation started. Do not retry. | `$observed.capture_refunded_events.count` | `gt` | `1` |

## Which observed states map to a verdict before completion?

The contract declares no verdict map. The completion block decides.

## How long does the runtime observe?

| Timing member | Value |
| --- | --- |
| Initial delay | 2000 ms |
| Poll interval | 5000 ms |
| Backoff | exponential factor 2, max 300000 ms |
| Maximum attempts | 60 |
| Timeout | 900000 ms |
| Stale read window | 20000 ms |
| On timeout | UNVERIFIABLE (`evidence_unavailable_before_timeout`), escalated to a person |

## Where do these rules come from?

- `paypal.payments.openapi#/paths/~1v2~1payments~1captures~1{capture_id}~1refund/post`: [paypal.payments.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json), retrieved 2026-09-08
- `paypal.payments.openapi#/paths/~1v2~1payments~1captures~1{capture_id}~1refund/post/responses/201`: [paypal.payments.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json), retrieved 2026-09-08
- `paypal.docs.refunds#refunds/refund-a-captured-payment`: [paypal.docs.refunds](https://developer.paypal.com/docs/api/payments/v2/), retrieved 2026-09-08
- `paypal.docs.refunds#refunds/a-pending-refund`: [paypal.docs.refunds](https://developer.paypal.com/docs/api/payments/v2/), retrieved 2026-09-08
- `paypal.payments.openapi#/components/schemas/refund`: [paypal.payments.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json), retrieved 2026-09-08
- `paypal.payments.openapi#/paths/~1v2~1payments~1refunds~1{refund_id}/get/responses/200`: [paypal.payments.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json), retrieved 2026-09-08
- `paypal.payments.openapi#/components/schemas/money/properties/value`: [paypal.payments.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json), retrieved 2026-09-08
- `paypal.payments.openapi#/components/schemas/money/properties/currency_code`: [paypal.payments.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json), retrieved 2026-09-08
- `paypal.payments.openapi#/components/schemas/activity_timestamps/properties/create_time`: [paypal.payments.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json), retrieved 2026-09-08
- `paypal.events#/events/PAYMENT.CAPTURE.REFUNDED`: [paypal.events](https://developer.paypal.com/api/rest/webhooks/event-names/), retrieved 2026-09-08
- `paypal.docs.refunds#refunds/events`: [paypal.docs.refunds](https://developer.paypal.com/docs/api/payments/v2/), retrieved 2026-09-08
- `paypal.docs.refunds#refunds/the-status-of-the-capture-after-a-refund`: [paypal.docs.refunds](https://developer.paypal.com/docs/api/payments/v2/), retrieved 2026-09-08

### Can paypal.refund.recorded return VERIFIED from the action response alone?

No. The minimum evidence level is E2. The action response is E1. The completion conditions read `refund_readback` and `capture_refunded_events`.

### What happens after the timeout?

The verdict is UNVERIFIABLE with the reason `evidence_unavailable_before_timeout`. The operation goes to a person for review.

## Read next

- [Read the PayPal REST API verification page](https://provely.sh/verify/paypal)
- [Read the paypal.capture.completed contract](https://provely.sh/verify/paypal/paypal.capture.completed)
- [Read the paypal.capture.recorded contract](https://provely.sh/verify/paypal/paypal.capture.recorded)
- [Read the paypal.refund.completed contract](https://provely.sh/verify/paypal/paypal.refund.completed)
- [Read what a completion contract contains](https://provely.sh/contracts)
- [Read what a receipt proves](https://provely.sh/docs/receipts)
