# Does a Stripe refund object mean the money moved?

> Does a Stripe refund object mean the money moved? The 2 completion levels, the Stripe lifecycle, and the evidence Provely reads. Certification Community.

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

**No. Stripe returns a 200 response with a refund object when it accepts the request. The refund then holds one of 5 states. Only `succeeded` is terminal success. Provely proves `created` and `succeeded` as separate promises.**

*Skill facts from the signed manifest.*

| Fact | Value |
| --- | --- |
| Skill version | `0.1.0` |
| Certification | Community (score 49 of 100) |
| Last conformance run | 2026-09-05T12:00:00Z: 30 of 32 cases passed, 0 critical false VERIFIED |
| Provider API versions | `2026-08-26` |
| Default provider API version | `2026-08-26` |
| Compiled | 2026-09-05T12:00:00Z by compiler 0.1.0 |
| Manifest hash | `596962869919041a` |
| Manifest hash check | the document hashes to the value the manifest states |
| Signature | valid, key `provely-test-key-1`, not in the trusted key map of this build |

## What does this page prove?

| Claim | Proven by | Evidence | Status |
| --- | --- | --- | --- |
| The created level proves that the Refund object exists at the provider with the requested amount and charge. It does not prove that money moved. | [stripe.refund.created](/verify/stripe/stripe.refund.created) | E2 | proven |
| A Refund object does not prove that money moved. This contract proves the succeeded state on the refund resource and a refund.updated event that carries it. | [stripe.refund.succeeded](/verify/stripe/stripe.refund.succeeded) | E2 + E3 | proven |
| An outcome outside Stripe, such as a bank credit or a person who read a message | not proven | no E5 channel | not proven |
| The agent report that the action worked | never counts | E0 | not proven |

## Which completion levels does the Stripe 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 |
| --- | --- | --- | --- | --- |
| `created` | [stripe.refund.created](/verify/stripe/stripe.refund.created) v1.0.0 | The created level proves that the Refund object exists at the provider with the requested amount and charge. It does not prove that money moved. | E2 | Community |
| `succeeded` | [stripe.refund.succeeded](/verify/stripe/stripe.refund.succeeded) v1.0.0 | A Refund object does not prove that money moved. This contract proves the succeeded state on the refund resource and a refund.updated event that carries it. | E2 + E3 | Community |

## What is the Stripe lifecycle?

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

| State | Class | Verdict | Meaning | Source |
| --- | --- | --- | --- | --- |
| `pending` | transitional | PENDING | Stripe submitted the refund to the payment network or waits for a condition. | [stripe.openapi](https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json) |
| `requires_action` | transitional | PENDING | The customer must give bank details before the refund can continue. | [stripe.openapi](https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json) |
| `succeeded` | terminal success | VERIFIED | The payment network accepted the refund. The funds return to the customer. | [stripe.openapi](https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json) |
| `failed` | terminal failure | FAILED | The payment network rejected the refund. Stripe returns the funds to the balance. | [stripe.openapi](https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json) |
| `canceled` | terminal neutral | FAILED | A refund in requires_action was canceled. No funds moved. | [stripe.openapi](https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json) |

In `stripe.refund` under provider API version `2026-08-26`, `succeeded` is the only state that means terminal success. Every other state gives PENDING, FAILED, or UNVERIFIABLE.

Source: https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json (retrieved 2026-09-05)

## 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 | refund_id from `$action.result.id` | yes | none |
| `idempotency_key` | strong | idempotency_key from `$operation.id` | no | none |
| `fingerprint` | weak | charge from `$input.charge`; amount from `$input.amount` | no | 600000 ms |

## 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 Stripe is E1 and never terminal success.

| Channel | Level | Independence | Verifier | Deterministic | Typical latency |
| --- | --- | --- | --- | --- | --- |
| `refund_action_response` | E1 | same response | `action_result` | yes | not stated |
| `refund_created_events` | E3 | provider event | `webhook` | no | 4000 ms |
| `refund_readback` | E2 | provider readback | `http` | yes | 250 ms |
| `refund_succeeded_events` | E3 | provider event | `webhook` | no | 4000 ms |

## Which ways can a Stripe action look done and not be?

