# Does a PayPal REST API success response mean the outcome happened?

> Does a PayPal REST API success response mean the outcome happened? The 4 completion levels, the PayPal REST API lifecycle, and the evidence Provely reads.

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

**No. PayPal REST API returns a success response when it accepts the request. The capture then holds one of 6 states. Only `COMPLETED` is terminal success. Provely proves `capture_completed`, `capture_recorded`, `refund_completed` and `refund_recorded` as separate promises.**

*Skill facts from the signed manifest.*

| Fact | Value |
| --- | --- |
| Skill version | `0.1.0` |
| Publisher | Built and signed by Provely. |
| Certification | Provisional (score 49 of 100) |
| Last conformance run | 2026-09-05T12:00:00Z: 59 of 59 cases passed, 0 critical false VERIFIED |
| Provider API versions | `v2` |
| Default provider API version | `v2` |
| Compiled | 2026-09-05T12:00:00Z by compiler 0.1.0 |
| Manifest hash | `b569478a510412b0` |
| Manifest hash check | the document hashes to the value the manifest states |
| Signature | valid, key `provely-skill-2026-09`, trusted by this build |

## What does this page prove?

| Claim | Proven by | Evidence | Status |
| --- | --- | --- | --- |
| 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. | [paypal.capture.completed](/verify/paypal/paypal.capture.completed) | E2 + E3 | proven |
| The captured payment exists with the intended order, amount, and currency. A 201 Created answer with the status PENDING proves that no money moved. | [paypal.capture.recorded](/verify/paypal/paypal.capture.recorded) | E2 + E3 | proven |
| The refund reached the status COMPLETED. A 201 Created answer with the status PENDING is an object that exists and not money that went back. | [paypal.refund.completed](/verify/paypal/paypal.refund.completed) | E2 + E3 | proven |
| 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. | [paypal.refund.recorded](/verify/paypal/paypal.refund.recorded) | E2 + E3 | proven |
| An outcome outside PayPal REST API, such as a bank credit or a person who read a message | not proven | no E5 channel | not proven |
| The meaning of the `FAILED` state of `paypal.capture` | not proven | no source states it | not proven |
| The meaning of the `CANCELLED` state of `paypal.refund` | not proven | no source states it | not proven |
| The agent report that the action worked | never counts | E0 | not proven |

## Which completion levels does the PayPal REST API skill expose?

Each level is one promise with one contract. An agent picks the level that matches the promise it makes. It cannot upgrade a level. Read the [completion level](/glossary/completion-level) definition.

| Level | Contract | Promise | Evidence | Certification |
| --- | --- | --- | --- | --- |
| `capture_completed` | [paypal.capture.completed](/verify/paypal/paypal.capture.completed) v1.0.0 | 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. | E2 + E3 | Provisional |
| `capture_recorded` | [paypal.capture.recorded](/verify/paypal/paypal.capture.recorded) v1.0.0 | The captured payment exists with the intended order, amount, and currency. A 201 Created answer with the status PENDING proves that no money moved. | E2 + E3 | Provisional |
| `refund_completed` | [paypal.refund.completed](/verify/paypal/paypal.refund.completed) v1.0.0 | The refund reached the status COMPLETED. A 201 Created answer with the status PENDING is an object that exists and not money that went back. | E2 + E3 | Provisional |
| `refund_recorded` | [paypal.refund.recorded](/verify/paypal/paypal.refund.recorded) v1.0.0 | 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. | E2 + E3 | Provisional |

## What is the PayPal REST API lifecycle?

### Which states can a `paypal.capture` be in?

| State | Class | Verdict | Meaning | Source |
| --- | --- | --- | --- | --- |
| `PENDING` | transitional | PENDING | The captured payment exists and the money did not move. The member status_details.reason states why. | [paypal.payments.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json) |
| `COMPLETED` | terminal success | VERIFIED | The capture completed. The money moved from the payer to the payee. | [paypal.payments.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json) |
| `DECLINED` | terminal failure | FAILED | PayPal declined the capture. No money moved. | [paypal.payments.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json) |
| `REFUNDED` | terminal neutral | FAILED | The money moved and a refund returned all of it. The capture is not a failure, and it holds no money now. | [paypal.payments.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json) |
| `PARTIALLY_REFUNDED` | terminal neutral | FAILED | The money moved and a refund returned a part of it. | [paypal.payments.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json) |
| `FAILED` | unknown | UNVERIFIABLE | The published enumeration lists this status. No source of this compile states what it means for the money, and the event table names no event for it. | [paypal.payments.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json) |

