# What does paypal.capture.completed prove?

> Prove that the money of this capture moved from the payer to the payee. Version 1.0.0, certification Provisional.

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

**Prove that the money of this capture moved from the payer to the payee. The captured payment reached the status COMPLETED. A 201 Created answer with the status PENDING is an object that exists and not money that moved.**

*Contract identity.*

| Fact | Value |
| --- | --- |
| Contract id | `paypal.capture.completed` |
| Version | `1.0.0` |
| Hash | `a90c595b2f9203ed` |
| Completion level | `capture_completed` |
| 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?

Capture the payment of the approved order and let the money move.

## What is the subject and the action?

| Member | Value |
| --- | --- |
| Subject type | `paypal.capture` |
| Subject identity | capture_id = `$action.result.purchase_units[0].payments.captures[0].id` |
| Canonical effect | `money.capture` |
| Provider operation | `POST /v2/checkout/orders/{id}/capture` |
| 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 | capture_id from `$action.result.purchase_units[0].payments.captures[0].id` | yes |
| `fingerprint` | weak | order_id from `$input.order_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 |
| --- | --- | --- | --- | --- |
| `capture_readback` | E2 | provider readback | `http` | Read the captured payment from the Payments API. A condition path is $observed.capture_readback.status, and the amount sits at $observed.capture_readback.amount.value as a string. |
| `capture_completed_events` | E3 | provider event | `webhook` | The PAYMENT.CAPTURE.COMPLETED events of the intended order since the operation started. The webhook verifier returns {events, count, latest, earliest, types, duplicates_dropped}. PayPal sends one for each capture that completes, so a count above one is a second movement of money. |

## Which conditions must all hold for VERIFIED?

| Condition | Meaning | Path | Operator | Expected | Evidence |
| --- | --- | --- | --- | --- | --- |
| `capture_present` | The Payments API holds the captured payment that the capture response named. | `$observed.capture_readback.id` | `eq` | `$action.result.purchase_units[0].payments.captures[0].id` | `capture_readback` |
| `capture_on_intended_order` | The captured payment belongs to the order that the intent named. | `$observed.capture_readback.supplementary_data.related_ids.order_id` | `eq` | `$input.order_id` | `capture_readback` |
| `capture_amount_matches` | The captured amount equals the requested amount. PayPal states the value as a string, so this is a string comparison and it normalizes nothing. | `$observed.capture_readback.amount.value` | `eq` | `$input.amount` | `capture_readback` |
| `capture_currency_matches` | The currency of the captured amount equals the requested currency. | `$observed.capture_readback.amount.currency_code` | `eq` | `$input.currency_code` | `capture_readback` |
| `capture_created_in_window` | PayPal made the captured payment after the operation started. | `$observed.capture_readback.create_time` | `time_after` | `$operation.created_at` | `capture_readback` |
| `capture_status_completed` | The captured payment states the status COMPLETED. That is the only status that proves that the money moved. | `$observed.capture_readback.status` | `eq` | `COMPLETED` | `capture_readback` |
| `capture_completed_event` | At least one PAYMENT.CAPTURE.COMPLETED event of this captured payment reached the workspace. | `$observed.capture_completed_events.count` | `gte` | `1` | `capture_completed_events` |

## Which conditions give CONTRADICTED?

| Condition | Class | Reason | Path | Operator | Expected |
| --- | --- | --- | --- | --- | --- |
| `capture_on_wrong_order` | wrong subject | The captured payment belongs to a different order than the intent named. | `$observed.capture_readback.supplementary_data.related_ids.order_id` | `ne` | `$input.order_id` |
| `capture_amount_mismatch` | wrong amount | PayPal captured a different amount than the intent stated. | `$observed.capture_readback.amount.value` | `ne` | `$input.amount` |
| `capture_currency_mismatch` | wrong amount | PayPal captured a different currency than the intent stated. | `$observed.capture_readback.amount.currency_code` | `ne` | `$input.currency_code` |
| `capture_predates_operation` | pre existing state | The captured payment is older than the operation. It proves nothing. | `$observed.capture_readback.create_time` | `time_before` | `$operation.created_at` |
| `duplicate_capture_present` | duplicate side effect | PayPal completed more than one capture of the order. Do not retry. | `$observed.capture_completed_events.count` | `gt` | `1` |

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

| Rule | Match | Verdict | Reason |
| --- | --- | --- | --- |
| `capture_declined` | `$observed.capture_readback.status` eq `"DECLINED"` | FAILED | PayPal declined the capture. No money moved. Retry with the first request id. |
| `capture_still_pending` | `$observed.capture_readback.status` eq `"PENDING"` | PENDING | The capture is pending. The money did not move. The runtime observes again. |
| `capture_refunded_before_verification` | `$observed.capture_readback.status` in `["REFUNDED","PARTIALLY_REFUNDED"]` | CONTRADICTED | A refund reversed the capture before the verification. Ask a person. |

## 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 | 900 |
| Timeout | 259200000 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#/components/schemas/capture_status/properties/status`: [paypal.payments.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json), retrieved 2026-09-08
- `paypal.docs.captures#captured-payments/the-status-of-a-captured-payment`: [paypal.docs.captures](https://developer.paypal.com/docs/api/orders/v2/), retrieved 2026-09-08
- `paypal.events#/events/PAYMENT.CAPTURE.COMPLETED`: [paypal.events](https://developer.paypal.com/api/rest/webhooks/event-names/), retrieved 2026-09-08
- `paypal.docs.captures#captured-payments/capture-a-payment`: [paypal.docs.captures](https://developer.paypal.com/docs/api/orders/v2/), retrieved 2026-09-08
- `paypal.payments.openapi#/components/schemas/capture`: [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}/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.orders.openapi#/components/schemas/payment_collection/properties/captures`: [paypal.orders.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/checkout_orders_v2.json), retrieved 2026-09-08
- `paypal.payments.openapi#/components/schemas/related_ids/properties/order_id`: [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/capture-2`: [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.docs.captures#captured-payments/events`: [paypal.docs.captures](https://developer.paypal.com/docs/api/orders/v2/), retrieved 2026-09-08

### Can paypal.capture.completed return VERIFIED from the action response alone?

No. The minimum evidence level is E2. The action response is E1. The completion conditions read `capture_readback` and `capture_completed_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.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 the paypal.refund.recorded contract](https://provely.sh/verify/paypal/paypal.refund.recorded)
- [Read what a completion contract contains](https://provely.sh/contracts)
- [Read what a receipt proves](https://provely.sh/docs/receipts)
