# Real provider readback: Stripe test mode

On 1 November 2026, Curbi's refund service was exercised against the real Stripe test API. This was a local SQLite execution using the existing Stripe CLI test login, not a hosted Worker or a live-money refund. No private signing key or Stripe credential is included in these artifacts.

## Observed result

- Fresh $1 test payment, scoped to one Charge; configured refund ceiling: 50 cents USD.
- A 51-cent request was rejected before dispatch.
- One 50-cent refund POST reached Stripe. Its separate readback response was deliberately lost. The service returned UNKNOWN, issued no completion receipt and refused completion-bundle export.
- The SQLite connection was closed and reopened. Same-version policy widening was rejected.
- Recovery used authenticated GET requests, including the bound test Charge and refund history. It did not POST another refund.
- After matching confirmation, one receipt and one log leaf were committed. Another SQLite reopen returned the identical receipt.
- A separate Stripe read showed exactly one refund for that Charge, succeeded, for the bound amount/currency/operation.
- Offline verification accepted the issuer signature, inclusion proof and exported observation digest. Changing the exported amount caused rejection.

[Machine-readable report](https://curbi.io/proof/evidence/stripe-test-2026-11-01/report.json) · [Receipt bundle](https://curbi.io/proof/evidence/stripe-test-2026-11-01/bundle.json) · [Public test keys](https://curbi.io/proof/evidence/stripe-test-2026-11-01/trusted-test-keys.json)

## The bug the real provider exposed

The adapter's synthetic Refund objects included `livemode:false`. Stripe's actual [Refund object](https://docs.stripe.com/api/refunds/object) has no such field. Requiring it incorrectly held a successful refund as UNKNOWN. The adapter now establishes test mode through its test credential, authenticated account and matching Charge with `livemode:false`; recovery re-reads that Charge. Contradictory mode markers, missing Charge evidence and mismatched bindings remain rejected.

The first qualification failed safely with no completion receipt. A second attempt reached confirmation but exposed a query-parameter issue in the CLI qualification transport's independent count check. The final retained run corrected that transport and passed all assertions. These were separate disposable test payments, not repeated refunds of one Charge.

## Inspect the observation offline

Download these three modules/files together:

```sh
curl -fsS https://curbi.io/downloads/curbi-provider-evidence.mjs -o curbi-provider-evidence.mjs
curl -fsS https://curbi.io/downloads/curbi-proof.mjs -o curbi-proof.mjs
curl -fsS https://curbi.io/proof/evidence/stripe-test-2026-11-01/bundle.json -o bundle.json
curl -fsS https://curbi.io/proof/evidence/stripe-test-2026-11-01/trusted-test-keys.json -o trusted-test-keys.json
node --input-type=module -e 'import {readFileSync as read} from "node:fs"; import {verifyProviderEvidence} from "./curbi-provider-evidence.mjs"; const result=await verifyProviderEvidence(JSON.parse(read("bundle.json")),{keys:JSON.parse(read("trusted-test-keys.json")),allowTest:true}); console.log(result); if(!result.ok)process.exit(1);'
```

The public test key is explicitly selected for this demonstration. Production verifiers must establish trusted keys through their own policy; a downloaded bundle cannot grant trust to its embedded keys. This verifier makes no network calls.

## What this establishes

The retained run connects a real provider observation to Curbi's signed statement, persistent local operation state and a verifiable artifact. It does not make the observation Stripe-signed, prove current Stripe state offline, qualify Cloudflare durability, authorize another action, or enable production signing.

Hosted qualification still needs a dedicated restricted Stripe test credential and enrolled private access/policy/signing configuration in an authorized Workers deployment. The current local Cloudflare login has Pages access, not Workers deployment access. Live-money execution and production action signing remain disabled.

For developers reproducing locally, the repository runner is `revenue-engine/hosted-proof/qualify-stripe.mjs`. It checks the fixed Curbi account and test-mode login before creating its isolated test fixture; it never extracts credentials. Use a fresh output directory. It retains a local ledger, report, public bundle and public test keys; its ephemeral private signing key stays in process memory.

## Try a configured check

This public example checks a reply against a configured price; it does not authorize an action or establish a provider outcome.

```sh
curl -sS https://api.curbi.io/v1/check \
  -H 'Content-Type: application/json' \
  -d '{"policy":{"prices":[{"item":"Starter","amount":49}]},"reply":"Starter is $99."}'
```

Expect `pass: false` with `price:mismatch`.

Next: [install a framework adapter](https://curbi.io/connect/) or [start with a working policy](https://curbi.io/policies/).