In `paypal.capture` under provider API version `v2`, `COMPLETED` is the only state that means terminal success. Every other state gives PENDING, FAILED, or UNVERIFIABLE.

Source: https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json (retrieved 2026-09-08)

### Which states can a `paypal.refund` be in?

| State | Class | Verdict | Meaning | Source |
| --- | --- | --- | --- | --- |
| `PENDING` | transitional | PENDING | The refund exists and the money did not move back. An eCheck refund waits for the bank of the merchant. | [paypal.payments.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json) |
| `COMPLETED` | terminal success | VERIFIED | The refund completed. The money went back to the payer. | [paypal.payments.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json) |
| `FAILED` | terminal failure | FAILED | The settlement process of the bank did not issue the refund. | [paypal.payments.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json) |
| `CANCELLED` | unknown | UNVERIFIABLE | The published enumeration lists this status. No source of this compile states when a refund reaches it, and the event table names no event for it. | [paypal.payments.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json) |

In `paypal.refund` under provider API version `v2`, `COMPLETED` is the only state that means terminal success. Every other state gives PENDING, FAILED, or UNVERIFIABLE.

Source: https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json (retrieved 2026-09-08)

## How does Provely tie the evidence to this exact operation?

A matching state that already existed must not verify. Every contract names the [correlation](/glossary/correlation) keys that bind the evidence to the operation, and the [idempotency](/glossary/idempotency) key that stops a duplicate side effect.

| Strategy | Assurance | Keys | Required | Window |
| --- | --- | --- | --- | --- |
| `resource_id` | strong | capture_id from `$action.result.purchase_units[0].payments.captures[0].id` | yes | none |
| `fingerprint` | weak | order_id from `$input.order_id`; amount from `$input.amount` | no | 600000 ms |
| `resource_id` | weak | capture_id from `$input.capture_id` | no | 600000 ms |
| `resource_id` | strong | refund_id from `$action.result.id` | no | none |
| `fingerprint` | weak | capture_id from `$input.capture_id`; amount from `$input.amount` | no | 600000 ms |

*Figure: The skill reads the channels below. It prefers the ones furthest from the action.*

- E0 agent assertion: never sufficient.
- E1 action response: the provider acknowledged the request.
- E2 provider readback: the runtime read the resource back.
- E3 provider event: the provider reported the change.
- E4 independent system: a system outside the action path agrees.
- E5 external outcome: the result is observable in the world.

## Which evidence channels does the skill read?

The runtime prefers the channel that is more independent from the action path. Read the [evidence level](/glossary/evidence-level) definition. An [acknowledgement](/glossary/acknowledgement) from PayPal REST API is E1 and never terminal success.

| Channel | Level | Independence | Verifier | Deterministic | Typical latency |
| --- | --- | --- | --- | --- | --- |
| `capture_completed_events` | E3 | provider event | `webhook` | no | 5000 ms |
| `capture_readback` | E2 | provider readback | `http` | yes | 400 ms |
| `capture_refunded_events` | E3 | provider event | `webhook` | no | 5000 ms |
| `capture_status_events` | E3 | provider event | `webhook` | no | 5000 ms |
| `refund_readback` | E2 | provider readback | `http` | yes | 400 ms |

## Which ways can a PayPal REST API action look done and not be?