| Contract | Case | Rule | Verdict |
| --- | --- | --- | --- |
| [stripe.refund.created](/verify/stripe/stripe.refund.created) | wrong subject | The refund belongs to a different charge. | CONTRADICTED |
| [stripe.refund.created](/verify/stripe/stripe.refund.created) | wrong amount | The provider refunded a different amount. | CONTRADICTED |
| [stripe.refund.created](/verify/stripe/stripe.refund.created) | pre existing state | The refund is older than the operation. It proves nothing. | CONTRADICTED |
| [stripe.refund.created](/verify/stripe/stripe.refund.created) | duplicate side effect | Stripe created more than one refund for the charge since the operation started. Do not retry. | CONTRADICTED |
| [stripe.refund.created](/verify/stripe/stripe.refund.created) | observed state | The provider reports a failed refund. | FAILED |
| [stripe.refund.created](/verify/stripe/stripe.refund.created) | observed state | The refund was canceled. No funds will move. | CONTRADICTED |
| [stripe.refund.succeeded](/verify/stripe/stripe.refund.succeeded) | wrong subject | The refund belongs to a different charge. | CONTRADICTED |
| [stripe.refund.succeeded](/verify/stripe/stripe.refund.succeeded) | wrong amount | The provider refunded a different amount. | CONTRADICTED |
| [stripe.refund.succeeded](/verify/stripe/stripe.refund.succeeded) | pre existing state | The refund is older than the operation. It proves nothing. | CONTRADICTED |
| [stripe.refund.succeeded](/verify/stripe/stripe.refund.succeeded) | duplicate side effect | Stripe created more than one refund for the charge since the operation started. Do not retry. | CONTRADICTED |
| [stripe.refund.succeeded](/verify/stripe/stripe.refund.succeeded) | observed state | The provider reports a failed refund. | FAILED |
| [stripe.refund.succeeded](/verify/stripe/stripe.refund.succeeded) | observed state | The refund is still moving. The runtime observes again later. | PENDING |
| [stripe.refund.succeeded](/verify/stripe/stripe.refund.succeeded) | observed state | The refund was canceled. No funds will move. | CONTRADICTED |

## What did the last conformance run show?

*The six confidence dimensions of the signed manifest.*

| Dimension | Score | Maximum |
| --- | --- | --- |
| Documentation | 18 | 20 |
| Schema alignment | 12.75 | 15 |
| Lifecycle certainty | 20 | 20 |
| Evidence strength | 12 | 20 |
| Causal correlation | 15 | 15 |
| Sandbox conformance | 9.38 | 10 |
| Raw score | 87.13 | 100 |
| Score after the caps | 49 | 100 |

The raw score is 87.13. 2 hard caps apply, so the score is 49 and the level is Community.

*The hard caps the compiler applied.*

| Gate | Cap | Reason |
| --- | --- | --- |
| `uncertainty_caps` | 49 | 1 uncertainty records are open. The lowest cap is 49. |
| `conformance_threshold` | 89 | 2 conformance cases failed. |

The last conformance run on 2026-09-05T12:00:00Z passed 30 of 32 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 | 1 | 2 |
| error before execution | 2 | 2 |
| evidence unavailable | 2 | 2 |
| idempotent retry | 2 | 2 |
| pre existing state | 2 | 2 |
| stale readback | 2 | 2 |
| still transitional | 2 | 2 |
| terminal failure | 2 | 2 |
| terminal success | 2 | 2 |
| timeout after commit | 1 | 2 |
| version mismatch | 2 | 2 |
| webhook duplicate | 2 | 2 |
| webhook out of order | 2 | 2 |
| wrong amount | 2 | 2 |
| wrong subject | 2 | 2 |

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

## What remains uncertain?

**Open questions remain. 1 uncertainty records are open. The lowest cap is 49. The published manifest states the cap and its reason. The questions themselves stay in the compiler review bundle, which no customer receives.**

> This is why the level is Community and not higher. Unknown means unknown. The compiler does not infer an undocumented rule.

## 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 |
| --- | --- | --- | --- |
| [stripe.docs.idempotency](https://docs.stripe.com/api/idempotent_requests) | docs | 2026-09-05 | authored |
| [stripe.docs.refunds](https://docs.stripe.com/refunds) | docs | 2026-09-05 | authored |
| [stripe.docs.webhooks](https://docs.stripe.com/webhooks) | docs | 2026-09-05 | authored |
| [stripe.events](https://docs.stripe.com/api/events/types) | event sample | 2026-09-05 | authored |
| [stripe.openapi](https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json) | openapi | 2026-09-05 | trimmed |

## How do I verify a Stripe action?

### Verify a Stripe action with Provely

1. **Begin the operation.** Call `begin` with the contract `stripe.refund.created` and the input. Keep the operation id and the idempotency key.
2. **Make the Stripe call you make today.** Send the `Idempotency-Key` 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 Stripe response. This is evidence level E1. It is not completion.
4. **Verify.** Call `verify`. The runtime reads `refund_action_response`, `refund_created_events`, `refund_readback` and `refund_succeeded_events` 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 `created` level prove the `succeeded` level?

No. The created level proves that the Refund object exists at the provider with the requested amount and charge. It does not prove that money moved. A Refund object does not prove that money moved. This contract proves the succeeded state on the refund resource and a refund.updated event that carries it. Use `stripe.refund.succeeded` to prove `succeeded`.

### What does the agent say while Stripe reports `pending` and `requires_action`?

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 Stripe API versions does the skill support?

`2026-08-26`. An operation on another version returns UNVERIFIABLE with the reason `version_unsupported`. The runtime never guesses.

### Does Provely need write access to Stripe?

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

## Read next

- [Read the stripe.refund.created contract](https://provely.sh/verify/stripe/stripe.refund.created)
- [Read the stripe.refund.succeeded contract](https://provely.sh/verify/stripe/stripe.refund.succeeded)
- [Read the Resend verification page](https://provely.sh/verify/resend)
- [Read the Shopify Admin API verification page](https://provely.sh/verify/shopify)
- [See every verified service](https://provely.sh/verify)
- [Verify Stripe actions from Claude Code](https://provely.sh/agents/claude-code)
- [Verify Stripe 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 the completion level definition](https://provely.sh/glossary/completion-level)