| Contract | Case | Rule | Verdict |
| --- | --- | --- | --- |
| [paypal.capture.completed](/verify/paypal/paypal.capture.completed) | wrong subject | The captured payment belongs to a different order than the intent named. | CONTRADICTED |
| [paypal.capture.completed](/verify/paypal/paypal.capture.completed) | wrong amount | PayPal captured a different amount than the intent stated. | CONTRADICTED |
| [paypal.capture.completed](/verify/paypal/paypal.capture.completed) | wrong amount | PayPal captured a different currency than the intent stated. | CONTRADICTED |
| [paypal.capture.completed](/verify/paypal/paypal.capture.completed) | pre existing state | The captured payment is older than the operation. It proves nothing. | CONTRADICTED |
| [paypal.capture.completed](/verify/paypal/paypal.capture.completed) | duplicate side effect | PayPal completed more than one capture of the order. Do not retry. | CONTRADICTED |
| [paypal.capture.completed](/verify/paypal/paypal.capture.completed) | observed state | PayPal declined the capture. No money moved. Retry with the first request id. | FAILED |
| [paypal.capture.completed](/verify/paypal/paypal.capture.completed) | observed state | The capture is pending. The money did not move. The runtime observes again. | PENDING |
| [paypal.capture.completed](/verify/paypal/paypal.capture.completed) | observed state | A refund reversed the capture before the verification. Ask a person. | CONTRADICTED |
| [paypal.capture.recorded](/verify/paypal/paypal.capture.recorded) | wrong subject | The captured payment belongs to a different order than the intent named. | CONTRADICTED |
| [paypal.capture.recorded](/verify/paypal/paypal.capture.recorded) | wrong amount | PayPal captured a different amount than the intent stated. | CONTRADICTED |
| [paypal.capture.recorded](/verify/paypal/paypal.capture.recorded) | wrong amount | PayPal captured a different currency than the intent stated. | CONTRADICTED |
| [paypal.capture.recorded](/verify/paypal/paypal.capture.recorded) | pre existing state | The captured payment is older than the operation. It proves nothing. | CONTRADICTED |
| [paypal.refund.completed](/verify/paypal/paypal.refund.completed) | wrong amount | PayPal refunded a different amount than the intent stated. | CONTRADICTED |
| [paypal.refund.completed](/verify/paypal/paypal.refund.completed) | wrong amount | PayPal refunded a different currency than the intent stated. | CONTRADICTED |
| [paypal.refund.completed](/verify/paypal/paypal.refund.completed) | pre existing state | The refund is older than the operation. It proves nothing. | CONTRADICTED |
| [paypal.refund.completed](/verify/paypal/paypal.refund.completed) | duplicate side effect | PayPal refunded the captured payment more than once since the operation started. Do not retry. | CONTRADICTED |
| [paypal.refund.completed](/verify/paypal/paypal.refund.completed) | observed state | The settlement process of the bank did not issue the refund. Retry with the first request id. | FAILED |
| [paypal.refund.completed](/verify/paypal/paypal.refund.completed) | observed state | The refund is pending. The money did not move back. The runtime observes again. | PENDING |
| [paypal.refund.recorded](/verify/paypal/paypal.refund.recorded) | wrong amount | PayPal refunded a different amount than the intent stated. | CONTRADICTED |
| [paypal.refund.recorded](/verify/paypal/paypal.refund.recorded) | wrong amount | PayPal refunded a different currency than the intent stated. | CONTRADICTED |
| [paypal.refund.recorded](/verify/paypal/paypal.refund.recorded) | pre existing state | The refund is older than the operation. It proves nothing. | CONTRADICTED |
| [paypal.refund.recorded](/verify/paypal/paypal.refund.recorded) | duplicate side effect | PayPal refunded the captured payment more than once since the operation started. Do not retry. | CONTRADICTED |

## What did the last conformance run show?

*The six confidence dimensions of the signed manifest.*

| Dimension | Score | Maximum |
| --- | --- | --- |
| Documentation | 14 | 20 |
| Schema alignment | 0 | 15 |
| Lifecycle certainty | 16 | 20 |
| Evidence strength | 16 | 20 |
| Causal correlation | 10 | 15 |
| Sandbox conformance | 10 | 10 |
| Raw score | 66 | 100 |
| Score after the caps | 49 | 100 |

The raw score is 66. 4 hard caps apply, so the score is 49 and the level is Provisional.

*Why the score is capped.*

| Reason | Highest score it allows |
| --- | --- |
| A lifecycle state has unknown semantics. The compiler cannot prove the end state. | 49 |
| No strong correlation strategy ties the evidence to the operation. | 69 |
| 24 uncertainty records are open. The lowest cap is 49. | 49 |
| 6 mandatory cases are missing. Example: paypal.capture.completed:duplicate_side_effect. | 74 |

*The score and the level of each contract.*

| Contract | Raw score | Score after the caps | Certification |
| --- | --- | --- | --- |
| `paypal.capture.completed` | 71.67 | 49 | Provisional |
| `paypal.capture.recorded` | 71.67 | 49 | Provisional |
| `paypal.refund.completed` | 65 | 49 | Provisional |
| `paypal.refund.recorded` | 65 | 49 | Provisional |

> The weakest contract is paypal.capture.completed. It scores 49 and reaches Provisional. The package level is Provisional, because a package level never rises above its weakest contract. Read the level of the contract you use.

The last conformance run on 2026-09-05T12:00:00Z passed 59 of 59 cases with 0 critical false VERIFIED. One critical false VERIFIED rejects a skill.

*The conformance result by case class.*

| Case class | Passed | Total |
| --- | --- | --- |
| duplicate side effect | 2 | 2 |
| error after execution | 4 | 4 |
| error before execution | 4 | 4 |
| evidence unavailable | 4 | 4 |
| idempotent retry | 4 | 4 |
| pre existing state | 4 | 4 |
| stale readback | 4 | 4 |
| still transitional | 4 | 4 |
| terminal failure | 2 | 2 |
| terminal success | 4 | 4 |
| timeout after commit | 4 | 4 |
| version mismatch | 4 | 4 |
| webhook duplicate | 4 | 4 |
| webhook out of order | 4 | 4 |
| wrong amount | 4 | 4 |
| wrong subject | 2 | 2 |
| wrong terminal state | 1 | 1 |

The conformance artifact digest is `7a1ba0842c927b54`. The harness signs the run, so a reader can check that these numbers come from that run.

## What remains uncertain?

> The level is Provisional because of it. A lifecycle state has unknown semantics. The compiler cannot prove the end state. 24 uncertainty records are open. The lowest cap is 49. Provely does not guess a rule that a source does not state.

## Where do these facts come from?

Every claim above cites a source assertion in the skill provenance. The compiler records the source, its hash, and the retrieval date. A page never states a provider rule without one.

| Source | Kind | Retrieved | Excerpt |
| --- | --- | --- | --- |
| [paypal.docs.captures](https://developer.paypal.com/docs/api/orders/v2/) | docs | 2026-09-08 | authored |
| [paypal.docs.credentials](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json) | docs | 2026-09-08 | authored |
| [paypal.docs.idempotency](https://developer.paypal.com/api/rest/requests/) | docs | 2026-09-08 | authored |
| [paypal.docs.refunds](https://developer.paypal.com/docs/api/payments/v2/) | docs | 2026-09-08 | authored |
| [paypal.docs.sandbox](https://developer.paypal.com/api/rest/sandbox/) | docs | 2026-09-08 | authored |
| [paypal.docs.versions](https://github.com/paypal/paypal-rest-api-specifications) | docs | 2026-09-08 | authored |
| [paypal.docs.webhooks](https://developer.paypal.com/api/rest/webhooks/) | docs | 2026-09-08 | authored |
| [paypal.events](https://developer.paypal.com/api/rest/webhooks/event-names/) | event sample | 2026-09-08 | authored |
| [paypal.orders.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/checkout_orders_v2.json) | openapi | 2026-09-08 | trimmed |
| [paypal.payments.openapi](https://raw.githubusercontent.com/paypal/paypal-rest-api-specifications/main/openapi/payments_payment_v2.json) | openapi | 2026-09-08 | trimmed |

## How do I verify a PayPal REST API action?

### Verify a PayPal REST API action with Provely

1. **Begin the operation.** Call `begin` with the contract `paypal.capture.completed` and the input. Keep the operation id and the idempotency key.
2. **Make the PayPal REST API call you make today.** Send the `PayPal-Request-Id` header with the key that `begin` returned. A retry then cannot create a second side effect.
3. **Submit the acknowledgement.** Call `action_result` with the PayPal REST API response. This is evidence level E1. It is not completion.
4. **Verify.** Call `verify`. The runtime reads `capture_completed_events`, `capture_readback`, `capture_refunded_events`, `capture_status_events` and `refund_readback` and evaluates the contract.
5. **Report the verdict exactly as returned.** VERIFIED comes with a signed receipt. PENDING comes with the operation id. CONTRADICTED and UNVERIFIABLE are not success.

## Questions developers ask

### Does the `capture_completed` level prove the `refund_recorded` level?

No. 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. 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. Use `paypal.refund.recorded` to prove `refund_recorded`.

### What does the agent say while PayPal REST API reports `PENDING`?

It says: "The action is accepted but not yet verified. Operation: <id>." The verdict is PENDING. The runtime observes again on the contract timing policy.

### Which PayPal REST API API versions does the skill support?

`v2`. An operation on another version returns UNVERIFIABLE with the reason `version_unsupported`. The runtime never guesses.

### Does Provely need write access to PayPal REST API?

No. The agent keeps its write key. The verifier reads with a separate read-only credential where PayPal REST API permits it, and it never shares that credential with the agent.

## Read next

- [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 the paypal.refund.recorded contract](https://provely.sh/verify/paypal/paypal.refund.recorded)
- [Read the GitHub REST API verification page](https://provely.sh/verify/github)
- [Read the HubSpot CRM API verification page](https://provely.sh/verify/hubspot)
- [See every integration](https://provely.sh/verify)
- [Verify PayPal REST API actions from Claude Code](https://provely.sh/agents/claude-code)
- [Verify PayPal REST API actions from Cursor](https://provely.sh/agents/cursor)
- [See every agent integration](https://provely.sh/agents)
- [Open the quick start](https://provely.sh/docs/quick-start)
- [Read how Provely records integration uptime](https://provely.sh/docs/uptime)
- [Read the completion level definition](https://provely.sh/glossary/completion-level)
