# Provely > Provely verifies that an AI agent action reached the promised outcome before the agent reports success. The agent does the action. A separate verifier reads the provider and signs an Ed25519 receipt. Canonical site: https://provely.sh Last reviewed: 2026-09-05 Every page has a Markdown twin at the same path with the .md suffix. The full text of the key pages is in /llms-full.txt. The machine-readable claims are in /facts. ## Product - [Provely: outcome verification for AI agents](https://provely.sh/index.md): An agent says "done" when it is not. Provely checks the outcome against the provider before the agent reports success, and signs a receipt. - [How Provely verifies an agent action](https://provely.sh/how-it-works.md): Provely keeps intent, action, acknowledgement, outcome, and completion apart, runs one frozen state machine, and ranks evidence from E0 to E5. - [Completion contracts: the definition of done](https://provely.sh/contracts.md): A completion contract is a versioned document that states which evidence proves one outcome. Read the schema and a worked Stripe refund example. - [Evidence receipts: signed proof of a verdict](https://provely.sh/receipts.md): A receipt names the contract, its version and hash, the evidence, the observations, and the verdict. It is signed with Ed25519. Validate it offline. - [The false-completion benchmark](https://provely.sh/benchmark.md): The benchmark lists the cases where an agent action looks done and is not. Every skill must pass all of them with zero false VERIFIED before it ships. - [Provely pricing: plans per verified action](https://provely.sh/pricing.md): Every plan carries every feature. Developer is free with 1,000 verified actions a month. Startup is $99, Pro is $249, Team is $499. - [Provely changelog](https://provely.sh/changelog.md): What changed in Provely, newest first: the public website, the platform shell, the engines, and the core model. Subscribe with the RSS feed. - [About Provely and Macleod Labs](https://provely.sh/about.md): Macleod Labs builds Provely, a workflow verifier for AI agents. This page names the company and the one contact address. - [Provely terms of service](https://provely.sh/terms.md): The agreement between Macleod Labs and the customer who uses Provely. It covers accounts, credentials, fees, and liability. - [Provely privacy policy](https://provely.sh/privacy.md): What personal data Provely collects, why it collects it, how long it keeps it, who it shares it with, and how to exercise your rights. - [Sign in to Provely](https://provely.sh/signin.md): Sign in with Google or GitHub to verify your first workflow. The free plan verifies 1,000 actions and needs no card. ## Verified services - [Verified services: Stripe, Shopify, Resend](https://provely.sh/verify.md): One page for each service Provely verifies. Each page comes from the signed skill manifest: the completion levels, the lifecycle, the certification. - [Verify Resend actions with Provely](https://provely.sh/verify/resend.md): Was the email sent, or was it delivered? The 4 completion levels, the Resend lifecycle, and the evidence Provely reads. Certification Community. - [Verify Shopify Admin API actions with Provely](https://provely.sh/verify/shopify.md): Does a Shopify Refund object mean the money went back? The 2 completion levels, the Shopify Admin API lifecycle, and the evidence Provely reads. - [Verify Stripe actions with Provely](https://provely.sh/verify/stripe.md): Does a Stripe refund object mean the money moved? The 2 completion levels, the Stripe lifecycle, and the evidence Provely reads. Certification Community. ## Contracts - [resend.email.accepted: the accepted contract](https://provely.sh/verify/resend/resend.email.accepted.md): Prove that Resend accepted the email request. Version 1.0.0, certification Community. Every condition and timing rule of the signed Resend skill. - [resend.email.bounced: the bounced contract](https://provely.sh/verify/resend/resend.email.bounced.md): Prove that the recipient mail server rejected the email. Version 1.0.0, certification Community. - [resend.email.delivered: the delivered contract](https://provely.sh/verify/resend/resend.email.delivered.md): Prove that the recipient mail server accepted the email. Version 1.0.0, certification Community. - [resend.email.sent: the sent contract](https://provely.sh/verify/resend/resend.email.sent.md): Prove that Resend handed the email to its sending infrastructure. Version 1.0.0, certification Community. - [shopify.refund.created: the created contract](https://provely.sh/verify/shopify/shopify.refund.created.md): Prove that Shopify holds a Refund record for the order. Version 1.0.0, certification Community. - [Contract: shopify.refund.financially_completed](https://provely.sh/verify/shopify/shopify.refund.financially_completed.md): Prove that the refund transaction succeeded at the gateway. Version 1.0.0, certification Community. - [stripe.refund.created: the created contract](https://provely.sh/verify/stripe/stripe.refund.created.md): Prove that Stripe holds a refund for the charge. Version 1.0.0, certification Community. Every condition and timing rule of the signed Stripe skill. - [stripe.refund.succeeded: the succeeded contract](https://provely.sh/verify/stripe/stripe.refund.succeeded.md): Prove that the refund reached the succeeded state. Version 1.0.0, certification Community. Every condition and timing rule of the signed Stripe skill. ## Agent integrations - [Agent integrations: Claude Code, Cursor, Codex](https://provely.sh/agents.md): Provely works with any agent through four surfaces: REST API, MCP server, CLI, and SDKs. One page per agent, with its guidance files and enforcement. - [Verify Claude Code actions with Provely](https://provely.sh/agents/claude-code.md): Connect Claude Code to Provely through the MCP server, the CLI, the REST API. The guidance files, the hooks, and the CI gate. - [Verify Codex actions with Provely](https://provely.sh/agents/codex.md): Connect Codex to Provely through the CLI, the REST API. The guidance files, the hooks, and the CI gate. The profile was verified on 2026-09-05. - [Verify Cursor actions with Provely](https://provely.sh/agents/cursor.md): Connect Cursor to Provely through the CLI, the REST API. The guidance files, the hooks, and the CI gate. The profile was verified on 2026-09-05. - [Verify Generic agent actions with Provely](https://provely.sh/agents/generic.md): Connect Generic agent to Provely through the MCP server, the CLI, the SDK, the REST API. The guidance files, the hooks, and the CI gate. - [Verify Grok actions with Provely](https://provely.sh/agents/grok.md): Connect Grok to Provely through the CLI, the REST API. The guidance files, the hooks, and the CI gate. The profile was verified on 2026-09-05. - [Verify Hermes actions with Provely](https://provely.sh/agents/hermes.md): Connect Hermes to Provely through the MCP server, the CLI, the SDK, the REST API. The guidance files, the hooks, and the CI gate. - [Verify LangGraph actions with Provely](https://provely.sh/agents/langgraph.md): Connect LangGraph to Provely through the MCP server, the CLI, the SDK, the REST API. The guidance files, the hooks, and the CI gate. - [Verify OpenAI Agents SDK actions with Provely](https://provely.sh/agents/openai-agents.md): Connect OpenAI Agents SDK to Provely through the MCP server, the CLI, the SDK, the REST API. The guidance files, the hooks, and the CI gate. - [Verify OpenClaw actions with Provely](https://provely.sh/agents/openclaw.md): Connect OpenClaw to Provely through the CLI, the REST API. The guidance files, the hooks, and the CI gate. The profile was verified on 2026-09-05. - [Verify pi actions with Provely](https://provely.sh/agents/pi.md): Connect pi to Provely through the CLI, the REST API. The guidance files, the hooks, and the CI gate. The profile was verified on 2026-09-05. ## Documentation - [Provely documentation](https://provely.sh/docs.md): The quick start, the TypeScript and Python SDKs, the provely CLI, the MCP server, and the REST API reference. Every page answers first. - [Quick start: verify a Stripe refund](https://provely.sh/docs/quick-start.md): Open an operation against stripe.refund.succeeded, make the refund call with the idempotency key, submit the result, and verify. Ten minutes. - [Intent compilation: prompt to contract](https://provely.sh/docs/intent-compilation.md): You pass the prompt, the context and the tools. Provely compiles a completion contract, you confirm it, and the receipt binds the ask to the promise. - [Verdicts, retries, and directives](https://provely.sh/docs/verdicts.md): What each verdict means and what an agent may do next. PENDING waits. FAILED retries with the first idempotency key. CONTRADICTED stops for a person. - [Integration compiler: one signed skill](https://provely.sh/docs/integration-compiler.md): The compiler reads a vendor schema, its documents, its events and its sandbox behaviour, then signs one skill. Six stages and six confidence dimensions. - [SDKs: TypeScript and Python](https://provely.sh/docs/sdks.md): The Provely SDKs are thin translators into one model: operation, contract, action result, verification, receipt. The types come from the schemas. - [CLI reference: the provely binary](https://provely.sh/docs/cli.md): provely is one static binary: verify and status drive an operation, receipt validate checks a receipt offline, and mcp serves the tools over stdio. - [MCP server: begin, verify, status, receipt](https://provely.sh/docs/mcp.md): The MCP server exposes four tools. Hosted mode uses HTTP with a bearer token. Local mode runs provely mcp over stdio. No tool takes an API key. - [API reference: the /v1 control plane](https://provely.sh/docs/api.md): The REST API is the only place verification happens: operations, action results, verify, receipts, events, contracts, skills, and usage under /v1. - [Version support: five version dimensions](https://provely.sh/docs/version-support.md): Provely tracks the provider API version, the event payload version, the SDK version, the protocol version, and the agent host version, each on its own. - [Security: the credential boundary](https://provely.sh/docs/security.md): The agent holds the action credentials. Provely holds read-only verifier credentials. No surface mixes them or returns a credential to an agent. ## Glossary - [Provely glossary](https://provely.sh/glossary.md): One-sentence definitions of the Provely terms: intent, action, acknowledgement, outcome, completion, correlation, idempotency, evidence level, verdict. - [Intent: Provely glossary](https://provely.sh/glossary/intent.md): What the user asked for, stated before any action. The Provely definition, with an example. - [Action: Provely glossary](https://provely.sh/glossary/action.md): What the agent attempted against the provider. The Provely definition, with an example. - [Acknowledgement: Provely glossary](https://provely.sh/glossary/acknowledgement.md): What the provider returned at once, such as HTTP 200 and an object. The Provely definition, with an example. - [Outcome: Provely glossary](https://provely.sh/glossary/outcome.md): The observable resulting state in the real system. The Provely definition, with an example. - [Completion: Provely glossary](https://provely.sh/glossary/completion.md): The outcome satisfies the completion contract. The Provely definition, with an example. - [Completion contract: Provely glossary](https://provely.sh/glossary/completion-contract.md): A machine-readable, versioned, hashable definition of done for one operation. The Provely definition, with an example. - [Completion level: Provely glossary](https://provely.sh/glossary/completion-level.md): One named promise of a service, proven by one contract. The Provely definition, with an example. - [Correlation: Provely glossary](https://provely.sh/glossary/correlation.md): The binding of evidence to the exact operation through keys such as a resource id. The Provely definition, with an example. - [Idempotency: Provely glossary](https://provely.sh/glossary/idempotency.md): The property that a retried request creates no second side effect. The Provely definition, with an example. - [Evidence level: Provely glossary](https://provely.sh/glossary/evidence-level.md): The rank of a piece of evidence by its independence from the action path, E0 to E5. The Provely definition, with an example. - [Verdict: Provely glossary](https://provely.sh/glossary/verdict.md): The result of one verification attempt: VERIFIED, PENDING, CONTRADICTED, FAILED, or UNVERIFIABLE. The Provely definition, with an example. - [PENDING: Provely glossary](https://provely.sh/glossary/pending.md): The verdict while an operation can still make progress. The Provely definition, with an example. - [UNVERIFIABLE: Provely glossary](https://provely.sh/glossary/unverifiable.md): The verdict when the evidence never became sufficient. The Provely definition, with an example. - [CONTRADICTED: Provely glossary](https://provely.sh/glossary/contradicted.md): The verdict when the evidence shows a different outcome than the intent. The Provely definition, with an example. - [False VERIFIED: Provely glossary](https://provely.sh/glossary/false-verified.md): A VERIFIED verdict for an outcome that did not happen. The highest-severity defect. The Provely definition, with an example. - [Evidence receipt: Provely glossary](https://provely.sh/glossary/receipt.md): A signed, machine-readable record of what was verified and how. The Provely definition, with an example. - [Service verification skill: Provely glossary](https://provely.sh/glossary/skill.md): A signed package of contracts, lifecycles, evidence channels, and tests for one provider. The Provely definition, with an example. - [Conformance: Provely glossary](https://provely.sh/glossary/conformance.md): The mandatory test matrix a skill must pass before certification. The Provely definition, with an example. - [Intent compilation: Provely glossary](https://provely.sh/glossary/intent-compilation.md): The step that turns a task in natural language into a completion contract. The Provely definition, with an example. - [Intent fidelity: Provely glossary](https://provely.sh/glossary/intent-fidelity.md): The agreement between what the user asked for and what the contract checks. The Provely definition, with an example. - [REQUIRES_REVIEW: Provely glossary](https://provely.sh/glossary/requires-review.md): The mark on a part of a task that no contract can check. The Provely definition, with an example. - [Drift: Provely glossary](https://provely.sh/glossary/drift.md): A change in a provider schema, docs, or behaviour that can change a contract. The Provely definition, with an example. ## Comparisons - [Comparisons: verification against other tools](https://provely.sh/compare.md): Honest comparisons of outcome verification with observability, LLM evaluation, and testing. Each answers a different question. Provely adds the verdict. - [Outcome verification against observability](https://provely.sh/compare/verification-vs-observability.md): Observability shows what your system did. Outcome verification decides whether the provider reached the promised state. They answer two questions. - [Outcome verification against LLM evaluation](https://provely.sh/compare/verification-vs-evaluation.md): LLM evaluation scores a model output against a rubric or a judge. Outcome verification reads the real state after a side effect. A judge is no proof. - [Outcome verification against testing](https://provely.sh/compare/verification-vs-testing.md): A test runs before release against fixtures and mocks. Outcome verification runs after each production action against the real provider. Use both. ## Machine surfaces - [Facts](https://provely.sh/facts): the contracts, levels, and certifications as JSON-LD. - [Sitemap](https://provely.sh/sitemap.xml): every route, once. - [Changelog feed](https://provely.sh/changelog.xml): the RSS feed. --- # Your agent said refunded. Stripe said pending. > An agent says "done" when it is not. Provely checks the outcome against the provider before the agent reports success, and signs a receipt. Canonical: https://provely.sh Last reviewed: 2026-09-05 **A 200 response proves a refund object exists. It does not prove the money moved. Provely reads the provider, not the agent. It holds the word “done” until the provider agrees, then signs a receipt anyone can check offline.** ## Five states. One state moves the money. One operation, one vendor. Each state returns a refund object and HTTP 200. From the response they look the same. - **pending** NO MONEY - **requires_action** NO MONEY - **failed** NO MONEY - **canceled** NO MONEY - **succeeded** MONEY MOVED [Read the five Stripe refund states](/docs/verdicts) ## A workflow is a promise with several parts. An agent can finish three parts and drop the fourth. It still reports success, because a successful tool call is all it sees. Provely writes the parts down first, then checks each one against the system that knows. - **Write a test that fails first** E4 · ci The test file is in the diff. The same test fails on the parent commit. - **Run the whole suite** E4 · ci The run for this commit is complete. No test is skipped or filtered. - **Update the documents** E2 · repository The document files change in the same commit as the code. - **Open the pull request** E2 · readback The pull request exists. Its head commit is the one under test. - **Refund the customer $142** E2 + E3 · stripe Provely reads the refund by id. Amount, currency and payment intent match. - **Restock the returned item** E2 · shopify Provely reads the inventory level, correlated by line item, never by count. - **Email the confirmation** E0 only No message id and no delivery event. Only the agent claims this step. - **Close the support ticket** E2 · helpdesk Provely reads the status from the helpdesk. An open step blocks the workflow. - **Send the payment of $8,400** E4 · bank The bank reports the transfer as settled. A payment object is not enough. - **Mark the invoice as paid** E2 · ledger Provely reads the invoice in the ledger. The paid amount matches the transfer. - **Send the remittance advice** E3 · resend The mail provider reports the message as delivered, not as accepted. - **Never pay the same invoice twice** E4 · bank A second settled transfer for this invoice exists. The negative postcondition fails. - **Create the identity account** E2 · identity The account exists in the directory and holds the correct group. - **Order the laptop** E3 · supplier The supplier confirms the order. A cart is not an order. - **Add the payroll record** E2 · payroll The payroll record carries the start date of the contract. - **Send the welcome note** E5 · outcome The invitation is accepted, so the person received it. - **Hold the calendar slot** E2 · calendar The event exists on both calendars. The time matches the customer request. - **Send the invitation** E5 · outcome The mail provider reports delivery. The customer accepted the event. - **Move the deal to Demo Booked** E2 · crm The stage of this deal id changed. A matching deal at that stage does not count. - **Log the call notes** E0 only No note is on the deal. The agent reported the step as complete. - The agent says “tests pass”. It ran one file. Provely reads the run, not the sentence. - Three steps pass. One has no evidence. The workflow is not done, and Provely says so. - Every positive check passed. The supplier was paid twice. CONTRADICTED, so a person decides. - Four systems, four owners, one promise. One receipt covers the whole workflow. - A pre-existing deal at the right stage must never verify. Provely correlates by deal id. [Read the verdicts and the retry rules](/docs/verdicts) ## You do not write the contract. You pass the prompt. Provely compiles the task into a machine-readable contract: the steps, the evidence that proves each step, and the negative postconditions that catch a duplicate. You confirm the contract once. Its hash goes into the receipt, so an auditor can compare the ask with the promise. - intent "Refund order 4471 for $142 and email the customer." - context { order_id: "4471", customer: "cus_8k2Rv1LmQ9xT" } - tools [stripe.refunds, shopify.inventory, resend.emails] - **stripe.refund.succeeded** E2 + E3 - **shopify.inventory.adjusted** E2 - **resend.email.delivered** E3 No second settled refund exists for this payment intent. “the customer” must resolve to one address. Confirm it before the run. [Read how intent compilation works](/docs/intent-compilation) ## One verifier. Hundreds of vendors. Each vendor draws the line between an acknowledgement and an outcome somewhere else. You never write that logic. The compiler reads the vendor’s schema, documents, events and sandbox behaviour, and signs one skill. A new vendor is a command, not a project. ### The first three skills - Accepted, sent and delivered are three different promises. - A Refund record does not prove that money left the merchant. - A refund object records a request. It does not record a transfer. [Read how the integration compiler works](/docs/integration-compiler) ## Does a successful call mean the work is done? ### Does a Resend send call mean the email was delivered? No. The email holds one of 12 states. `delivered`, `opened` and `clicked` are terminal success. The Resend skill proves `accepted`, `bounced`, `delivered`, `sent` as separate promises, at certification community. Source: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05. ### Does a Shopify Refund object mean money moved? No. The order_transaction holds one of 6 states, and only `SUCCESS` is terminal success. The Shopify Admin API skill proves `created`, `financially_completed` as separate promises, at certification community. Source: [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07), retrieved 2026-09-05. ### Does a successful Stripe refund call mean the customer got the money? No. The refund holds one of 5 states, and only `succeeded` is terminal success. The Stripe skill proves `created`, `succeeded` as separate promises, at certification community. Source: [stripe.openapi](https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json), retrieved 2026-09-05. ## Get your first verdict in ten minutes. Open an operation, run your agent, then ask for the verdict. Provely reads the provider and signs the receipt. The free plan verifies 1,000 actions. ## Read next - [Read how Provely works](https://provely.sh/how-it-works) - [Read the Resend verification page](https://provely.sh/verify/resend) - [Read the Shopify Admin API verification page](https://provely.sh/verify/shopify) - [Read the Stripe verification page](https://provely.sh/verify/stripe) - [Read what a receipt proves](https://provely.sh/receipts) - [Read the pricing](https://provely.sh/pricing) - [Open the quick start](https://provely.sh/docs/quick-start) --- # How does Provely decide that an agent action is done? > Provely keeps intent, action, acknowledgement, outcome, and completion apart, runs one frozen state machine, and ranks evidence from E0 to E5. Canonical: https://provely.sh/how-it-works Last reviewed: 2026-09-05 **Provely reads the real system after the agent acts, evaluates a versioned completion contract against that evidence, and returns one of five verdicts. The agent never decides.** The agent keeps its write credentials and makes the same API call. A separate verifier reads the provider with read-only credentials and signs a receipt. An agent report is E0, and E0 is never sufficient. ## Where does the contract come from? You pass the agent prompt, the context and the tools. Provely compiles the completion contract, and you confirm it before it runs. You never write the contract by hand. A language model may propose the contract. The contract decides completion, and a language model judgement is never completion evidence. A part of the task that no contract can check is marked REQUIRES_REVIEW. Read [intent compilation](/docs/intent-compilation). ## What are the five concepts that most agent stacks collapse? Provely keeps five concepts apart in the data model, the API, and the interface. *Figure: The five concepts, on the Stripe refund example.* - Intent: what the user asked for. - Action: what the agent attempted. - Acknowledgement: what the provider returned at once. - Outcome: the observable resulting state. - Completion: the outcome satisfies the contract. Only this earns VERIFIED. | Concept | Question it answers | Stripe refund example | | --- | --- | --- | | [Intent](/glossary/intent) | What did the user ask for? | Refund USD 142.00 to customer cus_8k2. | | [Action](/glossary/action) | What did the agent attempt? | `POST /v1/refunds` with an idempotency key. | | [Acknowledgement](/glossary/acknowledgement) | What did the provider return at once? | HTTP 200 and a refund object with `status: pending`. | | [Outcome](/glossary/outcome) | What state does the provider hold now? | `status: succeeded` on a readback. | | [Completion](/glossary/completion) | Does the outcome satisfy the contract? | Amount, charge, and status match. No duplicate. VERIFIED. | ## Which states can an operation be in? **An operation moves through one frozen state machine: CREATED, ACTION_STARTED, ACTION_ACCEPTED, OBSERVING, PENDING, and then one terminal state. The terminal states are VERIFIED, CONTRADICTED, FAILED, UNVERIFIABLE, EXPIRED, and HUMAN_REVIEW.** *Figure: The operation state machine. No plugin can change it.* - CREATED moves to ACTION_STARTED when the agent begins the action. - ACTION_STARTED moves to ACTION_ACCEPTED when the provider acknowledges. - ACTION_ACCEPTED moves to OBSERVING when the verifier starts to read evidence. - OBSERVING moves to PENDING while the evidence is not sufficient. - PENDING moves to VERIFIED, CONTRADICTED, FAILED, UNVERIFIABLE, EXPIRED, or HUMAN_REVIEW. | Verdict | Meaning | Example | | --- | --- | --- | | VERIFIED | Every positive postcondition holds and no negative one holds. | The refund shows `succeeded` for the right amount and charge. | | [PENDING](/glossary/pending) | The operation can still make progress. | The refund shows `pending` or `requires_action`. | | [CONTRADICTED](/glossary/contradicted) | The evidence shows an outcome the intent does not allow. | Two refunds exist for one operation. | | FAILED | The provider reports a terminal failure. | The refund shows `failed` or `canceled`. | | [UNVERIFIABLE](/glossary/unverifiable) | The evidence never became sufficient. | The readback stayed unavailable until the deadline. | | HUMAN_REVIEW | A person must decide. | The contract escalates a timeout to a person. | ## What are the frozen safety rules? 1. **A false VERIFIED is the highest-severity defect.** When evidence is not sufficient, the answer is UNVERIFIABLE. 2. **Progress is not failure.** While an operation can still complete, the answer is PENDING, never FAILED. 3. **An agent assertion is never sufficient.** E0 cannot support VERIFIED, alone or combined. 4. **Acknowledgement is never terminal success.** HTTP 200 and an object id prove only that a request was accepted. 5. **Evidence must correlate with the exact operation.** A matching state that already existed must not verify. 6. **The verifier reads with read-only credentials** where the provider permits it. The agent never holds them. > A pre-existing refund for the same amount is the classic false proof. A search by amount finds it. A correlation by refund id and payment intent does not. ## What does a false completion look like? **A Shopify refund shows it. The mutation succeeds, the Refund object exists, and the webhook fires. The money has not moved: the order transaction is still PENDING. Two promises, two contracts.** *Figure: A Refund object exists while the order transaction is still pending, so the money did not move.* - The refundCreate mutation succeeds. - The Refund object exists and the refunds/create webhook fires. Neither proves that money moved. - The OrderTransaction still shows PENDING. - Money moved is not yet true. The financially_completed contract proves it. The created contract does not. The [Shopify page](/verify/shopify) states the contracts and the evidence that separate the two promises. ## Why is not all evidence equal? **Provely ranks evidence by its independence from the action path. E0 is the agent word. E5 is an external outcome, such as a bank credit. The runtime prefers the more independent level.** *Figure: The evidence hierarchy. E0 is never sufficient.* - E0 agent assertion: never sufficient. - E1 action response: proves acknowledgement, rarely completion. - E2 provider readback: deterministic state, subject to stale reads. - E3 provider event: strong timing, needs deduplication and ordering. - E4 independent system: the provider plus your own ledger. - E5 external outcome: a bank, a carrier, or a recipient acknowledgement. ## What happens between the action and the answer? *Figure: One operation, from begin to receipt.* - begin: the agent opens an operation against a contract and gets an idempotency key. - act: the agent makes the provider call with that key. - action_result: the agent submits the provider acknowledgement. - verify: the runtime reads the provider and evaluates the contract. - receipt: the runtime signs the verdict with Ed25519. *The action stays yours* ```typescript const op = await provely.begin({ contract: 'stripe.refund.succeeded', input: { charge_id, amount_cents: 14200 }, }); const refund = await stripe.refunds.create( { charge: charge_id, amount: 14200 }, { idempotencyKey: op.idempotency_key }, ); await op.actionResult(refund); const verification = await op.verify(); // verification.verdict is VERIFIED, PENDING, CONTRADICTED, FAILED, or UNVERIFIABLE. // Report it exactly as returned. ``` ## Which cases must every skill pass before it ships? *The mandatory conformance matrix.* | Scenario | Required verdict | | --- | --- | | Action accepted, terminal success confirmed | VERIFIED | | Action accepted, provider still transitional | PENDING | | Provider reports terminal failure | FAILED | | Correct resource, wrong amount or subject | CONTRADICTED | | Duplicate side effect for one operation | CONTRADICTED | | Readback stale inside the consistency window | PENDING | | Evidence unavailable until the timeout | UNVERIFIABLE | | Pre-existing matching state, no causal link | Must not verify | | Webhook duplicated | No duplicate transition | | Webhook out of order | Reconciled by provider semantics, not arrival order | | Contract or provider version not supported | UNVERIFIABLE with reason version_unsupported | ### Can a plugin change what VERIFIED means? No. A plugin adds an evidence channel or an operator. The state machine, the verdicts, and the safety rules are frozen. ### What does the agent say while the verdict is PENDING? It says: "The action is accepted but not yet verified. Operation: ." Any caller can check that id later. ## Read next - [Read what a completion contract contains](https://provely.sh/contracts) - [Read what a signed receipt proves](https://provely.sh/receipts) - [Read the Stripe verification page](https://provely.sh/verify/stripe) - [Read the evidence level definition](https://provely.sh/glossary/evidence-level) --- # Which services does Provely verify? > One page for each service Provely verifies. Each page comes from the signed skill manifest: the completion levels, the lifecycle, the certification. Canonical: https://provely.sh/verify Last reviewed: 2026-09-05 **Provely verifies Resend, Shopify Admin API and Stripe today. Each service page is generated from the signed skill package, so it never claims a completion level the skill does not certify.** | Service | Completion levels | Certification | Skill version | Last conformance run | | --- | --- | --- | --- | --- | | [Resend](/verify/resend) | `accepted`, `bounced`, `delivered`, `sent` | Community | 0.1.0 | 2026-09-05T12:00:00Z | | [Shopify Admin API](/verify/shopify) | `created`, `financially_completed` | Community | 0.1.0 | 2026-09-05T12:00:00Z | | [Stripe](/verify/stripe) | `created`, `succeeded` | Community | 0.1.0 | 2026-09-05T12:00:00Z | ## How is a service page made? 1. The Integration Compiler reads the provider schema, docs, event samples, and sandbox experiments. 2. It classifies side effects, infers lifecycles, discovers evidence channels, and synthesizes contracts and tests. 3. The conformance harness runs the false-completion benchmark against the skill. 4. The compiler certifies and signs the manifest. 5. This site renders the page from that manifest. A skill change updates the page. ### How do I get a service that is not listed? Run `provely skill generate --openapi ` to draft a skill from a schema, review the uncertainties, and run the conformance matrix. A service becomes a compilation and conformance problem, not an integration project. ## Read next - [Read the Resend verification page](https://provely.sh/verify/resend) - [Read the Shopify Admin API verification page](https://provely.sh/verify/shopify) - [Read the Stripe verification page](https://provely.sh/verify/stripe) - [Read the false-completion benchmark](https://provely.sh/benchmark) - [Read what a completion contract contains](https://provely.sh/contracts) --- # Was the email sent, or was it delivered? > Was the email sent, or was it delivered? The 4 completion levels, the Resend lifecycle, and the evidence Provely reads. Certification Community. Canonical: https://provely.sh/verify/resend Last reviewed: 2026-09-05 Skill version: 0.1.0 Certification: community **No. Resend returns a send response with an email id when it accepts the request. The email then holds one of 12 states. Provely proves `accepted`, `bounced`, `delivered` and `sent` 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: 58 of 60 cases passed, 0 critical false VERIFIED | | Provider API versions | `1.5.1` | | Default provider API version | `1.5.1` | | Compiled | 2026-09-05T12:00:00Z by compiler 0.1.0 | | Manifest hash | `bb3243d9753c7608` | | 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 accepted level proves that Resend holds an email record for the request. It does not prove that the message left the provider. | [resend.email.accepted](/verify/resend/resend.email.accepted) | E2 | proven | | The bounced level proves the bounced state on the email record and the email.bounced event. Use it when the intent is to confirm a rejection, for example before a suppression. | [resend.email.bounced](/verify/resend/resend.email.bounced) | E2 + E3 | proven | | The delivered level proves the delivered state on the email record and the email.delivered event. It does not prove that a person read the message. This level needs the email.delivered webhook. | [resend.email.delivered](/verify/resend/resend.email.delivered) | E2 + E3 | proven | | The sent level proves the email.sent event of this email. It does not prove that the recipient mail server accepted the message. This level needs the email.sent webhook. | [resend.email.sent](/verify/resend/resend.email.sent) | E2 + E3 | proven | | An outcome outside Resend, 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 Resend 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 | | --- | --- | --- | --- | --- | | `accepted` | [resend.email.accepted](/verify/resend/resend.email.accepted) v1.0.0 | The accepted level proves that Resend holds an email record for the request. It does not prove that the message left the provider. | E2 | Community | | `bounced` | [resend.email.bounced](/verify/resend/resend.email.bounced) v1.0.0 | The bounced level proves the bounced state on the email record and the email.bounced event. Use it when the intent is to confirm a rejection, for example before a suppression. | E2 + E3 | Community | | `delivered` | [resend.email.delivered](/verify/resend/resend.email.delivered) v1.0.0 | The delivered level proves the delivered state on the email record and the email.delivered event. It does not prove that a person read the message. This level needs the email.delivered webhook. | E2 + E3 | Community | | `sent` | [resend.email.sent](/verify/resend/resend.email.sent) v1.0.0 | The sent level proves the email.sent event of this email. It does not prove that the recipient mail server accepted the message. This level needs the email.sent webhook. | E2 + E3 | Community | ## What is the Resend lifecycle? ### Which states can a `resend.email` be in? | State | Class | Verdict | Meaning | Source | | --- | --- | --- | --- | --- | | `queued` | transitional | PENDING | Resend accepted the message and holds it in its queue. | [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml) | | `scheduled` | transitional | PENDING | The message waits for its scheduled send time. | [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml) | | `sent` | transitional | PENDING | Resend handed the message to its sending infrastructure and attempts delivery. | [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml) | | `delivery_delayed` | transitional | PENDING | The recipient mail server did not accept the message yet. Resend retries. | [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml) | | `delivered` | terminal success | VERIFIED | The recipient mail server accepted the message. | [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml) | | `opened` | terminal success | VERIFIED | The recipient opened the message. Delivery happened before. | [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml) | | `clicked` | terminal success | VERIFIED | The recipient clicked a link in the message. Delivery happened before. | [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml) | | `complained` | terminal neutral | FAILED | The message was delivered, and the recipient marked it as spam. | [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml) | | `bounced` | terminal failure | FAILED | The recipient mail server rejected the message. | [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml) | | `failed` | terminal failure | FAILED | Resend could not send the message. | [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml) | | `suppressed` | terminal failure | FAILED | Resend suppressed the message because the recipient address is on a suppression list. | [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml) | | `canceled` | terminal neutral | FAILED | The schedule of the message was canceled before the send. | [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml) | In `resend.email` under provider API version `1.5.1`, `delivered`, `opened` and `clicked` are the only states that mean terminal success. Every other state gives PENDING, FAILED, or UNVERIFIABLE. Source: https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml (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 | email_id from `$action.result.id` | yes | none | | `idempotency_key` | strong | idempotency_key from `$operation.id` | no | none | | `fingerprint` | weak | to from `$input.to`; subject from `$input.subject` | 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 Resend is E1 and never terminal success. | Channel | Level | Independence | Verifier | Deterministic | Typical latency | | --- | --- | --- | --- | --- | --- | | `email_action_response` | E1 | same response | `action_result` | yes | not stated | | `bounced_events` | E3 | provider event | `webhook` | no | 5000 ms | | `delivered_events` | E3 | provider event | `webhook` | no | 5000 ms | | `sent_events` | E3 | provider event | `webhook` | no | 5000 ms | | `sent_events_by_intent` | E3 | provider event | `webhook` | no | 5000 ms | | `email_readback` | E2 | provider readback | `http` | yes | 300 ms | ## Which ways can a Resend action look done and not be? | Contract | Case | Rule | Verdict | | --- | --- | --- | --- | | [resend.email.accepted](/verify/resend/resend.email.accepted) | wrong subject | The message went to a different recipient. | CONTRADICTED | | [resend.email.accepted](/verify/resend/resend.email.accepted) | pre existing state | The provider record is older than the operation. It proves nothing. | CONTRADICTED | | [resend.email.accepted](/verify/resend/resend.email.accepted) | partial completion | The record lists more than one recipient. This contract proves the outcome for one recipient. Use one operation per recipient. | CONTRADICTED | | [resend.email.accepted](/verify/resend/resend.email.accepted) | duplicate side effect | Resend sent more than one email for this recipient and subject since the operation started. Do not retry. | CONTRADICTED | | [resend.email.accepted](/verify/resend/resend.email.accepted) | observed state | The provider reports that the message failed, bounced, or was suppressed. | FAILED | | [resend.email.accepted](/verify/resend/resend.email.accepted) | observed state | The schedule of the message was canceled. The provider will not send it. | CONTRADICTED | | [resend.email.bounced](/verify/resend/resend.email.bounced) | wrong subject | The message went to a different recipient. | CONTRADICTED | | [resend.email.bounced](/verify/resend/resend.email.bounced) | pre existing state | The provider record is older than the operation. It proves nothing. | CONTRADICTED | | [resend.email.bounced](/verify/resend/resend.email.bounced) | partial completion | The record lists more than one recipient. This contract proves the outcome for one recipient. Use one operation per recipient. | CONTRADICTED | | [resend.email.bounced](/verify/resend/resend.email.bounced) | duplicate side effect | Resend sent more than one email for this recipient and subject since the operation started. Do not retry. | CONTRADICTED | | [resend.email.bounced](/verify/resend/resend.email.bounced) | observed state | The provider reports that the message failed, bounced, or was suppressed. | FAILED | | [resend.email.bounced](/verify/resend/resend.email.bounced) | observed state | The message is on the way. The runtime observes again later. | PENDING | | [resend.email.bounced](/verify/resend/resend.email.bounced) | observed state | The schedule of the message was canceled. The provider will not send it. | CONTRADICTED | | [resend.email.bounced](/verify/resend/resend.email.bounced) | observed state | The recipient mail server accepted the message. It did not bounce. | CONTRADICTED | | [resend.email.delivered](/verify/resend/resend.email.delivered) | wrong subject | The message went to a different recipient. | CONTRADICTED | | [resend.email.delivered](/verify/resend/resend.email.delivered) | pre existing state | The provider record is older than the operation. It proves nothing. | CONTRADICTED | | [resend.email.delivered](/verify/resend/resend.email.delivered) | partial completion | The record lists more than one recipient. This contract proves the outcome for one recipient. Use one operation per recipient. | CONTRADICTED | | [resend.email.delivered](/verify/resend/resend.email.delivered) | duplicate side effect | Resend sent more than one email for this recipient and subject since the operation started. Do not retry. | CONTRADICTED | | [resend.email.delivered](/verify/resend/resend.email.delivered) | observed state | The provider reports that the message failed, bounced, or was suppressed. | FAILED | | [resend.email.delivered](/verify/resend/resend.email.delivered) | observed state | The message is on the way. The runtime observes again later. | PENDING | | [resend.email.delivered](/verify/resend/resend.email.delivered) | observed state | The schedule of the message was canceled. The provider will not send it. | CONTRADICTED | | [resend.email.delivered](/verify/resend/resend.email.delivered) | observed state | The recipient marked the message as spam. The record no longer states the delivery state. | UNVERIFIABLE | | [resend.email.sent](/verify/resend/resend.email.sent) | wrong subject | The message went to a different recipient. | CONTRADICTED | | [resend.email.sent](/verify/resend/resend.email.sent) | pre existing state | The provider record is older than the operation. It proves nothing. | CONTRADICTED | | [resend.email.sent](/verify/resend/resend.email.sent) | partial completion | The record lists more than one recipient. This contract proves the outcome for one recipient. Use one operation per recipient. | CONTRADICTED | | [resend.email.sent](/verify/resend/resend.email.sent) | duplicate side effect | Resend sent more than one email for this recipient and subject since the operation started. Do not retry. | CONTRADICTED | | [resend.email.sent](/verify/resend/resend.email.sent) | observed state | The provider reports that the message failed, bounced, or was suppressed. | FAILED | | [resend.email.sent](/verify/resend/resend.email.sent) | observed state | The message is on the way. The runtime observes again later. | PENDING | | [resend.email.sent](/verify/resend/resend.email.sent) | observed state | The schedule of the message was canceled. The provider will not send it. | CONTRADICTED | ## What did the last conformance run show? *The six confidence dimensions of the signed manifest.* | Dimension | Score | Maximum | | --- | --- | --- | | Documentation | 14 | 20 | | Schema alignment | 12.31 | 15 | | Lifecycle certainty | 20 | 20 | | Evidence strength | 12 | 20 | | Causal correlation | 15 | 15 | | Sandbox conformance | 9.67 | 10 | | Raw score | 82.98 | 100 | | Score after the caps | 49 | 100 | The raw score is 82.98. 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 | 2 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 58 of 60 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 | 4 | 4 | | error after execution | 4 | 4 | | error before execution | 4 | 4 | | evidence unavailable | 4 | 4 | | idempotent retry | 3 | 4 | | pre existing state | 4 | 4 | | stale readback | 4 | 4 | | still transitional | 4 | 4 | | terminal failure | 4 | 4 | | terminal success | 3 | 4 | | timeout after commit | 4 | 4 | | version mismatch | 4 | 4 | | webhook duplicate | 4 | 4 | | webhook out of order | 4 | 4 | | wrong subject | 4 | 4 | The conformance artifact digest is `9e6ec913dfe29cd9`. The harness signs the run, so a reader can check that these numbers come from that run. ## What remains uncertain? **Open questions remain. 2 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 | | --- | --- | --- | --- | | [resend.docs.idempotency](https://resend.com/docs/dashboard/emails/idempotency-keys) | docs | 2026-09-05 | authored | | [resend.docs.webhooks](https://resend.com/docs/dashboard/webhooks/introduction) | docs | 2026-09-05 | authored | | [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml) | openapi | 2026-09-05 | trimmed | ## How do I verify a Resend action? ### Verify a Resend action with Provely 1. **Begin the operation.** Call `begin` with the contract `resend.email.accepted` and the input. Keep the operation id and the idempotency key. 2. **Make the Resend 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 Resend response. This is evidence level E1. It is not completion. 4. **Verify.** Call `verify`. The runtime reads `email_action_response`, `bounced_events`, `delivered_events`, `sent_events`, `sent_events_by_intent` and `email_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 `accepted` level prove the `sent` level? No. The accepted level proves that Resend holds an email record for the request. It does not prove that the message left the provider. The sent level proves the email.sent event of this email. It does not prove that the recipient mail server accepted the message. This level needs the email.sent webhook. Use `resend.email.sent` to prove `sent`. ### What does the agent say while Resend reports `queued`, `scheduled`, `sent` and `delivery_delayed`? It says: "The action is accepted but not yet verified. Operation: ." The verdict is PENDING. The runtime observes again on the contract timing policy. ### Which Resend API versions does the skill support? `1.5.1`. An operation on another version returns UNVERIFIABLE with the reason `version_unsupported`. The runtime never guesses. ### Does Provely need write access to Resend? No. The agent keeps its write key. The verifier reads with a separate read-only credential where Resend permits it, and it never shares that credential with the agent. ## Read next - [Read the resend.email.accepted contract](https://provely.sh/verify/resend/resend.email.accepted) - [Read the resend.email.bounced contract](https://provely.sh/verify/resend/resend.email.bounced) - [Read the resend.email.delivered contract](https://provely.sh/verify/resend/resend.email.delivered) - [Read the resend.email.sent contract](https://provely.sh/verify/resend/resend.email.sent) - [Read the Shopify Admin API verification page](https://provely.sh/verify/shopify) - [Read the Stripe verification page](https://provely.sh/verify/stripe) - [See every verified service](https://provely.sh/verify) - [Verify Resend actions from Claude Code](https://provely.sh/agents/claude-code) - [Verify Resend 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) --- # What does resend.email.accepted prove? > Prove that Resend accepted the email request. Version 1.0.0, certification Community. Every condition and timing rule of the signed Resend skill. Canonical: https://provely.sh/verify/resend/resend.email.accepted Last reviewed: 2026-09-05 Skill version: 0.1.0 Certification: community **Prove that Resend accepted the email request. The accepted level proves that Resend holds an email record for the request. It does not prove that the message left the provider.** *Contract identity.* | Fact | Value | | --- | --- | | Contract id | `resend.email.accepted` | | Version | `1.0.0` | | Hash | `c8227388e474f64c` | | Completion level | `accepted` | | Certification | Community | | Skill | [Resend 0.1.0](/verify/resend) | | Valid for provider API versions | `1.5.1` | ## What is the intent? Hand the email to Resend. ## What is the subject and the action? | Member | Value | | --- | --- | | Subject type | `resend.email` | | Subject identity | email_id = `$action.result.id` | | Canonical effect | `message.send` | | Provider operation | `POST /emails` | | Idempotency | idempotency_key through `Idempotency-Key`, retry is safe | ## How does the evidence correlate with this operation? | Strategy | Assurance | Keys | Required | | --- | --- | --- | --- | | `resource_id` | strong | email_id from `$action.result.id` | yes | | `idempotency_key` | strong | idempotency_key from `$operation.id` | no | | `fingerprint` | weak | to from `$input.to`; subject from `$input.subject` | no | ## Which evidence does the contract require? Minimum evidence level `E2`. An independent channel is required. Minimum channels: 1. | Channel | Level | Independence | Verifier | Description | | --- | --- | --- | --- | --- | | `email_readback` | E2 | provider readback | `http` | Read the email record. The http verifier returns the parsed Email object, so a condition path is $observed.email_readback.last_event. | | `sent_events_by_intent` | E3 | provider event | `webhook` | The email.sent events for the same recipient and subject since the operation started. A count above one shows a second send. The webhook verifier returns {events, count, latest, earliest, types, duplicates_dropped}, so a condition reads the count. | ## Which conditions must all hold for VERIFIED? | Condition | Meaning | Path | Operator | Expected | Evidence | | --- | --- | --- | --- | --- | --- | | `record_created_in_window` | The provider created the email record after the operation started. | `$observed.email_readback.created_at` | `time_after` | `$operation.created_at` | `email_readback` | | `record_present` | The provider holds the email record with the returned id. | `$observed.email_readback.id` | `eq` | `$action.result.id` | `email_readback` | ## Which conditions give CONTRADICTED? | Condition | Class | Reason | Path | Operator | Expected | | --- | --- | --- | --- | --- | --- | | `wrong_recipient` | wrong subject | The message went to a different recipient. | `$observed.email_readback.to` | `ne` | `$input.to` | | `record_predates_operation` | pre existing state | The provider record is older than the operation. It proves nothing. | `$observed.email_readback.created_at` | `time_before` | `$operation.created_at` | | `more_than_one_recipient` | partial completion | The record lists more than one recipient. This contract proves the outcome for one recipient. Use one operation per recipient. | `$observed.email_readback.to` | `array_length` | `{"min":2}` | | `duplicate_email_present` | duplicate side effect | Resend sent more than one email for this recipient and subject since the operation started. Do not retry. | `$observed.sent_events_by_intent.count` | `gt` | `1` | ## Which observed states map to a verdict before completion? | Rule | Match | Verdict | Reason | | --- | --- | --- | --- | | `terminal_failure` | `$observed.email_readback.last_event` in `["failed","suppressed"]` | FAILED | The provider reports that the message failed, bounced, or was suppressed. | | `canceled` | `$observed.email_readback.last_event` eq `"canceled"` | CONTRADICTED | The schedule of the message was canceled. The provider will not send it. | ## How long does the runtime observe? | Timing member | Value | | --- | --- | | Initial delay | 2000 ms | | Poll interval | 10000 ms | | Backoff | exponential factor 2, max 120000 ms | | Maximum attempts | 60 | | Timeout | 3600000 ms | | Stale read window | 30000 ms | | On timeout | UNVERIFIABLE (`evidence_unavailable_before_timeout`) | ## Where do these rules come from? - `resend.openapi#/paths/~1emails/post`: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05 - `resend.openapi#/paths/~1emails/post/responses/200`: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05 - `resend.openapi#/paths/~1emails~1{email_id}/get`: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05 - `resend.openapi#/components/schemas/Email/properties/created_at`: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05 - `resend.openapi#/components/schemas/Email/properties/id`: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05 - `resend.openapi#/paths/~1emails~1{email_id}/get/responses/200`: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05 ### Can resend.email.accepted return VERIFIED from the action response alone? No. The minimum evidence level is E2. The action response is E1. The completion conditions read `email_readback`. ### What happens after the timeout? The verdict is UNVERIFIABLE with the reason `evidence_unavailable_before_timeout`. The operation ends. ## Read next - [Read the Resend verification page](https://provely.sh/verify/resend) - [Read the resend.email.bounced contract](https://provely.sh/verify/resend/resend.email.bounced) - [Read the resend.email.delivered contract](https://provely.sh/verify/resend/resend.email.delivered) - [Read the resend.email.sent contract](https://provely.sh/verify/resend/resend.email.sent) - [Read what a completion contract contains](https://provely.sh/contracts) - [Read what a receipt proves](https://provely.sh/receipts) --- # What does resend.email.bounced prove? > Prove that the recipient mail server rejected the email. Version 1.0.0, certification Community. Canonical: https://provely.sh/verify/resend/resend.email.bounced Last reviewed: 2026-09-05 Skill version: 0.1.0 Certification: community **Prove that the recipient mail server rejected the email. The bounced level proves the bounced state on the email record and the email.bounced event. Use it when the intent is to confirm a rejection, for example before a suppression.** *Contract identity.* | Fact | Value | | --- | --- | | Contract id | `resend.email.bounced` | | Version | `1.0.0` | | Hash | `56703353a6dbfaf3` | | Completion level | `bounced` | | Certification | Community | | Skill | [Resend 0.1.0](/verify/resend) | | Valid for provider API versions | `1.5.1` | ## What is the intent? Confirm that the email bounced. ## What is the subject and the action? | Member | Value | | --- | --- | | Subject type | `resend.email` | | Subject identity | email_id = `$action.result.id` | | Canonical effect | `message.send` | | Provider operation | `POST /emails` | | Idempotency | idempotency_key through `Idempotency-Key`, retry is safe | ## How does the evidence correlate with this operation? | Strategy | Assurance | Keys | Required | | --- | --- | --- | --- | | `resource_id` | strong | email_id from `$action.result.id` | yes | | `idempotency_key` | strong | idempotency_key from `$operation.id` | no | | `fingerprint` | weak | to from `$input.to`; subject from `$input.subject` | no | ## Which evidence does the contract require? Minimum evidence level `E2`. An independent channel is required. Minimum channels: 1. | Channel | Level | Independence | Verifier | Description | | --- | --- | --- | --- | --- | | `email_readback` | E2 | provider readback | `http` | Read the email record. The http verifier returns the parsed Email object, so a condition path is $observed.email_readback.last_event. | | `sent_events_by_intent` | E3 | provider event | `webhook` | The email.sent events for the same recipient and subject since the operation started. A count above one shows a second send. The webhook verifier returns {events, count, latest, earliest, types, duplicates_dropped}, so a condition reads the count. | | `bounced_events` | E3 | provider event | `webhook` | The email.bounced events of this email. The resource id is the data.email_id of the payload. The webhook verifier returns {events, count, latest, earliest, types, duplicates_dropped}, so a condition reads the count. | ## Which conditions must all hold for VERIFIED? | Condition | Meaning | Path | Operator | Expected | Evidence | | --- | --- | --- | --- | --- | --- | | `record_created_in_window` | The provider created the email record after the operation started. | `$observed.email_readback.created_at` | `time_after` | `$operation.created_at` | `email_readback` | | `readback_shows_bounced` | The record shows the bounced state. | `$observed.email_readback.last_event` | `eq` | `bounced` | `email_readback` | | `bounce_event_present` | At least one email.bounced event of this email arrived. | `$observed.bounced_events.count` | `gte` | `1` | `bounced_events` | ## Which conditions give CONTRADICTED? | Condition | Class | Reason | Path | Operator | Expected | | --- | --- | --- | --- | --- | --- | | `wrong_recipient` | wrong subject | The message went to a different recipient. | `$observed.email_readback.to` | `ne` | `$input.to` | | `record_predates_operation` | pre existing state | The provider record is older than the operation. It proves nothing. | `$observed.email_readback.created_at` | `time_before` | `$operation.created_at` | | `more_than_one_recipient` | partial completion | The record lists more than one recipient. This contract proves the outcome for one recipient. Use one operation per recipient. | `$observed.email_readback.to` | `array_length` | `{"min":2}` | | `duplicate_email_present` | duplicate side effect | Resend sent more than one email for this recipient and subject since the operation started. Do not retry. | `$observed.sent_events_by_intent.count` | `gt` | `1` | ## Which observed states map to a verdict before completion? | Rule | Match | Verdict | Reason | | --- | --- | --- | --- | | `terminal_failure` | `$observed.email_readback.last_event` in `["failed","suppressed"]` | FAILED | The provider reports that the message failed, bounced, or was suppressed. | | `still_transitional` | `$observed.email_readback.last_event` in `["queued","scheduled","sent","delivery_delayed"]` | PENDING | The message is on the way. The runtime observes again later. | | `canceled` | `$observed.email_readback.last_event` eq `"canceled"` | CONTRADICTED | The schedule of the message was canceled. The provider will not send it. | | `delivered` | `$observed.email_readback.last_event` in `["delivered","opened","clicked","complained"]` | CONTRADICTED | The recipient mail server accepted the message. It did not bounce. | ## How long does the runtime observe? | Timing member | Value | | --- | --- | | Initial delay | 2000 ms | | Poll interval | 10000 ms | | Backoff | exponential factor 2, max 120000 ms | | Maximum attempts | 60 | | Timeout | 3600000 ms | | Stale read window | 30000 ms | | On timeout | UNVERIFIABLE (`evidence_unavailable_before_timeout`) | ## Where do these rules come from? - `resend.openapi#/paths/~1emails/post`: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05 - `resend.openapi#/components/schemas/Email/properties/last_event`: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05 - `resend.openapi#/webhooks/email.bounced`: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05 - `resend.openapi#/components/schemas/Email/properties/created_at`: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05 - `resend.docs.webhooks#webhooks/event-types/p4`: [resend.docs.webhooks](https://resend.com/docs/dashboard/webhooks/introduction), retrieved 2026-09-05 - `resend.openapi#/components/schemas/OutboundEmailEventData/properties/email_id`: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05 ### Can resend.email.bounced return VERIFIED from the action response alone? No. The minimum evidence level is E2. The action response is E1. The completion conditions read `email_readback` and `bounced_events`. ### What happens after the timeout? The verdict is UNVERIFIABLE with the reason `evidence_unavailable_before_timeout`. The operation ends. ## Read next - [Read the Resend verification page](https://provely.sh/verify/resend) - [Read the resend.email.accepted contract](https://provely.sh/verify/resend/resend.email.accepted) - [Read the resend.email.delivered contract](https://provely.sh/verify/resend/resend.email.delivered) - [Read the resend.email.sent contract](https://provely.sh/verify/resend/resend.email.sent) - [Read what a completion contract contains](https://provely.sh/contracts) - [Read what a receipt proves](https://provely.sh/receipts) --- # What does resend.email.delivered prove? > Prove that the recipient mail server accepted the email. Version 1.0.0, certification Community. Canonical: https://provely.sh/verify/resend/resend.email.delivered Last reviewed: 2026-09-05 Skill version: 0.1.0 Certification: community **Prove that the recipient mail server accepted the email. The delivered level proves the delivered state on the email record and the email.delivered event. It does not prove that a person read the message. This level needs the email.delivered webhook.** *Contract identity.* | Fact | Value | | --- | --- | | Contract id | `resend.email.delivered` | | Version | `1.0.0` | | Hash | `62f92acbd9f8b6fd` | | Completion level | `delivered` | | Certification | Community | | Skill | [Resend 0.1.0](/verify/resend) | | Valid for provider API versions | `1.5.1` | ## What is the intent? Deliver the email to the recipient mailbox. ## What is the subject and the action? | Member | Value | | --- | --- | | Subject type | `resend.email` | | Subject identity | email_id = `$action.result.id` | | Canonical effect | `message.send` | | Provider operation | `POST /emails` | | Idempotency | idempotency_key through `Idempotency-Key`, retry is safe | ## How does the evidence correlate with this operation? | Strategy | Assurance | Keys | Required | | --- | --- | --- | --- | | `resource_id` | strong | email_id from `$action.result.id` | yes | | `idempotency_key` | strong | idempotency_key from `$operation.id` | no | | `fingerprint` | weak | to from `$input.to`; subject from `$input.subject` | no | ## Which evidence does the contract require? Minimum evidence level `E2`. An independent channel is required. Minimum channels: 1. | Channel | Level | Independence | Verifier | Description | | --- | --- | --- | --- | --- | | `email_readback` | E2 | provider readback | `http` | Read the email record. The http verifier returns the parsed Email object, so a condition path is $observed.email_readback.last_event. | | `sent_events_by_intent` | E3 | provider event | `webhook` | The email.sent events for the same recipient and subject since the operation started. A count above one shows a second send. The webhook verifier returns {events, count, latest, earliest, types, duplicates_dropped}, so a condition reads the count. | | `delivered_events` | E3 | provider event | `webhook` | The email.delivered events of this email. The resource id is the data.email_id of the payload. The webhook verifier returns {events, count, latest, earliest, types, duplicates_dropped}, so a condition reads the count. | ## Which conditions must all hold for VERIFIED? | Condition | Meaning | Path | Operator | Expected | Evidence | | --- | --- | --- | --- | --- | --- | | `record_created_in_window` | The provider created the email record after the operation started. | `$observed.email_readback.created_at` | `time_after` | `$operation.created_at` | `email_readback` | | `readback_shows_delivered` | The record shows the delivered state or a later engagement state. | `$observed.email_readback.last_event` | `in` | `["delivered","opened","clicked"]` | `email_readback` | | `delivery_event_present` | At least one email.delivered event of this email arrived. | `$observed.delivered_events.count` | `gte` | `1` | `delivered_events` | ## Which conditions give CONTRADICTED? | Condition | Class | Reason | Path | Operator | Expected | | --- | --- | --- | --- | --- | --- | | `wrong_recipient` | wrong subject | The message went to a different recipient. | `$observed.email_readback.to` | `ne` | `$input.to` | | `record_predates_operation` | pre existing state | The provider record is older than the operation. It proves nothing. | `$observed.email_readback.created_at` | `time_before` | `$operation.created_at` | | `more_than_one_recipient` | partial completion | The record lists more than one recipient. This contract proves the outcome for one recipient. Use one operation per recipient. | `$observed.email_readback.to` | `array_length` | `{"min":2}` | | `duplicate_email_present` | duplicate side effect | Resend sent more than one email for this recipient and subject since the operation started. Do not retry. | `$observed.sent_events_by_intent.count` | `gt` | `1` | ## Which observed states map to a verdict before completion? | Rule | Match | Verdict | Reason | | --- | --- | --- | --- | | `terminal_failure` | `$observed.email_readback.last_event` in `["bounced","failed","suppressed"]` | FAILED | The provider reports that the message failed, bounced, or was suppressed. | | `still_transitional` | `$observed.email_readback.last_event` in `["queued","scheduled","sent","delivery_delayed"]` | PENDING | The message is on the way. The runtime observes again later. | | `canceled` | `$observed.email_readback.last_event` eq `"canceled"` | CONTRADICTED | The schedule of the message was canceled. The provider will not send it. | | `recipient_complained` | `$observed.email_readback.last_event` eq `"complained"` | UNVERIFIABLE | The recipient marked the message as spam. The record no longer states the delivery state. | ## How long does the runtime observe? | Timing member | Value | | --- | --- | | Initial delay | 2000 ms | | Poll interval | 10000 ms | | Backoff | exponential factor 2, max 120000 ms | | Maximum attempts | 60 | | Timeout | 3600000 ms | | Stale read window | 30000 ms | | On timeout | UNVERIFIABLE (`evidence_unavailable_before_timeout`) | ## Where do these rules come from? - `resend.openapi#/paths/~1emails/post`: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05 - `resend.openapi#/components/schemas/Email/properties/last_event`: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05 - `resend.openapi#/webhooks/email.delivered`: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05 - `resend.openapi#/components/schemas/Email/properties/created_at`: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05 - `resend.docs.webhooks#webhooks/event-types/p2`: [resend.docs.webhooks](https://resend.com/docs/dashboard/webhooks/introduction), retrieved 2026-09-05 - `resend.openapi#/components/schemas/OutboundEmailEventData/properties/email_id`: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05 ### Can resend.email.delivered return VERIFIED from the action response alone? No. The minimum evidence level is E2. The action response is E1. The completion conditions read `email_readback` and `delivered_events`. ### What happens after the timeout? The verdict is UNVERIFIABLE with the reason `evidence_unavailable_before_timeout`. The operation ends. ## Read next - [Read the Resend verification page](https://provely.sh/verify/resend) - [Read the resend.email.accepted contract](https://provely.sh/verify/resend/resend.email.accepted) - [Read the resend.email.bounced contract](https://provely.sh/verify/resend/resend.email.bounced) - [Read the resend.email.sent contract](https://provely.sh/verify/resend/resend.email.sent) - [Read what a completion contract contains](https://provely.sh/contracts) - [Read what a receipt proves](https://provely.sh/receipts) --- # What does resend.email.sent prove? > Prove that Resend handed the email to its sending infrastructure. Version 1.0.0, certification Community. Canonical: https://provely.sh/verify/resend/resend.email.sent Last reviewed: 2026-09-05 Skill version: 0.1.0 Certification: community **Prove that Resend handed the email to its sending infrastructure. The sent level proves the email.sent event of this email. It does not prove that the recipient mail server accepted the message. This level needs the email.sent webhook.** *Contract identity.* | Fact | Value | | --- | --- | | Contract id | `resend.email.sent` | | Version | `1.0.0` | | Hash | `b57df708a74febc9` | | Completion level | `sent` | | Certification | Community | | Skill | [Resend 0.1.0](/verify/resend) | | Valid for provider API versions | `1.5.1` | ## What is the intent? Send the email. ## What is the subject and the action? | Member | Value | | --- | --- | | Subject type | `resend.email` | | Subject identity | email_id = `$action.result.id` | | Canonical effect | `message.send` | | Provider operation | `POST /emails` | | Idempotency | idempotency_key through `Idempotency-Key`, retry is safe | ## How does the evidence correlate with this operation? | Strategy | Assurance | Keys | Required | | --- | --- | --- | --- | | `resource_id` | strong | email_id from `$action.result.id` | yes | | `idempotency_key` | strong | idempotency_key from `$operation.id` | no | | `fingerprint` | weak | to from `$input.to`; subject from `$input.subject` | no | ## Which evidence does the contract require? Minimum evidence level `E2`. An independent channel is required. Minimum channels: 1. | Channel | Level | Independence | Verifier | Description | | --- | --- | --- | --- | --- | | `email_readback` | E2 | provider readback | `http` | Read the email record. The http verifier returns the parsed Email object, so a condition path is $observed.email_readback.last_event. | | `sent_events_by_intent` | E3 | provider event | `webhook` | The email.sent events for the same recipient and subject since the operation started. A count above one shows a second send. The webhook verifier returns {events, count, latest, earliest, types, duplicates_dropped}, so a condition reads the count. | | `sent_events` | E3 | provider event | `webhook` | The email.sent events of this email. The resource id is the data.email_id of the payload. The webhook verifier returns {events, count, latest, earliest, types, duplicates_dropped}, so a condition reads the count. | ## Which conditions must all hold for VERIFIED? | Condition | Meaning | Path | Operator | Expected | Evidence | | --- | --- | --- | --- | --- | --- | | `record_created_in_window` | The provider created the email record after the operation started. | `$observed.email_readback.created_at` | `time_after` | `$operation.created_at` | `email_readback` | | `sent_event_present` | At least one email.sent event of this email arrived. | `$observed.sent_events.count` | `gte` | `1` | `sent_events` | ## Which conditions give CONTRADICTED? | Condition | Class | Reason | Path | Operator | Expected | | --- | --- | --- | --- | --- | --- | | `wrong_recipient` | wrong subject | The message went to a different recipient. | `$observed.email_readback.to` | `ne` | `$input.to` | | `record_predates_operation` | pre existing state | The provider record is older than the operation. It proves nothing. | `$observed.email_readback.created_at` | `time_before` | `$operation.created_at` | | `more_than_one_recipient` | partial completion | The record lists more than one recipient. This contract proves the outcome for one recipient. Use one operation per recipient. | `$observed.email_readback.to` | `array_length` | `{"min":2}` | | `duplicate_email_present` | duplicate side effect | Resend sent more than one email for this recipient and subject since the operation started. Do not retry. | `$observed.sent_events_by_intent.count` | `gt` | `1` | ## Which observed states map to a verdict before completion? | Rule | Match | Verdict | Reason | | --- | --- | --- | --- | | `terminal_failure` | `$observed.email_readback.last_event` in `["failed","suppressed"]` | FAILED | The provider reports that the message failed, bounced, or was suppressed. | | `still_transitional` | `$observed.email_readback.last_event` in `["queued","scheduled"]` | PENDING | The message is on the way. The runtime observes again later. | | `canceled` | `$observed.email_readback.last_event` eq `"canceled"` | CONTRADICTED | The schedule of the message was canceled. The provider will not send it. | ## How long does the runtime observe? | Timing member | Value | | --- | --- | | Initial delay | 2000 ms | | Poll interval | 10000 ms | | Backoff | exponential factor 2, max 120000 ms | | Maximum attempts | 60 | | Timeout | 3600000 ms | | Stale read window | 30000 ms | | On timeout | UNVERIFIABLE (`evidence_unavailable_before_timeout`) | ## Where do these rules come from? - `resend.openapi#/paths/~1emails/post`: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05 - `resend.openapi#/webhooks/email.sent`: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05 - `resend.docs.webhooks#webhooks/event-types/p1`: [resend.docs.webhooks](https://resend.com/docs/dashboard/webhooks/introduction), retrieved 2026-09-05 - `resend.openapi#/components/schemas/Email/properties/created_at`: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05 - `resend.openapi#/components/schemas/OutboundEmailEventData/properties/email_id`: [resend.openapi](https://raw.githubusercontent.com/resend/resend-openapi/main/resend.yaml), retrieved 2026-09-05 ### Can resend.email.sent return VERIFIED from the action response alone? No. The minimum evidence level is E2. The action response is E1. The completion conditions read `email_readback` and `sent_events`. ### What happens after the timeout? The verdict is UNVERIFIABLE with the reason `evidence_unavailable_before_timeout`. The operation ends. ## Read next - [Read the Resend verification page](https://provely.sh/verify/resend) - [Read the resend.email.accepted contract](https://provely.sh/verify/resend/resend.email.accepted) - [Read the resend.email.bounced contract](https://provely.sh/verify/resend/resend.email.bounced) - [Read the resend.email.delivered contract](https://provely.sh/verify/resend/resend.email.delivered) - [Read what a completion contract contains](https://provely.sh/contracts) - [Read what a receipt proves](https://provely.sh/receipts) --- # Does a Shopify Refund object mean the money went back? > Does a Shopify Refund object mean the money went back? The 2 completion levels, the Shopify Admin API lifecycle, and the evidence Provely reads. Canonical: https://provely.sh/verify/shopify Last reviewed: 2026-09-05 Skill version: 0.1.0 Certification: community **No. Shopify Admin API returns a successful refundCreate mutation when it accepts the request. The order_transaction then holds one of 6 states. Only `SUCCESS` is terminal success. Provely proves `created` and `financially_completed` 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: 28 of 30 cases passed, 0 critical false VERIFIED | | Provider API versions | `2025-07` | | Default provider API version | `2025-07` | | Compiled | 2026-09-05T12:00:00Z by compiler 0.1.0 | | Manifest hash | `db245b927503ea08` | | 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 record exists with the requested amount and a refunds/create webhook. It does not prove that money moved. | [shopify.refund.created](/verify/shopify/shopify.refund.created) | E2 + E3 | proven | | A Refund record does not prove money movement. This level proves the SUCCESS status on the refund transaction with the requested amount. | [shopify.refund.financially_completed](/verify/shopify/shopify.refund.financially_completed) | E2 | proven | | An outcome outside Shopify Admin API, such as a bank credit or a person who read a message | not proven | no E5 channel | not proven | | The meaning of the `UNKNOWN` state of `shopify.order_transaction` | REQUIRES_REVIEW | unknown semantics | not proven | | The agent report that the action worked | never counts | E0 | not proven | ## Which completion levels does the Shopify Admin 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 | | --- | --- | --- | --- | --- | | `created` | [shopify.refund.created](/verify/shopify/shopify.refund.created) v1.0.0 | The created level proves that the Refund record exists with the requested amount and a refunds/create webhook. It does not prove that money moved. | E2 + E3 | Community | | `financially_completed` | [shopify.refund.financially_completed](/verify/shopify/shopify.refund.financially_completed) v1.0.0 | A Refund record does not prove money movement. This level proves the SUCCESS status on the refund transaction with the requested amount. | E2 | Community | ## What is the Shopify Admin API lifecycle? ### Which states can a `shopify.order_transaction` be in? | State | Class | Verdict | Meaning | Source | | --- | --- | --- | --- | --- | | `AWAITING_RESPONSE` | transitional | PENDING | The gateway has not answered yet. | [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07) | | `PENDING` | transitional | PENDING | The transaction is pending at the gateway. | [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07) | | `SUCCESS` | terminal success | VERIFIED | The gateway processed the transaction. The money moved. | [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07) | | `FAILURE` | terminal failure | FAILED | The transaction failed at the gateway. | [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07) | | `ERROR` | terminal failure | FAILED | An error occurred while the gateway processed the transaction. | [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07) | | `UNKNOWN` | unknown | UNVERIFIABLE | The sources state only that the status is unknown. | [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07) | In `shopify.order_transaction` under provider API version `2025-07`, `SUCCESS` is the only state that means terminal success. Every other state gives PENDING, FAILED, or UNVERIFIABLE. Source: https://shopify.dev/docs/api/admin-graphql/2025-07 (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.refundCreate.refund.id` | yes | none | | `fingerprint` | weak | order from `$input.order_id`; 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 Shopify Admin API is E1 and never terminal success. | Channel | Level | Independence | Verifier | Deterministic | Typical latency | | --- | --- | --- | --- | --- | --- | | `order_readback` | E2 | provider readback | `http` | yes | 400 ms | | `refund_action_response` | E1 | same response | `action_result` | yes | not stated | | `refund_events` | E3 | provider event | `webhook` | no | 5000 ms | | `order_refund_events` | E3 | provider event | `webhook` | no | 5000 ms | | `refund_readback` | E2 | provider readback | `http` | yes | 400 ms | | `transaction_readback` | E2 | provider readback | `http` | yes | 400 ms | ## Which ways can a Shopify Admin API action look done and not be? | Contract | Case | Rule | Verdict | | --- | --- | --- | --- | | [shopify.refund.created](/verify/shopify/shopify.refund.created) | wrong subject | The refund belongs to another order. | CONTRADICTED | | [shopify.refund.created](/verify/shopify/shopify.refund.created) | wrong amount | The provider recorded a different refund amount. | CONTRADICTED | | [shopify.refund.created](/verify/shopify/shopify.refund.created) | pre existing state | The refund is older than the operation. It proves nothing. | CONTRADICTED | | [shopify.refund.created](/verify/shopify/shopify.refund.created) | duplicate side effect | Shopify created more than one refund on the order since the operation started. Do not retry. | CONTRADICTED | | [shopify.refund.created](/verify/shopify/shopify.refund.created) | observed state | The refund record exists, but its transaction failed at the gateway. The refund will not complete. | FAILED | | [shopify.refund.financially_completed](/verify/shopify/shopify.refund.financially_completed) | wrong subject | The refund belongs to another order. | CONTRADICTED | | [shopify.refund.financially_completed](/verify/shopify/shopify.refund.financially_completed) | wrong amount | The provider recorded a different refund amount. | CONTRADICTED | | [shopify.refund.financially_completed](/verify/shopify/shopify.refund.financially_completed) | pre existing state | The refund is older than the operation. It proves nothing. | CONTRADICTED | | [shopify.refund.financially_completed](/verify/shopify/shopify.refund.financially_completed) | partial completion | The refund holds more than one transaction. This contract proves one refund transaction. Use one refund per transaction. | CONTRADICTED | | [shopify.refund.financially_completed](/verify/shopify/shopify.refund.financially_completed) | duplicate side effect | Shopify created more than one refund on the order since the operation started. Do not retry. | CONTRADICTED | | [shopify.refund.financially_completed](/verify/shopify/shopify.refund.financially_completed) | observed state | The gateway rejected the refund transaction. | FAILED | | [shopify.refund.financially_completed](/verify/shopify/shopify.refund.financially_completed) | observed state | The gateway has not processed the refund yet. The runtime observes again later. | PENDING | | [shopify.refund.financially_completed](/verify/shopify/shopify.refund.financially_completed) | observed state | The gateway reports an unknown status. The runtime cannot prove the outcome. | UNVERIFIABLE | ## What did the last conformance run show? *The six confidence dimensions of the signed manifest.* | Dimension | Score | Maximum | | --- | --- | --- | | Documentation | 12 | 20 | | Schema alignment | 0 | 15 | | Lifecycle certainty | 16.67 | 20 | | Evidence strength | 12 | 20 | | Causal correlation | 15 | 15 | | Sandbox conformance | 9.33 | 10 | | Raw score | 65 | 100 | | Score after the caps | 49 | 100 | The raw score is 65. 3 hard caps apply, so the score is 49 and the level is Community. *The hard caps the compiler applied.* | Gate | Cap | Reason | | --- | --- | --- | | `unknown_terminal_semantics` | 49 | A lifecycle state has unknown semantics. The compiler cannot prove the end state. | | `uncertainty_caps` | 49 | 4 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 28 of 30 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 | | 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 `dc03f8d9f0df26a7`. The harness signs the run, so a reader can check that these numbers come from that run. ## What remains uncertain? **Open questions remain. A lifecycle state has unknown semantics. The compiler cannot prove the end state. 4 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 | | --- | --- | --- | --- | | [shopify.docs.refunds](https://shopify.dev/docs/api/admin-graphql/2025-07/mutations/refundCreate) | docs | 2026-09-05 | authored | | [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07) | graphql | 2026-09-05 | authored | ## How do I verify a Shopify Admin API action? ### Verify a Shopify Admin API action with Provely 1. **Begin the operation.** Call `begin` with the contract `shopify.refund.financially_completed` and the input. Keep the operation id. 2. **Make the Shopify Admin API call you make today.** Send the request with the correlation metadata that `begin` returned. 3. **Submit the acknowledgement.** Call `action_result` with the Shopify Admin API response. This is evidence level E1. It is not completion. 4. **Verify.** Call `verify`. The runtime reads `order_readback`, `refund_action_response`, `refund_events`, `order_refund_events`, `refund_readback` and `transaction_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 `created` level prove the `financially_completed` level? No. The created level proves that the Refund record exists with the requested amount and a refunds/create webhook. It does not prove that money moved. A Refund record does not prove money movement. This level proves the SUCCESS status on the refund transaction with the requested amount. Use `shopify.refund.financially_completed` to prove `financially_completed`. ### What does the agent say while Shopify Admin API reports `AWAITING_RESPONSE` and `PENDING`? It says: "The action is accepted but not yet verified. Operation: ." The verdict is PENDING. The runtime observes again on the contract timing policy. ### Which Shopify Admin API API versions does the skill support? `2025-07`. An operation on another version returns UNVERIFIABLE with the reason `version_unsupported`. The runtime never guesses. ### Does Provely need write access to Shopify Admin API? No. The agent keeps its write key. The verifier reads with a separate read-only credential where Shopify Admin API permits it, and it never shares that credential with the agent. ## Read next - [Read the shopify.refund.created contract](https://provely.sh/verify/shopify/shopify.refund.created) - [Read the shopify.refund.financially_completed contract](https://provely.sh/verify/shopify/shopify.refund.financially_completed) - [Read the Resend verification page](https://provely.sh/verify/resend) - [Read the Stripe verification page](https://provely.sh/verify/stripe) - [See every verified service](https://provely.sh/verify) - [Verify Shopify Admin API actions from Claude Code](https://provely.sh/agents/claude-code) - [Verify Shopify Admin 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 the completion level definition](https://provely.sh/glossary/completion-level) --- # What does shopify.refund.created prove? > Prove that Shopify holds a Refund record for the order. Version 1.0.0, certification Community. Canonical: https://provely.sh/verify/shopify/shopify.refund.created Last reviewed: 2026-09-05 Skill version: 0.1.0 Certification: community **Prove that Shopify holds a Refund record for the order. The created level proves that the Refund record exists with the requested amount and a refunds/create webhook. It does not prove that money moved.** *Contract identity.* | Fact | Value | | --- | --- | | Contract id | `shopify.refund.created` | | Version | `1.0.0` | | Hash | `3b0c1707cf0adcf1` | | Completion level | `created` | | Certification | Community | | Skill | [Shopify Admin API 0.1.0](/verify/shopify) | | Valid for provider API versions | `2025-07` | ## What is the intent? Create the refund record on the order. ## What is the subject and the action? | Member | Value | | --- | --- | | Subject type | `shopify.refund` | | Subject identity | refund_id = `$action.result.refundCreate.refund.id` | | Canonical effect | `money.refund` | | Provider operation | `mutation refundCreate` | | Idempotency | not stated | ## How does the evidence correlate with this operation? | Strategy | Assurance | Keys | Required | | --- | --- | --- | --- | | `resource_id` | strong | refund_id from `$action.result.refundCreate.refund.id` | yes | | `fingerprint` | weak | order 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 | | --- | --- | --- | --- | --- | | `refund_readback` | E2 | provider readback | `http` | Read the Refund record with its order and its transactions. It proves the record, not the money movement. The http verifier returns the parsed GraphQL response body, so a condition path starts with $observed..data. The connection of the shop gives the base URL. | | `refund_events` | E3 | provider event | `webhook` | The refunds/create webhooks of this refund. The type name is the WebhookSubscriptionTopic value. The resource id is the global id of the refund. The webhook verifier returns {events, count, latest, earliest, types, duplicates_dropped}, so a condition reads the count. | | `order_refund_events` | E3 | provider event | `webhook` | The refunds/create webhooks for the order since the operation started. A count above one shows a second refund. The webhook verifier returns {events, count, latest, earliest, types, duplicates_dropped}. | ## Which conditions must all hold for VERIFIED? | Condition | Meaning | Path | Operator | Expected | Evidence | | --- | --- | --- | --- | --- | --- | | `refund_created_in_window` | The shop created the Refund record after the operation started. | `$observed.refund_readback.data.refund.createdAt` | `time_after` | `$operation.created_at` | `refund_readback` | | `refund_present` | The shop holds the refund with the returned global id. | `$observed.refund_readback.data.refund.id` | `eq` | `$action.result.refundCreate.refund.id` | `refund_readback` | | `refund_webhook_present` | At least one refunds/create webhook of this refund arrived. | `$observed.refund_events.count` | `gte` | `1` | `refund_events` | ## Which conditions give CONTRADICTED? | Condition | Class | Reason | Path | Operator | Expected | | --- | --- | --- | --- | --- | --- | | `refund_on_wrong_order` | wrong subject | The refund belongs to another order. | `$observed.refund_readback.data.refund.order.id` | `ne` | `$input.order_id` | | `refund_amount_mismatch` | wrong amount | The provider recorded a different refund amount. | `$observed.refund_readback.data.refund.totalRefundedSet.shopMoney.amount` | `ne` | `$input.amount` | | `refund_predates_operation` | pre existing state | The refund is older than the operation. It proves nothing. | `$observed.refund_readback.data.refund.createdAt` | `time_before` | `$operation.created_at` | | `duplicate_refund_present` | duplicate side effect | Shopify created more than one refund on the order since the operation started. Do not retry. | `$observed.order_refund_events.count` | `gt` | `1` | ## Which observed states map to a verdict before completion? | Rule | Match | Verdict | Reason | | --- | --- | --- | --- | | `transaction_failed` | `$observed.refund_readback.data.refund.transactions[0].status` in `["FAILURE","ERROR"]` | FAILED | The refund record exists, but its transaction failed at the gateway. The refund will not complete. | ## How long does the runtime observe? | Timing member | Value | | --- | --- | | Initial delay | 1000 ms | | Poll interval | 5000 ms | | Backoff | exponential factor 2, max 60000 ms | | Maximum attempts | 40 | | Timeout | 604800000 ms | | Stale read window | 20000 ms | | On timeout | UNVERIFIABLE (`evidence_unavailable_before_timeout`), escalated to a person | ## Where do these rules come from? - `shopify.graphql#/mutations/refundCreate`: [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07), retrieved 2026-09-05 - `shopify.docs.refunds#refunds-in-the-admin-graphql-api/p1`: [shopify.docs.refunds](https://shopify.dev/docs/api/admin-graphql/2025-07/mutations/refundCreate), retrieved 2026-09-05 - `shopify.docs.refunds#refunds-in-the-admin-graphql-api/refund-objects-and-money-movement/p1`: [shopify.docs.refunds](https://shopify.dev/docs/api/admin-graphql/2025-07/mutations/refundCreate), retrieved 2026-09-05 - `shopify.docs.refunds#refunds-in-the-admin-graphql-api/webhooks/p1`: [shopify.docs.refunds](https://shopify.dev/docs/api/admin-graphql/2025-07/mutations/refundCreate), retrieved 2026-09-05 - `shopify.graphql#/types/Refund/fields/createdAt`: [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07), retrieved 2026-09-05 - `shopify.graphql#/types/Refund/fields/id`: [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07), retrieved 2026-09-05 - `shopify.graphql#/queries/refund`: [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07), retrieved 2026-09-05 - `shopify.graphql#/enums/WebhookSubscriptionTopic/values/REFUNDS_CREATE`: [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07), retrieved 2026-09-05 ### Can shopify.refund.created 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 `refund_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 Shopify Admin API verification page](https://provely.sh/verify/shopify) - [Read the shopify.refund.financially_completed contract](https://provely.sh/verify/shopify/shopify.refund.financially_completed) - [Read what a completion contract contains](https://provely.sh/contracts) - [Read what a receipt proves](https://provely.sh/receipts) --- # What does shopify.refund.financially_completed prove? > Prove that the refund transaction succeeded at the gateway. Version 1.0.0, certification Community. Canonical: https://provely.sh/verify/shopify/shopify.refund.financially_completed Last reviewed: 2026-09-05 Skill version: 0.1.0 Certification: community **Prove that the refund transaction succeeded at the gateway. A Refund record does not prove money movement. This level proves the SUCCESS status on the refund transaction with the requested amount.** *Contract identity.* | Fact | Value | | --- | --- | | Contract id | `shopify.refund.financially_completed` | | Version | `1.0.0` | | Hash | `183f55df6169b4e5` | | Completion level | `financially_completed` | | Certification | Community | | Skill | [Shopify Admin API 0.1.0](/verify/shopify) | | Valid for provider API versions | `2025-07` | ## What is the intent? Return the amount to the customer. ## What is the subject and the action? | Member | Value | | --- | --- | | Subject type | `shopify.refund` | | Subject identity | refund_id = `$action.result.refundCreate.refund.id` | | Canonical effect | `money.refund` | | Provider operation | `mutation refundCreate` | | Idempotency | not stated | ## How does the evidence correlate with this operation? | Strategy | Assurance | Keys | Required | | --- | --- | --- | --- | | `resource_id` | strong | refund_id from `$action.result.refundCreate.refund.id` | yes | | `fingerprint` | weak | order 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 | | --- | --- | --- | --- | --- | | `refund_readback` | E2 | provider readback | `http` | Read the Refund record with its order and its transactions. It proves the record, not the money movement. The http verifier returns the parsed GraphQL response body, so a condition path starts with $observed..data. The connection of the shop gives the base URL. | | `transaction_readback` | E2 | provider readback | `http` | Read the refund transactions through the Refund record. The status of a transaction carries the money movement state. The http verifier returns the parsed GraphQL response body, so a condition path starts with $observed..data. The connection of the shop gives the base URL. | | `order_refund_events` | E3 | provider event | `webhook` | The refunds/create webhooks for the order since the operation started. A count above one shows a second refund. The webhook verifier returns {events, count, latest, earliest, types, duplicates_dropped}. | ## Which conditions must all hold for VERIFIED? | Condition | Meaning | Path | Operator | Expected | Evidence | | --- | --- | --- | --- | --- | --- | | `refund_created_in_window` | The shop created the Refund record after the operation started. | `$observed.transaction_readback.data.refund.createdAt` | `time_after` | `$operation.created_at` | `transaction_readback` | | `transaction_status_success` | The refund transaction shows the SUCCESS status. | `$observed.transaction_readback.data.refund.transactions[0].status` | `eq` | `SUCCESS` | `transaction_readback` | | `transaction_kind_refund` | The transaction is a refund transaction. | `$observed.transaction_readback.data.refund.transactions[0].kind` | `eq` | `REFUND` | `transaction_readback` | | `transaction_amount_matches` | The refund transaction carries the requested amount. | `$observed.transaction_readback.data.refund.transactions[0].amountSet.shopMoney.amount` | `eq` | `$input.amount` | `transaction_readback` | ## Which conditions give CONTRADICTED? | Condition | Class | Reason | Path | Operator | Expected | | --- | --- | --- | --- | --- | --- | | `refund_on_wrong_order` | wrong subject | The refund belongs to another order. | `$observed.refund_readback.data.refund.order.id` | `ne` | `$input.order_id` | | `refund_amount_mismatch` | wrong amount | The provider recorded a different refund amount. | `$observed.refund_readback.data.refund.totalRefundedSet.shopMoney.amount` | `ne` | `$input.amount` | | `refund_predates_operation` | pre existing state | The refund is older than the operation. It proves nothing. | `$observed.refund_readback.data.refund.createdAt` | `time_before` | `$operation.created_at` | | `more_than_one_transaction` | partial completion | The refund holds more than one transaction. This contract proves one refund transaction. Use one refund per transaction. | `$observed.transaction_readback.data.refund.transactions` | `array_length` | `{"min":2}` | | `duplicate_refund_present` | duplicate side effect | Shopify created more than one refund on the order since the operation started. Do not retry. | `$observed.order_refund_events.count` | `gt` | `1` | ## Which observed states map to a verdict before completion? | Rule | Match | Verdict | Reason | | --- | --- | --- | --- | | `terminal_failure` | `$observed.transaction_readback.data.refund.transactions[0].status` in `["FAILURE","ERROR"]` | FAILED | The gateway rejected the refund transaction. | | `still_transitional` | `$observed.transaction_readback.data.refund.transactions[0].status` in `["PENDING","AWAITING_RESPONSE"]` | PENDING | The gateway has not processed the refund yet. The runtime observes again later. | | `status_unknown` | `$observed.transaction_readback.data.refund.transactions[0].status` eq `"UNKNOWN"` | UNVERIFIABLE | The gateway reports an unknown status. The runtime cannot prove the outcome. | ## How long does the runtime observe? | Timing member | Value | | --- | --- | | Initial delay | 1000 ms | | Poll interval | 5000 ms | | Backoff | exponential factor 2, max 60000 ms | | Maximum attempts | 40 | | Timeout | 604800000 ms | | Stale read window | 20000 ms | | On timeout | UNVERIFIABLE (`evidence_unavailable_before_timeout`), escalated to a person | ## Where do these rules come from? - `shopify.graphql#/mutations/refundCreate`: [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07), retrieved 2026-09-05 - `shopify.docs.refunds#refunds-in-the-admin-graphql-api/refund-objects-and-money-movement/p1`: [shopify.docs.refunds](https://shopify.dev/docs/api/admin-graphql/2025-07/mutations/refundCreate), retrieved 2026-09-05 - `shopify.docs.refunds#refunds-in-the-admin-graphql-api/refund-objects-and-money-movement/p2`: [shopify.docs.refunds](https://shopify.dev/docs/api/admin-graphql/2025-07/mutations/refundCreate), retrieved 2026-09-05 - `shopify.docs.refunds#refunds-in-the-admin-graphql-api/refund-objects-and-money-movement/p4`: [shopify.docs.refunds](https://shopify.dev/docs/api/admin-graphql/2025-07/mutations/refundCreate), retrieved 2026-09-05 - `shopify.graphql#/types/Refund/fields/createdAt`: [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07), retrieved 2026-09-05 - `shopify.graphql#/enums/OrderTransactionStatus/values/SUCCESS`: [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07), retrieved 2026-09-05 - `shopify.graphql#/types/OrderTransaction/fields/status`: [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07), retrieved 2026-09-05 - `shopify.graphql#/enums/OrderTransactionKind/values/REFUND`: [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07), retrieved 2026-09-05 - `shopify.graphql#/types/OrderTransaction/fields/kind`: [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07), retrieved 2026-09-05 - `shopify.graphql#/types/OrderTransaction/fields/amountSet`: [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07), retrieved 2026-09-05 - `shopify.graphql#/inputs/OrderTransactionInput/fields/amount`: [shopify.graphql](https://shopify.dev/docs/api/admin-graphql/2025-07), retrieved 2026-09-05 ### Can shopify.refund.financially_completed return VERIFIED from the action response alone? No. The minimum evidence level is E2. The action response is E1. The completion conditions read `transaction_readback`. ### 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 Shopify Admin API verification page](https://provely.sh/verify/shopify) - [Read the shopify.refund.created contract](https://provely.sh/verify/shopify/shopify.refund.created) - [Read what a completion contract contains](https://provely.sh/contracts) - [Read what a receipt proves](https://provely.sh/receipts) --- # 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: ." 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) --- # What does stripe.refund.created prove? > Prove that Stripe holds a refund for the charge. Version 1.0.0, certification Community. Every condition and timing rule of the signed Stripe skill. Canonical: https://provely.sh/verify/stripe/stripe.refund.created Last reviewed: 2026-09-05 Skill version: 0.1.0 Certification: community **Prove that Stripe holds a refund for the charge. 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.** *Contract identity.* | Fact | Value | | --- | --- | | Contract id | `stripe.refund.created` | | Version | `1.0.0` | | Hash | `0540b6160ff287df` | | Completion level | `created` | | Certification | Community | | Skill | [Stripe 0.1.0](/verify/stripe) | | Valid for provider API versions | `2026-08-26` | ## What is the intent? Request a refund of the charge. ## What is the subject and the action? | Member | Value | | --- | --- | | Subject type | `stripe.refund` | | Subject identity | refund_id = `$action.result.id` | | Canonical effect | `money.refund` | | Provider operation | `POST /v1/refunds` | | Idempotency | idempotency_key through `Idempotency-Key`, retry is safe | ## How does the evidence correlate with this operation? | Strategy | Assurance | Keys | Required | | --- | --- | --- | --- | | `resource_id` | strong | refund_id from `$action.result.id` | yes | | `idempotency_key` | strong | idempotency_key from `$operation.id` | no | | `fingerprint` | weak | charge from `$input.charge`; 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 provider. The http verifier returns the parsed Refund object, so a condition path is $observed.refund_readback.status. | | `refund_created_events` | E3 | provider event | `webhook` | The refund.created events for the charge since the operation started. The webhook verifier returns {events, count, latest, earliest, types, duplicates_dropped}. A count above one shows a second refund. | ## Which conditions must all hold for VERIFIED? | Condition | Meaning | Path | Operator | Expected | Evidence | | --- | --- | --- | --- | --- | --- | | `refund_present` | The provider holds the refund with the returned id. | `$observed.refund_readback.id` | `eq` | `$action.result.id` | `refund_readback` | | `refund_state_known` | The refund shows a live state of the refund lifecycle. | `$observed.refund_readback.status` | `in` | `["pending","requires_action","succeeded"]` | `refund_readback` | | `refund_created_in_window` | The provider created the refund after the operation started. Stripe writes created in seconds since the epoch. | `$observed.refund_readback.created` | `time_after` | `$operation.created_at` | `refund_readback` | ## Which conditions give CONTRADICTED? | Condition | Class | Reason | Path | Operator | Expected | | --- | --- | --- | --- | --- | --- | | `refund_on_wrong_charge` | wrong subject | The refund belongs to a different charge. | `$observed.refund_readback.charge` | `ne` | `$input.charge` | | `refund_amount_mismatch` | wrong amount | The provider refunded a different amount. | `$observed.refund_readback.amount` | `ne` | `$input.amount` | | `refund_predates_operation` | pre existing state | The refund is older than the operation. It proves nothing. | `$observed.refund_readback.created` | `time_before` | `$operation.created_at` | | `duplicate_refund_present` | duplicate side effect | Stripe created more than one refund for the charge since the operation started. Do not retry. | `$observed.refund_created_events.count` | `gt` | `1` | ## Which observed states map to a verdict before completion? | Rule | Match | Verdict | Reason | | --- | --- | --- | --- | | `terminal_failure` | `$observed.refund_readback.status` in `["failed"]` | FAILED | The provider reports a failed refund. | | `canceled` | `$observed.refund_readback.status` eq `"canceled"` | CONTRADICTED | The refund was canceled. No funds will move. | ## How long does the runtime observe? | Timing member | Value | | --- | --- | | Initial delay | 1000 ms | | Poll interval | 5000 ms | | Backoff | exponential factor 2, max 60000 ms | | Maximum attempts | 40 | | Timeout | 604800000 ms | | Stale read window | 20000 ms | | On timeout | UNVERIFIABLE (`evidence_unavailable_before_timeout`), escalated to a person | ## Where do these rules come from? - `stripe.openapi#/paths/~1v1~1refunds/post`: [stripe.openapi](https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json), retrieved 2026-09-05 - `stripe.openapi#/components/schemas/refund/properties/status`: [stripe.openapi](https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json), retrieved 2026-09-05 - `stripe.docs.refunds#refunds/p1`: [stripe.docs.refunds](https://docs.stripe.com/refunds), retrieved 2026-09-05 - `stripe.openapi#/components/schemas/refund/properties/id`: [stripe.openapi](https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json), retrieved 2026-09-05 - `stripe.openapi#/paths/~1v1~1refunds~1{refund}/get/responses/200`: [stripe.openapi](https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json), retrieved 2026-09-05 - `stripe.docs.refunds#refunds/refund-status/p1`: [stripe.docs.refunds](https://docs.stripe.com/refunds), retrieved 2026-09-05 - `stripe.docs.refunds#refunds/refund-status/p2`: [stripe.docs.refunds](https://docs.stripe.com/refunds), retrieved 2026-09-05 - `stripe.docs.refunds#refunds/refund-status/p3`: [stripe.docs.refunds](https://docs.stripe.com/refunds), retrieved 2026-09-05 - `stripe.openapi#/components/schemas/refund/properties/created`: [stripe.openapi](https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json), retrieved 2026-09-05 ### Can stripe.refund.created 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`. ### 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 Stripe verification page](https://provely.sh/verify/stripe) - [Read the stripe.refund.succeeded contract](https://provely.sh/verify/stripe/stripe.refund.succeeded) - [Read what a completion contract contains](https://provely.sh/contracts) - [Read what a receipt proves](https://provely.sh/receipts) --- # What does stripe.refund.succeeded prove? > Prove that the refund reached the succeeded state. Version 1.0.0, certification Community. Every condition and timing rule of the signed Stripe skill. Canonical: https://provely.sh/verify/stripe/stripe.refund.succeeded Last reviewed: 2026-09-05 Skill version: 0.1.0 Certification: community **Prove that the refund reached the succeeded state. 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.** *Contract identity.* | Fact | Value | | --- | --- | | Contract id | `stripe.refund.succeeded` | | Version | `1.0.0` | | Hash | `83491ff981adfd05` | | Completion level | `succeeded` | | Certification | Community | | Skill | [Stripe 0.1.0](/verify/stripe) | | Valid for provider API versions | `2026-08-26` | ## What is the intent? Refund the charge to the customer. ## What is the subject and the action? | Member | Value | | --- | --- | | Subject type | `stripe.refund` | | Subject identity | refund_id = `$action.result.id` | | Canonical effect | `money.refund` | | Provider operation | `POST /v1/refunds` | | Idempotency | idempotency_key through `Idempotency-Key`, retry is safe | ## How does the evidence correlate with this operation? | Strategy | Assurance | Keys | Required | | --- | --- | --- | --- | | `resource_id` | strong | refund_id from `$action.result.id` | yes | | `idempotency_key` | strong | idempotency_key from `$operation.id` | no | | `fingerprint` | weak | charge from `$input.charge`; 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 provider. The http verifier returns the parsed Refund object, so a condition path is $observed.refund_readback.status. | | `refund_succeeded_events` | E3 | provider event | `webhook` | The refund.updated events of this refund that carry the succeeded state. The webhook verifier returns {events, count, latest, earliest, types, duplicates_dropped}. A condition reads $observed.refund_succeeded_events.count. | | `refund_created_events` | E3 | provider event | `webhook` | The refund.created events for the charge since the operation started. The webhook verifier returns {events, count, latest, earliest, types, duplicates_dropped}. A count above one shows a second refund. | ## Which conditions must all hold for VERIFIED? | Condition | Meaning | Path | Operator | Expected | Evidence | | --- | --- | --- | --- | --- | --- | | `refund_status_succeeded` | The refund resource shows the succeeded state. | `$observed.refund_readback.status` | `eq` | `succeeded` | `refund_readback` | | `refund_amount_matches` | The refund amount equals the requested amount. | `$observed.refund_readback.amount` | `eq` | `$input.amount` | `refund_readback` | | `refund_created_in_window` | The provider created the refund after the operation started. Stripe writes created in seconds since the epoch. | `$observed.refund_readback.created` | `time_after` | `$operation.created_at` | `refund_readback` | | `refund_event_succeeded` | At least one refund.updated event of this refund carries the succeeded state. | `$observed.refund_succeeded_events.count` | `gte` | `1` | `refund_succeeded_events` | ## Which conditions give CONTRADICTED? | Condition | Class | Reason | Path | Operator | Expected | | --- | --- | --- | --- | --- | --- | | `refund_on_wrong_charge` | wrong subject | The refund belongs to a different charge. | `$observed.refund_readback.charge` | `ne` | `$input.charge` | | `refund_amount_mismatch` | wrong amount | The provider refunded a different amount. | `$observed.refund_readback.amount` | `ne` | `$input.amount` | | `refund_predates_operation` | pre existing state | The refund is older than the operation. It proves nothing. | `$observed.refund_readback.created` | `time_before` | `$operation.created_at` | | `duplicate_refund_present` | duplicate side effect | Stripe created more than one refund for the charge since the operation started. Do not retry. | `$observed.refund_created_events.count` | `gt` | `1` | ## Which observed states map to a verdict before completion? | Rule | Match | Verdict | Reason | | --- | --- | --- | --- | | `terminal_failure` | `$observed.refund_readback.status` in `["failed"]` | FAILED | The provider reports a failed refund. | | `still_transitional` | `$observed.refund_readback.status` in `["pending","requires_action"]` | PENDING | The refund is still moving. The runtime observes again later. | | `canceled` | `$observed.refund_readback.status` eq `"canceled"` | CONTRADICTED | The refund was canceled. No funds will move. | ## How long does the runtime observe? | Timing member | Value | | --- | --- | | Initial delay | 1000 ms | | Poll interval | 5000 ms | | Backoff | exponential factor 2, max 60000 ms | | Maximum attempts | 40 | | Timeout | 604800000 ms | | Stale read window | 20000 ms | | On timeout | UNVERIFIABLE (`evidence_unavailable_before_timeout`), escalated to a person | ## Where do these rules come from? - `stripe.openapi#/paths/~1v1~1refunds/post`: [stripe.openapi](https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json), retrieved 2026-09-05 - `stripe.openapi#/components/schemas/refund/properties/status`: [stripe.openapi](https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json), retrieved 2026-09-05 - `stripe.docs.refunds#refunds/p1`: [stripe.docs.refunds](https://docs.stripe.com/refunds), retrieved 2026-09-05 - `stripe.docs.refunds#refunds/refund-status/p3`: [stripe.docs.refunds](https://docs.stripe.com/refunds), retrieved 2026-09-05 - `stripe.openapi#/components/schemas/refund/properties/amount`: [stripe.openapi](https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json), retrieved 2026-09-05 - `stripe.openapi#/components/schemas/refund/properties/created`: [stripe.openapi](https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json), retrieved 2026-09-05 - `stripe.events#/events/refund.updated`: [stripe.events](https://docs.stripe.com/api/events/types), retrieved 2026-09-05 - `stripe.openapi#/components/schemas/notification_event_data/properties/object`: [stripe.openapi](https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json), retrieved 2026-09-05 - `stripe.docs.refunds#refunds/events/p2`: [stripe.docs.refunds](https://docs.stripe.com/refunds), retrieved 2026-09-05 ### Can stripe.refund.succeeded 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 `refund_succeeded_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 Stripe verification page](https://provely.sh/verify/stripe) - [Read the stripe.refund.created contract](https://provely.sh/verify/stripe/stripe.refund.created) - [Read what a completion contract contains](https://provely.sh/contracts) - [Read what a receipt proves](https://provely.sh/receipts) --- # What is a completion contract? > A completion contract is a versioned document that states which evidence proves one outcome. Read the schema and a worked Stripe refund example. Canonical: https://provely.sh/contracts Last reviewed: 2026-09-05 **A completion contract is a machine-readable definition of "done" for one operation. It names the intent, the subject, the action, the correlation keys, the positive and negative postconditions, the timing policy, and the result on timeout.** Contracts are immutable, versioned, and hashable. Every [receipt](/receipts) records the contract id, version, and hash. A contract is data. Code interprets it and holds no provider rule. ## Where does a contract come from? Provely compiles it from the task. You pass the agent prompt, the context and the tools. The compiler returns the steps, the evidence, the correlation keys and the negative postconditions. You confirm the result before it runs. A part of the task that no contract can check is marked REQUIRES_REVIEW, and it is never dropped in silence. Read [intent compilation](/docs/intent-compilation). ## What does a contract contain? | Member | Purpose | Example | | --- | --- | --- | | `intent` | What the user asked for, and the input schema. | Refund the charge to the customer. | | `subject` | The real-world thing the contract talks about. | `stripe.refund` identified by `$action.result.id`. | | `action` | The effect class and the [idempotency](/glossary/idempotency) rule. | `money.refund` with `Idempotency-Key: $operation.id`. | | `correlation` | How evidence ties to this exact operation. | Match the refund id from the action response. | | `evidence_policy` | The channels and the minimum [evidence level](/glossary/evidence-level). | Readback at E2, event at E3, independent channel required. | | `completion.all_of` | The positive postconditions. Every one must hold. | `status eq succeeded`, `amount eq $input.amount_cents`. | | `negative_conditions.any_of` | The false-success blockers. One gives CONTRADICTED. | More than one refund for this operation. | | `verdict_map` | Observed state to verdict, before completion. | `pending` gives PENDING. `failed` gives FAILED. | | `timing` | Poll interval, backoff, deadline, stale-read window. | Poll every 5 s, stop after 7 days. | | `on_timeout` | The verdict when the deadline passes. VERIFIED is never allowed. | UNVERIFIABLE, escalated to a person. | | `valid_for` | The provider API versions the semantics are proven for. | `>=2025-03-31`. | | `overlays` | Version differences as a merge patch. One contract, no copies. | The 2026-08-26 overlay adds `requires_action`. | ## What does the Stripe refund contract look like? *stripe.refund.succeeded, abridged* ```yaml schema_version: '1.0.0' id: stripe.refund.succeeded version: 1.4.2 service: stripe completion_level: succeeded intent: statement: Refund the charge to the customer. subject: type: stripe.refund identity: { refund_id: $action.result.id } action: canonical_effect: money.refund idempotency: { strategy: idempotency_key, key: $operation.id, header: Idempotency-Key } correlation: strategies: - { name: resource_id, assurance: strong, required: true, keys: [{ name: refund_id, source: $action.result.id }] } evidence_policy: minimum_evidence_level: E2 require_independent_channel: true channels: - { name: provider_readback, evidence_level: E2, independence: provider_readback, verifier: { name: http, version: '^1' } } completion: all_of: - { id: refund_status_succeeded, path: $observed.provider_readback.status, operator: eq, expected: succeeded, evidence: [provider_readback] } - { id: refund_amount_matches, path: $observed.provider_readback.amount, operator: eq, expected: $input.amount_cents, evidence: [provider_readback] } negative_conditions: any_of: - { id: duplicate_refund_present, class: duplicate_side_effect, reason_code: duplicate_refund, path: $observed.provider_readback.operation_refund_count, operator: gt, expected: 1, evidence: [provider_readback] } timing: { poll_interval_ms: 5000, timeout_ms: 604800000, stale_read_window_ms: 20000 } on_timeout: { result: UNVERIFIABLE, reason_code: evidence_unavailable_before_timeout, escalate_to_human_review: true } valid_for: { provider_api_versions: ['>=2025-03-31'] } ``` The [Stripe contract page](/verify/stripe/stripe.refund.succeeded) renders every condition from the signed manifest. ## Why are completion levels separate contracts? **Because a service makes more than one promise. Resend accepts, sends, and delivers an email as three events. Each level is one contract, so an agent cannot upgrade the promise it made.** - `resend.email.accepted`, `resend.email.sent`, `resend.email.delivered`, and `resend.email.bounced` are four contracts. - `shopify.refund.created` and `shopify.refund.financially_completed` are two contracts, because a Refund object does not prove money moved. - `stripe.refund.created` and `stripe.refund.succeeded` are two contracts, because `pending` is not `succeeded`. ## Which rules does the schema enforce? - Every condition names an evidence channel that the contract declares. - A channel cannot claim a level above its path. A reading of the action response is E1 at most. - A weak correlation strategy states a time window. An Official contract needs one strong strategy. - A PENDING result on timeout must escalate to a person. An operation always ends. - `verdict_map` and `on_timeout` can never give VERIFIED. Only the completion block can. - An overlay adds a condition. It cannot remove one, change the identity, or weaken the evidence policy. - The document rejects an unknown member with a clear error. The published schema is `completion-contract.schema.json`, JSON Schema draft 2020-12, in the `@provely/core` package. Source: https://schemas.provely.sh/v1/completion-contract.schema.json (retrieved 2026-09-05) ## How does composition work? A contract can `use` other contracts as sub-contracts. The runtime combines their verdicts with frozen precedence rules. One CONTRADICTED component contradicts the whole. One PENDING component keeps the whole PENDING. VERIFIED needs every component VERIFIED. ### Can I write a contract by hand? Yes. The schema and the loader are public. The Integration Compiler writes the Official contracts, because it records provenance and runs the conformance matrix. ### What happens when the provider ships a new API version? The drift monitor fingerprints the schema and the docs, classifies the change, and recompiles only the affected contracts. A version outside `valid_for` gives UNVERIFIABLE with the reason `version_unsupported`. The runtime never falls back to "latest". ### How is the contract hash computed? The runtime canonicalizes the document as RFC 8785 JSON without the hash member and takes the SHA-256. TypeScript, Python, and Rust produce the same bytes. The cross-language fixtures prove it. ## Read next - [Read how a prompt becomes a contract](https://provely.sh/docs/intent-compilation) - [Read what a receipt proves](https://provely.sh/receipts) - [Read the glossary definition of a completion contract](https://provely.sh/glossary/completion-contract) - [Read the Stripe verification page](https://provely.sh/verify/stripe) - [Open the quick start](https://provely.sh/docs/quick-start) --- # What does a signed receipt prove? > A receipt names the contract, its version and hash, the evidence, the observations, and the verdict. It is signed with Ed25519. Validate it offline. Canonical: https://provely.sh/receipts Last reviewed: 2026-09-05 **A receipt proves which contract the runtime evaluated, at which version and hash, against which observations, and what the verdict was. Ed25519 signs it, so anyone checks it offline without trusting the dashboard.** A receipt carries references to evidence, never raw provider payloads. It names the skill version, the provider API version, the evidence levels used, and the time of verification. ## What does a receipt look like? *A VERIFIED receipt for stripe.refund.succeeded. The build signed this document with the public core test key and verified it.* ```json { "schema_version": "1.0.0", "id": "rc_01ARZ3NDEKTSV4RRFFQ69G5FB1", "issued_at": "2026-09-05T14:03:26.006Z", "issuer": "provely-runtime", "operation_id": "op_01ARZ3NDEKTSV4RRFFQ69G5FAV", "intent": { "statement": "Refund the charge to the customer." }, "contract": { "id": "stripe.refund.succeeded", "version": "1.0.0", "hash": "83491ff981adfd05086d9b90d93e6cdb6cfccafa5554e296b732e5dc0486e7c6" }, "skill": { "service": "stripe", "skill_version": "0.1.0", "certification": "community" }, "versions": { "provider_api_version": "2026-08-26", "runtime_version": "0.1.0" }, "verdict": { "verdict": "VERIFIED", "terminal": true, "reason_code": "all_conditions_satisfied", "reason": "The evidence satisfies every condition of the contract.", "evidence_levels_used": [ "E2" ] }, "observations": [ { "id": "obs_readback_1", "kind": "observation", "channel": "refund_readback", "evidence_level": "E2", "independence": "provider_readback", "digest": "723aefd14209efcc53cbc32bc3fa445e141470a1a1855283cd57bf5a40ffdc0e", "observed_at": "2026-09-05T14:03:26.004Z" } ], "attempt_count": 3, "verified_at": "2026-09-05T14:03:26.005Z", "signature": { "algorithm": "ed25519", "canonicalization": "jcs", "key_id": "provely-test-key-1", "public_key": "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a", "value": "83e03aeb99c05e4f97d9abf50dec9d87c2aa4345b82fe28d25e97b73f266ee8aa95f9e913ce26391a718f676be26e1ec30bebeb8ca79cd1292d5f464e4a59007", "payload_sha256": "800af02aa9a9809f9edcaa2f54f16c8378ecd9eed92b30e8f50b059c00a7442c" } } ``` ## How do I validate a receipt offline? ### Validate a receipt with the CLI 1. **Install the CLI.** Download the `provely` static binary for Linux, macOS, or Windows, or run `npx provely`. 2. **Put the trusted keys in the configuration.** The validator needs a key map that you control. It maps a key id to a public key. A receipt that verifies against its own embedded key proves nothing. 3. **Run the validator.** Run `provely receipt validate receipt.json`. The exit code is the verdict code: 0 VERIFIED, 2 PENDING, 3 FAILED, 4 CONTRADICTED, 5 UNVERIFIABLE. An invalid receipt gives 1. 4. **Gate on the exit code.** A pipeline step passes only on a valid VERIFIED receipt. A valid PENDING receipt is not done. *The validator output* ```text $ provely receipt validate rc_01ARZ3NDEKTSV4RRFFQ69G5FB1.json contract hash ok canonical json ok signature ok key provely-test-key-1 key trusted ok from your key map evidence claim ok E2 present on one observation verdict VERIFIED exit 0 ``` > This receipt names the skill `stripe` at version 0.1.0, certification community, and the contract `stripe.refund.succeeded` at version 1.0.0. Those are the values of the signed skill package that this site renders. Read the [stripe verification page](/verify/stripe). ## Which checks does the validator run? 1. The document validates against `receipt.schema.json`. 2. The canonical JSON of the document without the signature member hashes to `signature.payload_sha256`. 3. The Ed25519 signature verifies against the public key. 4. The key id maps to that public key in your trusted key map. 5. A VERIFIED verdict declares one evidence level above E0, and every declared level appears on an observation reference. 6. A VERIFIED component names the channel that supports it. > The conformance fixtures carry four forgeries. One is signed by a rogue key. One holds a tampered verdict with a repaired digest. One claims VERIFIED and carries no observation. The TypeScript, Python, and Rust validators reject all of them with the same reason codes. A receipt states the contract hash in `contract.hash`. The published receipt schema requires a VERIFIED receipt to carry one observation reference with an evidence level of E1 or higher. Source: https://schemas.provely.sh/v1/receipt.schema.json (retrieved 2026-09-05) ### Does a receipt contain the provider response? No. It holds a reference to each observation: a digest, a channel, an evidence level, and a time. Raw evidence stays optional, encrypted, and short-lived. ### Can a receipt say VERIFIED on the agent word alone? No. The receipt builder and the schema reject a VERIFIED claim whose evidence levels are absent, empty, or E0 only. ### Why is canonical JSON needed? Three languages must sign and verify identical bytes. RFC 8785 fixes member order, number formatting, and string escaping. The fixtures cover the traps: `-0`, `1e-7`, and UTF-16 code unit order. ## Read next - [Read what a completion contract contains](https://provely.sh/contracts) - [Read the CLI reference](https://provely.sh/docs/cli) - [Read the glossary definition of a receipt](https://provely.sh/glossary/receipt) - [Read how the verdict is produced](https://provely.sh/how-it-works) --- # Which agents work with Provely? > Provely works with any agent through four surfaces: REST API, MCP server, CLI, and SDKs. One page per agent, with its guidance files and enforcement. Canonical: https://provely.sh/agents Last reviewed: 2026-09-05 **Any agent works with Provely. Every agent connects through four surfaces: the REST API, the MCP server, the CLI, and the SDKs. Each target is one profile plus guidance files.** No agent forks the core. A new agent needs a profile and rendered guidance, not code. | Agent | Kind | MCP | CLI | Hooks | CI gate | Verified on | | --- | --- | --- | --- | --- | --- | --- | | [Claude Code](/agents/claude-code) | coding agent | Supported | Supported | Supported | yes | 2026-09-05 | | [Codex](/agents/codex) | coding agent | Verify at implementation | Supported | Verify at implementation | yes | 2026-09-05 | | [Cursor](/agents/cursor) | coding agent | Verify at implementation | Supported | Verify at implementation | yes | 2026-09-05 | | [Generic agent](/agents/generic) | agent | Supported | Supported | Not supported | yes | 2026-09-05 | | [Grok](/agents/grok) | autonomous agent | Verify at implementation | Supported | Not supported | yes | 2026-09-05 | | [Hermes](/agents/hermes) | autonomous agent | Supported | Supported | Not supported | yes | 2026-09-05 | | [LangGraph](/agents/langgraph) | agent framework | Supported | Supported | Not supported | yes | 2026-09-05 | | [OpenAI Agents SDK](/agents/openai-agents) | agent framework | Supported | Supported | Supported | yes | 2026-09-05 | | [OpenClaw](/agents/openclaw) | autonomous agent | Verify at implementation | Supported | Not supported | no | 2026-09-05 | | [pi](/agents/pi) | coding agent | Not supported | Supported | Verify at implementation | yes | 2026-09-05 | ## What does every agent do, on every surface? 1. `begin(contract, input)` returns an operation id and the correlation and idempotency metadata. 2. The agent does the side-effecting action with that metadata. 3. `action_result(operation_id)` submits the provider acknowledgement. 4. `verify(operation_id)` returns VERIFIED, PENDING, CONTRADICTED, FAILED, or UNVERIFIABLE. 5. `status` and `receipt` resume the operation later and fetch the signed receipt. > The agent is untrusted. An agent report is E0, which is never sufficient. No surface gives an agent the verifier credentials. ## Read next - [Verify Claude Code actions](https://provely.sh/agents/claude-code) - [Verify Codex actions](https://provely.sh/agents/codex) - [Verify Cursor actions](https://provely.sh/agents/cursor) - [Verify Generic agent actions](https://provely.sh/agents/generic) - [Verify Grok actions](https://provely.sh/agents/grok) - [Verify Hermes actions](https://provely.sh/agents/hermes) - [Verify LangGraph actions](https://provely.sh/agents/langgraph) - [Verify OpenAI Agents SDK actions](https://provely.sh/agents/openai-agents) - [Verify OpenClaw actions](https://provely.sh/agents/openclaw) - [Verify pi actions](https://provely.sh/agents/pi) - [Read the MCP server reference](https://provely.sh/docs/mcp) - [See every verified service](https://provely.sh/verify) --- # What is the false-completion benchmark? > The benchmark lists the cases where an agent action looks done and is not. Every skill must pass all of them with zero false VERIFIED before it ships. Canonical: https://provely.sh/benchmark Last reviewed: 2026-09-05 **The false-completion benchmark is the set of cases where an agent action looks complete and is not. Every service skill must pass every case, with zero false VERIFIED results, before Provely signs it.** The oracle of each case is independent from the contract under test. A harness simulator plays the provider. The cases come from the provider semantics, the chaos cases, and the version rules. ## Which cases does the benchmark require? This table is the specification. Each skill runs its own cases against these rules. The next table states the case classes that the last run covered. *Benchmark version 1.0.0. The required result of each case.* | Case | Scenario | Required result | Class | | --- | --- | --- | --- | | `terminal_success` | Action accepted, terminal success confirmed | VERIFIED | positive | | `still_transitional` | Action accepted, provider still transitional | PENDING | progress | | `terminal_failure` | Provider reports terminal failure | FAILED | failure | | `wrong_subject` | Correct resource, wrong amount or subject | CONTRADICTED | false success | | `duplicate_effect` | Duplicate side effect for one operation | CONTRADICTED | false success | | `stale_readback` | Readback stale inside the consistency window | PENDING | progress | | `evidence_timeout` | Evidence unavailable until the timeout | UNVERIFIABLE | insufficient | | `pre_existing_state` | Pre-existing matching state, no causal link | Must not verify | false success | | `webhook_duplicate` | Webhook duplicated | No duplicate transition | events | | `webhook_out_of_order` | Webhook out of order | Reconciled by provider semantics | events | | `timeout_after_commit` | Timeout after the provider committed | VERIFIED after readback, never FAILED | chaos | | `five_xx_after_execution` | 5xx after the provider executed | VERIFIED after readback, never a retry | chaos | | `version_unsupported` | Provider version outside valid_for | UNVERIFIABLE with version_unsupported | versions | ## Which case classes did the last runs cover? *The case classes of the last conformance run, by service.* | Case class | Resend | Shopify Admin API | Stripe | | --- | --- | --- | --- | | duplicate side effect | 4 of 4 | 2 of 2 | 2 of 2 | | error after execution | 4 of 4 | 1 of 2 | 1 of 2 | | error before execution | 4 of 4 | 2 of 2 | 2 of 2 | | evidence unavailable | 4 of 4 | 2 of 2 | 2 of 2 | | idempotent retry | 3 of 4 | not run | 2 of 2 | | pre existing state | 4 of 4 | 2 of 2 | 2 of 2 | | stale readback | 4 of 4 | 2 of 2 | 2 of 2 | | still transitional | 4 of 4 | 2 of 2 | 2 of 2 | | terminal failure | 4 of 4 | 2 of 2 | 2 of 2 | | terminal success | 3 of 4 | 2 of 2 | 2 of 2 | | timeout after commit | 4 of 4 | 1 of 2 | 1 of 2 | | version mismatch | 4 of 4 | 2 of 2 | 2 of 2 | | webhook duplicate | 4 of 4 | 2 of 2 | 2 of 2 | | webhook out of order | 4 of 4 | 2 of 2 | 2 of 2 | | wrong amount | not run | 2 of 2 | 2 of 2 | | wrong subject | 4 of 4 | 2 of 2 | 2 of 2 | ## What are the results per skill? **The table reads the conformance summary of each signed skill manifest. A skill with one critical false VERIFIED is rejected. The numbers change when a skill is recompiled.** | Service | Skill version | Cases | Passed | Critical false VERIFIED | Certification | Last run | Source | | --- | --- | --- | --- | --- | --- | --- | --- | | [Resend](/verify/resend) | 0.1.0 | 60 | 58 | 0 | Community | 2026-09-05T12:00:00Z | signed package | | [Shopify Admin API](/verify/shopify) | 0.1.0 | 30 | 28 | 0 | Community | 2026-09-05T12:00:00Z | signed package | | [Stripe](/verify/stripe) | 0.1.0 | 32 | 30 | 0 | Community | 2026-09-05T12:00:00Z | signed package | ## How is the benchmark scored? - A false VERIFIED on any case rejects the skill. There is no partial credit. - The sandbox conformance dimension scores 0 to 10 points of the 100-point confidence score. - Three hard caps apply before the level. Unknown terminal semantics cap at 49. No causal correlation caps at 69. Action-response-only evidence caps at 49. - Community is the first level. Generated draft needs 50 or more. Verified needs 75 or more and the gates. Official needs 90 or more, every critical test, and every reviewed uncertainty. ### Can I run the benchmark against my own contract? Yes. The harness package runs the conformance matrix against any contract with the simulator or with record-and-replay fixtures. The oracle must not be the contract under test. ### Where is the machine-readable result? The `/facts` endpoint publishes the current cases, levels, and certification of every skill as JSON-LD. ## Read next - [Read the frozen safety rules](https://provely.sh/how-it-works) - [See every verified service](https://provely.sh/verify) - [Read the machine-readable facts](https://provely.sh/facts) --- # What does Provely cost? > Every plan carries every feature. Developer is free with 1,000 verified actions a month. Startup is $99, Pro is $249, Team is $499. Canonical: https://provely.sh/pricing Last reviewed: 2026-09-05 **Provely charges per verified action. Every plan carries every feature. Only the allowance changes. Developer is free with 1,000 verified actions. Startup, Pro, and Team cost $99, $249, and $499 a month for 10,000, 50,000, and 250,000 actions.** A verified action is one metered call to the verification API. The plan bucket pays first and refills each calendar month. A bought pack pays the rest and does not expire. ## Which plans exist? | Plan | Price | Verified actions per month | | --- | --- | --- | | Developer | Free | 1,000 | | Startup | $99 per month | 10,000 | | Pro | $249 per month | 50,000 | | Team | $499 per month | 250,000 | ## What does each plan include? > Every plan includes every feature in this list. Only the monthly allowance changes. - Intent compilation: pass the agent prompt, then confirm the compiled contract. - The hosted verification runtime, and the local runtime you run yourself. - Every verifier: HTTP readback, SQL, webhook, and your own. - Every Official skill, with the version support and the drift alerts. - Provider event ingestion, with signature checks and deduplication. - Workflow contracts across more than one system. - Evidence history, retry directives, and the receipt archive. - The dashboard, the alerts, and every seat on your team. - The SDKs, the CLI, the MCP server, and the REST API. You never compare four feature lists. Pick the row that matches your volume, and change it in the dashboard when the volume changes. ## What is a metered action? - Each call to `POST /v1/operations/{id}/verify` reserves one credit, then settles it. - A call with a reused idempotency key returns the stored result. It is not counted again. - A refunded call returns its credit. A retry runs again. - The plan bucket pays first. The bought bucket pays when the plan bucket is empty. - When both buckets are empty, the API answers 402 with the plans and the packs you can buy. ## Which packs exist? | Pack | Verified actions | Price | | --- | --- | --- | | 1,000 verified actions | 1,000 | $29 once | | 10,000 verified actions | 10,000 | $199 once | > Always free: the SDKs, the contract format, the receipt validator, and the generic verifier interface. The compiler and the maintained Official skills are the paid product. ### Does a cheaper plan give me fewer features? No. Every plan carries every feature. The Developer plan verifies 1,000 actions a month, and the Team plan verifies 250,000. ### Is a PENDING verdict charged? Each verify call is one metered action. Set a poll interval in the contract timing policy, so the runtime observes at the pace the provider needs. ### Do I need a card for the Developer plan? No. The Developer plan refills 1,000 verified actions on the first call of each month. ### How do I pay? Through Stripe Checkout. The API grants credits only from a signed Stripe webhook. A refund or a dispute reverses the grant once. ## Read next - [Start with the quick start](https://provely.sh/docs/quick-start) - [Read the API reference](https://provely.sh/docs/api) - [See the verified services](https://provely.sh/verify) --- # Where do I start with Provely? > The quick start, the TypeScript and Python SDKs, the provely CLI, the MCP server, and the REST API reference. Every page answers first. Canonical: https://provely.sh/docs Last reviewed: 2026-09-05 **Start with the [quick start](/docs/quick-start). It takes one Stripe refund from `begin` to a signed receipt. Then pick the surface your agent uses: the SDK, the CLI, the MCP server, or the REST API.** | Page | Purpose | | --- | --- | | [Quick start](/docs/quick-start) | First verified outcome in under ten minutes. | | [Intent compilation](/docs/intent-compilation) | From an agent prompt to a signed completion contract. | | [Verdicts and retries](/docs/verdicts) | What each verdict means and what the agent may do next. | | [Integration compiler](/docs/integration-compiler) | How one vendor becomes one signed skill, in six stages. | | [SDKs](/docs/sdks) | The TypeScript and Python SDKs and the canonical model. | | [CLI](/docs/cli) | The provely binary: scan, verify, status, receipt validate, mcp, init. | | [MCP server](/docs/mcp) | The four tools: begin, verify, status, receipt. | | [API reference](/docs/api) | The /v1 control plane endpoints. | | [Version support](/docs/version-support) | How Provely tracks provider API, event, SDK, protocol, and agent host versions. | | [Security](/docs/security) | The credential boundary: the agent writes, the verifier reads. | ## What is the one loop every surface implements? ```text 1. begin(contract, input) -> operation_id + correlation/idempotency metadata 2. act() -> the AGENT does the side-effecting action 3. action_result(operation_id) -> submit the provider acknowledgement 4. verify(operation_id) -> VERIFIED | PENDING | CONTRADICTED | FAILED | UNVERIFIABLE 5. status / receipt -> poll later; fetch the signed receipt ``` ## Read next - [Read how Provely works](https://provely.sh/how-it-works) - [See every verified service](https://provely.sh/verify) - [See every agent integration](https://provely.sh/agents) --- # How do I verify my first refund? > Open an operation against stripe.refund.succeeded, make the refund call with the idempotency key, submit the result, and verify. Ten minutes. Canonical: https://provely.sh/docs/quick-start Last reviewed: 2026-09-05 **Install the SDK, open an operation against `stripe.refund.succeeded`, make the refund call with the idempotency key from `begin`, submit the response, and call `verify`. The first verified outcome takes under ten minutes with an Official skill.** ## Which steps does the quick start take? ### Verify a Stripe refund with the TypeScript SDK 1. **Install the SDK.** Run `npm install @provely/sdk` or `pip install provely`. 2. **Set the API key.** Create a key in the dashboard and export it as `PROVELY_API_KEY`. The SDK reads it. The key never goes to the agent prompt. 3. **Connect Stripe with a read-only key.** Call `POST /v1/connections` with a restricted Stripe key that can read refunds. The verifier reads with this key. Your agent keeps its own write key. 4. **Begin the operation.** Call `begin` with the contract `stripe.refund.succeeded` and the input `{ charge_id, amount_cents }`. Keep `op.idempotency_key`. 5. **Make the refund call.** Call `stripe.refunds.create` with the `Idempotency-Key` header set to `op.idempotency_key`. 6. **Submit the acknowledgement.** Call `op.actionResult(refund)` with the Stripe response. 7. **Verify and report.** Call `op.verify()`. Report the verdict exactly as returned. On VERIFIED, download the receipt with `op.receipt()`. *The whole loop* ```typescript import { Provely } from '@provely/sdk'; import Stripe from 'stripe'; const provely = new Provely({ baseUrl: 'https://api.provely.sh' }); const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!); const op = await provely.begin({ contract: 'stripe.refund.succeeded', input: { charge_id: 'ch_3QxT5s2eZvKYlo2C', amount_cents: 14200 }, }); const refund = await stripe.refunds.create( { charge: 'ch_3QxT5s2eZvKYlo2C', amount: 14200 }, { idempotencyKey: op.idempotency_key }, ); await op.actionResult(refund); const verification = await op.verify(); switch (verification.verdict) { case 'VERIFIED': console.log('The action is verified complete. Receipt:', verification.receipt_id); break; case 'PENDING': console.log('The action is accepted but not yet verified. Operation:', op.id); break; default: console.log('Verification did not confirm the outcome:', verification.verdict, verification.reason); } ``` *The same loop in Python* ```python from provely import Provely provely = Provely(base_url="https://api.provely.sh") op = provely.begin( contract="stripe.refund.succeeded", input={"charge_id": "ch_3QxT5s2eZvKYlo2C", "amount_cents": 14200}, ) refund = stripe.Refund.create( charge="ch_3QxT5s2eZvKYlo2C", amount=14200, idempotency_key=op.idempotency_key ) op.action_result(refund) verification = op.verify() print(verification.verdict) # VERIFIED, PENDING, CONTRADICTED, FAILED, or UNVERIFIABLE ``` ## What does each verdict mean for the agent? | Verdict | What the agent says | | --- | --- | | VERIFIED | "The action is verified complete. Receipt: ``." | | PENDING | "The action is accepted but not yet verified. Operation: ``." | | CONTRADICTED | "Verification found a different outcome than requested. Do not retry blindly." | | UNVERIFIABLE | "I cannot prove the outcome. Treat the action as unconfirmed." | | FAILED | "The provider reports that the action failed." | ### Can I skip begin and only call verify? No. `begin` binds the idempotency key and the correlation keys to the operation. Without it the runtime cannot tell your refund from a pre-existing one, and a pre-existing match must not verify. ### How long does verify wait? One call observes once and returns. PENDING is a normal answer. Call `status` later, or use `provely verify --wait 10m` from the CLI to poll until a terminal verdict. ## Read next - [Read the Stripe verification page](https://provely.sh/verify/stripe) - [Read the SDK reference](https://provely.sh/docs/sdks) - [Read the CLI reference](https://provely.sh/docs/cli) - [Read what a receipt proves](https://provely.sh/receipts) --- # How does Provely turn a prompt into a contract? > You pass the prompt, the context and the tools. Provely compiles a completion contract, you confirm it, and the receipt binds the ask to the promise. Canonical: https://provely.sh/docs/intent-compilation Last reviewed: 2026-09-05 **You pass the agent prompt, the context and the tools. Provely compiles a completion contract: the steps, the evidence, the correlation keys and the negative postconditions. You confirm it once. You never write it.** Writing a contract by hand is the work this removes. A language model may propose the contract. The contract decides completion. A language model judgement is never completion evidence. > A contract can be honest and still answer the wrong question. "Buy the cheapest blue shirt under 50 dollars" compiled to "an order exists" verifies truthfully and misses the ask. The three controls below stop that. ## What do you pass? - **intent** "Refund order 4471 for $142 and email the customer." - **context** { order_id: "4471", customer: "cus_8k2Rv1LmQ9xT" } - **tools** [stripe.refunds, shopify.inventory, resend.emails] ## What does the compiler return? - **stripe.refund.succeeded** E2 + E3 Read the refund by id, then wait for refund.updated. Correlate by refund id and payment intent. Amount 14200 usd. - **shopify.inventory.adjusted** E2 Read the inventory level back. Correlate by line item, never by a matching count. - **resend.email.delivered** E3 Wait for the delivery event. Accepted and sent are different promises. No second settled refund exists for this payment intent. “the customer” must resolve to one address. Confirm it before the run. Provely never drops a part of the task in silence. A part that no contract can check is marked REQUIRES_REVIEW, and it says so on the confirmation screen. ## What does the code look like? *The minimal call* ```typescript // Three lines. Provely compiles the rest. const op = await provely.begin({ intent: task.prompt, context }) await agent.run(task) const v = await op.verify() ``` *What it compiled* ```yaml contract: order.refund.completed # compiled from the intent subject: { order_id: "4471" } steps: - stripe.refund.succeeded # E2 readback + E3 event correlate: [refund_id, payment_intent] amount: 14200 usd - shopify.inventory.adjusted # E2 readback, by line item - resend.email.delivered # E3 delivery event negative: - no second settled refund for this payment intent review: - "the customer" resolves to one address ``` *Acting on the verdict* ```typescript let v = await op.verify() // PENDING: wait. Never run the action again. while (v.verdict === "PENDING" && v.retry.remaining > 0) { await sleep(v.retry.after_ms) v = await op.verify() } // No evidence for a step: v.feedback names it. Hand it back. while (v.verdict === "UNVERIFIABLE" && v.retry.remaining > 0) { await agent.run(task, { feedback: v.feedback }) v = await op.verify() } // FAILED: the provider refused. The first key stops a double effect. if (v.verdict === "FAILED") { await stripe.refunds.create(input, { idempotencyKey: op.idempotency_key }) v = await op.verify() } // CONTRADICTED: reality already differs. A person decides. if (v.verdict === "CONTRADICTED") await escalate(v) ``` ## Which controls hold intent fidelity? 1. **You confirm the compiled contract before it runs.** The screen states what the contract does not check. 2. **The receipt binds the intent to the promise.** It carries the intent statement, the contract id, the contract version and the contract hash, so an auditor compares the ask with the promise. 3. **A part that no contract can check is marked REQUIRES_REVIEW.** Provely never drops a part of the task in silence. The contract is immutable, versioned, hashed and signed before it verifies anything. Read [what a completion contract contains](/contracts). ### Can a language model decide that the task is complete? No. A language model may propose the contract. The runtime evaluates the contract with operators against provider evidence, and it gives no evidence to a language model. ### What happens to a part of the task that no contract can check? The compiler marks it REQUIRES_REVIEW and shows it on the confirmation screen. The verdict never covers it, and the page never claims it. ### Can I still write a contract by hand? Yes. The schema and the loader are public. Read [what a completion contract contains](/contracts) for the members and the rules. ## Read next - [Read what a completion contract contains](https://provely.sh/contracts) - [Read what a signed receipt proves](https://provely.sh/receipts) - [Read the intent compilation definition](https://provely.sh/glossary/intent-compilation) - [Open the quick start](https://provely.sh/docs/quick-start) --- # What must an agent do after each verdict? > What each verdict means and what an agent may do next. PENDING waits. FAILED retries with the first idempotency key. CONTRADICTED stops for a person. Canonical: https://provely.sh/docs/verdicts Last reviewed: 2026-09-05 **Wait on PENDING. Retry the check on UNVERIFIABLE. Retry the action with the first idempotency key on FAILED. Stop and ask a person on CONTRADICTED. The runtime never performs the correction.** | verdict | what the agent may do next | why | | --- | --- | --- | | PENDING | Wait. Do not retry the action. | The action can still succeed. A retry refunds twice. | | UNVERIFIABLE | Retry the check. Do not retry the action. | The action is not in doubt. The evidence has not arrived. | | FAILED | Retry the action with the first idempotency key. | The provider refused. The key stops a double effect. | | CONTRADICTED | Stop. Ask a person. | Reality already differs from the promise. | ## The verifier never acts. Provely returns a directive and nothing else. Your host carries it out: a Claude Code hook, a framework node or the CI gate. A verifier that acts is no longer independent. Every directive carries the idempotency key of the first attempt and a retry budget. An executor that reaches the budget stops and asks a person. The directive is also feedback. It names the step with no evidence and the evidence that step needs. Pass it into the next agent turn, and the agent finishes what it dropped. ## Why is an acknowledgement not an outcome? One operation, one vendor. Each state returns a refund object and HTTP 200. From the response they look the same. *Five states. One state moves the money.* | State | What it means | Money | | --- | --- | --- | | pending | The bank holds the refund in a queue. No money leaves the account. | NO MONEY | | requires_action | A person outside your system must act first. | NO MONEY | | failed | The bank refused the refund. The object still reads 200. | NO MONEY | | canceled | Someone withdrew the refund before settlement. The customer waits. | NO MONEY | | succeeded | The money moved. Only this state earns the word “done”. | MONEY MOVED | ## Which evidence supports a verdict? Provely ranks evidence from E0 to E5 by its independence from the action path. E0 is the agent word and is never sufficient. Read the [evidence hierarchy](/how-it-works) and the [evidence level definition](/glossary/evidence-level). ## Read next - [Read how the verdict is produced](https://provely.sh/how-it-works) - [Read the verdict definition](https://provely.sh/glossary/verdict) - [Read the CLI reference](https://provely.sh/docs/cli) --- # How does Provely add a new vendor? > The compiler reads a vendor schema, its documents, its events and its sandbox behaviour, then signs one skill. Six stages and six confidence dimensions. Canonical: https://provely.sh/docs/integration-compiler Last reviewed: 2026-09-05 **The compiler reads the vendor schema, the documents, the event catalogue and the sandbox behaviour. It writes the contracts, generates the conformance tests, scores six dimensions, and signs one skill.** Each vendor draws the line between an acknowledgement and an outcome somewhere else. You never write that logic. The compiler reads the vendor’s schema, documents, events and sandbox behaviour, and signs one skill. A new vendor is a command, not a project. *Compile a vendor* ```text $ provely skill generate stripe $ provely skill generate --openapi ./vendor.yaml ``` ## Which stages does the compiler run? 1. **Ingest** Read the OpenAPI or GraphQL schema, the reference documents, the event catalogue and the SDK types. 2. **Classify** Mark every operation that changes the world. Infer the lifecycle of each resource. 3. **Plan the evidence** Find the readback, the event and the independent system that prove the outcome. 4. **Synthesise** Write the completion contracts. Add the negative postconditions that catch duplicates. 5. **Test** Generate the conformance cases. Run them against the vendor sandbox. 6. **Certify and sign** Score six dimensions. Apply the hard caps. Sign the skill and publish it. ## How is a skill certified? Every skill scores six dimensions. **Generated draft** at 50, **Verified** at 75, **Official** at 90. An undocumented semantic caps the score at 49 and is marked REQUIRES_REVIEW. One known false VERIFIED rejects the skill. > A skill states its certification level and its last conformance run on its own page. Read [the verified services](/verify). ## Read next - [See every verified service](https://provely.sh/verify) - [Read how Provely tracks provider versions](https://provely.sh/docs/version-support) - [Read the service verification skill definition](https://provely.sh/glossary/skill) --- # What do the Provely SDKs do? > The Provely SDKs are thin translators into one model: operation, contract, action result, verification, receipt. The types come from the schemas. Canonical: https://provely.sh/docs/sdks Last reviewed: 2026-09-05 **The SDKs wrap the REST API. Each SDK is a thin translator into the same canonical model: operation, contract, action result, verification, and receipt. No SDK contains verification logic. The runtime owns verification.** | SDK | Package | Status | Types | | --- | --- | --- | --- | | TypeScript | `@provely/sdk` | first release | generated from the JSON Schemas | | Python | `provely` | first release | pydantic models generated from the JSON Schemas | | More languages | on request | after the REST API and the schemas support them | generated | ## Which calls does every SDK expose? | Call | REST endpoint | Returns | | --- | --- | --- | | `begin(contract, input)` | `POST /v1/operations` | The operation id, the idempotency key, the correlation keys. | | `op.actionResult(result)` | `POST /v1/operations/{id}/action-result` | The stored acknowledgement reference. | | `op.verify()` | `POST /v1/operations/{id}/verify` | The verdict, the reason, the evidence levels used. | | `op.status()` | `GET /v1/operations/{id}` | The operation state and the last verdict. | | `op.receipt()` | `GET /v1/operations/{id}/receipt` | The signed receipt document. | | `verifyReceipt(receipt, keys)` | offline | The validation result with a reason code. | ## Which rules do all SDKs share? - Generate the types from the contract and receipt schemas. Do not write them by hand. - Pass the same cross-language conformance fixtures: canonical JSON, contract hashes, receipt validation, verdict rules. - Read the API key from configuration. Never accept it as a tool argument. - Return the verdict as the runtime gives it. Do not soften it. *Validate a receipt offline in TypeScript* ```typescript import { verifyReceipt } from '@provely/sdk'; const result = await verifyReceipt(receipt, { trustedKeys: { 'provely-prod-2026-09': '' }, }); // result.valid, result.reasonCode: signature_valid | receipt_key_not_trusted | ... ``` ### Can I use the SDK with a framework adapter? Yes. Adapters for the OpenAI Agents SDK, LangGraph, and MCP wrap a tool or a node so the action runs inside an operation. They register through the `Adapter` extension point and contain no verification logic. ## Read next - [Open the quick start](https://provely.sh/docs/quick-start) - [Read the API reference](https://provely.sh/docs/api) - [Read what a receipt proves](https://provely.sh/receipts) --- # What does the provely CLI do? > provely is one static binary: verify and status drive an operation, receipt validate checks a receipt offline, and mcp serves the tools over stdio. Canonical: https://provely.sh/docs/cli Last reviewed: 2026-09-05 **`provely` is one static binary for Linux, macOS, and Windows. It drives an operation from scripts and CI, validates receipts offline, and serves the MCP tools over stdio.** *Install* ```text # Run without an install npx provely --version # Or download the static binary for your platform and put it on PATH provely --version ``` The CLI is a client of the control plane. It contains no verification logic. ## Which commands exist? | Command | Purpose | | --- | --- | | `provely scan ` | Parse TypeScript and JavaScript, find side-effecting calls, and name the contract that would verify each one. Runs locally. Sends nothing. | | `provely begin --input ` | Open an operation. Print the operation id and the idempotency key. | | `provely action-result --file ` | Submit the provider acknowledgement. | | `provely verify [--wait ]` | Verify once, or poll until a terminal verdict or the deadline. | | `provely status ` | Resume any prior operation. | | `provely receipt validate ` | Validate a receipt offline against your trusted key map. | | `provely skill generate >` | Call the hosted compiler and write the review bundle. | | `provely init --agent ` | Write the guidance files for an agent target from its integration profile. | | `provely mcp` | Serve begin, verify, status, and receipt over stdio. | ## Which exit codes does the CLI use? | Exit code | Meaning | | --- | --- | | 0 | VERIFIED, or a command with no verdict succeeded | | 1 | Error, invalid receipt, or a scan with findings | | 2 | PENDING | | 3 | FAILED | | 4 | CONTRADICTED | | 5 | UNVERIFIABLE | > A usage error exits 1, not 2. The code 2 belongs to PENDING. A CI gate must not read a typo as "not done yet". ## How do I gate a pipeline on a verdict? *A CI step* ```yaml - name: Verify the refund reached succeeded run: provely verify "$OPERATION_ID" --wait 10m --json # exit 0 only on VERIFIED; PENDING exits 2 and fails the step ``` ### Does the scanner send my code anywhere? No. It parses the files locally and prints a report. It makes no network call. ### Where does the CLI read the API key? From its configuration file or the `PROVELY_API_KEY` environment variable. There is no `--api-key` flag, so a key never lands in a shell history or a process list. ## Read next - [Read the MCP server reference](https://provely.sh/docs/mcp) - [Read how to validate a receipt](https://provely.sh/receipts) - [See every agent integration](https://provely.sh/agents) --- # How does the Provely MCP server work? > The MCP server exposes four tools. Hosted mode uses HTTP with a bearer token. Local mode runs provely mcp over stdio. No tool takes an API key. Canonical: https://provely.sh/docs/mcp Last reviewed: 2026-09-05 **The MCP server exposes four tools: `begin`, `verify`, `status`, and `receipt`. Hosted mode serves streamable HTTP with a bearer token. Local mode runs `provely mcp` over stdio. No tool takes an API key.** | Tool | Input | Output | | --- | --- | --- | | `begin` | `contract`, `input` | operation id, idempotency key, correlation keys | | `verify` | `operation_id` | verdict, reason, evidence levels used | | `status` | `operation_id` | operation state, last verdict | | `receipt` | `operation_id` | the signed receipt document | > Every tool description carries the core rule: a successful tool call is not proof of completion. The server reads the bearer token inside each tool handler and never returns a credential. ## How do I register the server? *.mcp.json for a local stdio server* ```json { "mcpServers": { "provely": { "command": "provely", "args": ["mcp"] } } } ``` *The hosted server* ```json { "mcpServers": { "provely": { "type": "http", "url": "https://api.provely.sh/mcp", "headers": { "Authorization": "Bearer " } } } } ``` ## How does an agent drive the four tools? ### Use the MCP tools from an agent 1. **Call begin.** Pass the contract id and the input. Keep the operation id and the idempotency key. 2. **Do the action.** Use the idempotency key in the provider request. 3. **Call verify.** Pass the operation id. Read the verdict. 4. **Report the verdict as returned.** On PENDING, give the operation id and call status later. On VERIFIED, call receipt. ### Which agents support MCP today? Claude Code, Cursor, Codex, the OpenAI Agents SDK, and LangGraph state MCP support in their profiles. OpenClaw, pi, and Grok are marked verify at implementation. Read the [agent pages](/agents). ## Read next - [Verify Claude Code actions](https://provely.sh/agents/claude-code) - [Read the CLI reference](https://provely.sh/docs/cli) - [Read the API reference](https://provely.sh/docs/api) --- # Which endpoints does the Provely API expose? > The REST API is the only place verification happens: operations, action results, verify, receipts, events, contracts, skills, and usage under /v1. Canonical: https://provely.sh/docs/api Last reviewed: 2026-09-05 **The control plane at `https://api.provely.sh` exposes ten endpoints under `/v1`. It is the only place verification happens. Every other surface is a thin client of this API.** | Method and path | Purpose | Metered | | --- | --- | --- | | `POST /v1/operations` | Create an operation against a contract. Returns the idempotency key and the correlation keys. | no | | `POST /v1/operations/{id}/action-result` | Submit the provider acknowledgement (E1). | no | | `POST /v1/operations/{id}/verify` | Observe once and evaluate the contract. | yes, one verified action | | `GET /v1/operations/{id}` | Read the operation state and the last verdict. | no | | `GET /v1/operations/{id}/receipt` | Read the signed receipt. | no | | `POST /v1/events/{provider}/{workspace}` | Receive a provider webhook. The signature is validated and the event is deduplicated. | no | | `GET /v1/contracts/{id}` | Read a contract by id. | no | | `GET /v1/skills/{service}` | Read the skill manifest of a service. | no | | `POST /v1/connections` | Store a read-only provider credential, encrypted. | no | | `GET /v1/usage` | Read the plan bucket, the bought bucket, and the verified actions this period. | no | ## How does authentication work? - Send `Authorization: Bearer pv_...` with an API key, or an OAuth access token from the pinned issuer. - The control plane hashes an API key at rest. A key carries scopes, expires, and rotates with a grace time. - The credential decides the account. There is no account id in the request body. - Every response carries a request id in `x-request-id`. ## How does a metered call behave? 1. Rate limit, then request size, then parse, then preflight. 2. Idempotency: a reused `Idempotency-Key` with the same body returns the stored result. A different body returns 422. 3. Reserve one credit, run, then settle. A failed run refunds the credit. 4. With no credit left, the response is 402 with the plans and the packs in `payment`. *Create and verify an operation with curl* ```text curl -X POST https://api.provely.sh/v1/operations \ -H "Authorization: Bearer $PROVELY_API_KEY" \ -H "Content-Type: application/json" \ -d '{"contract":"stripe.refund.succeeded","input":{"charge_id":"ch_3QxT5s2eZvKYlo2C","amount_cents":14200}}' curl -X POST https://api.provely.sh/v1/operations/op_01J.../verify \ -H "Authorization: Bearer $PROVELY_API_KEY" \ -H "Idempotency-Key: verify-op_01J...-1" ``` ### Is there an OpenAPI document? Yes. The control plane serves `/v1/openapi.json`. The SDK clients are generated from it. ### Which events does the billing webhook accept? The six Stripe events for checkout, invoices, refunds, and disputes, plus `checkout.session.async_payment_succeeded`. The control plane grants credits only from a signed webhook. ## Read next - [Read the SDK reference](https://provely.sh/docs/sdks) - [Read the pricing](https://provely.sh/pricing) - [Read what a receipt proves](https://provely.sh/receipts) --- # What does Provely do with a provider version? > Provely tracks the provider API version, the event payload version, the SDK version, the protocol version, and the agent host version, each on its own. Canonical: https://provely.sh/docs/version-support Last reviewed: 2026-09-05 **Provely supports more than one version of each external API. It tracks five version dimensions separately and records the versions in effect for each operation in the receipt. An unsupported version returns UNVERIFIABLE.** | Dimension | Example | Where it is recorded | | --- | --- | --- | | Provider API version | `2026-08-26` for Stripe, `2025-07` for Shopify | The contract `valid_for` and the receipt. | | Event payload version | The `api_version` on a webhook event | The contract `valid_for.event_payload_versions`. | | Provider SDK version | The Stripe or Resend client library | The receipt `versions.provider_sdk_version`. | | Protocol version | OpenAPI 3.1, GraphQL, MCP | The registry key of the ingester or the adapter. | | Agent host version | Claude Code 2.1.261 | The integration profile `host_versions`. | The runtime never falls back to "latest". An unsupported version returns the reason `version_unsupported`. ## What happens on a version the skill does not support? - The runtime returns UNVERIFIABLE with the reason `version_unsupported`. It does not guess. - A registry lookup with no match is an error, not a fallback. - A contract that declares no `valid_for.provider_api_versions` covers no known provider version. - An overlay states the difference between two versions as a merge patch. It can add a condition. It cannot remove one or weaken the evidence policy. ## What happens when a provider changes? The drift monitor fingerprints the schemas, the documentation, and the observed behaviour. It classifies a change as cosmetic, additive, contract-affecting, or breaking. It recompiles only the affected contracts, runs targeted conformance, and signs a new skill version. When uncertainty rises, the certification goes down. It never rises automatically. Read the [drift definition](/glossary/drift). ### Can one contract cover two provider versions? Yes. The contract states a version range in `valid_for` and puts each difference in an overlay. There is never one copy of a contract per version. ### Where do I see the version that decided my operation? In the receipt, under `versions`. The dashboard shows the same values on the operation detail page. ## Read next - [Read what a completion contract contains](https://provely.sh/contracts) - [See the supported provider versions of each service](https://provely.sh/verify) - [Read the drift definition](https://provely.sh/glossary/drift) --- # How does Provely keep credentials apart? > The agent holds the action credentials. Provely holds read-only verifier credentials. No surface mixes them or returns a credential to an agent. Canonical: https://provely.sh/docs/security Last reviewed: 2026-09-05 **The agent holds the credentials that write. Provely holds separate credentials that read, where the provider permits a read-only key. No surface gives an agent the verifier credentials, and no surface returns a provider secret.** | Rule | What it means | | --- | --- | | Separate credentials | The agent writes with its key. The verifier reads with a restricted key that you store through `POST /v1/connections`. | | Encrypted at rest | A stored provider credential is encrypted. The configuration never logs it. | | Redacted telemetry | A provider response is redacted before it reaches a log or a span. | | Short retention | Raw provider evidence is optional, encrypted, and kept for a short time. A receipt holds a digest, not a payload. | | Signed webhooks | The runtime validates every event signature and drops a duplicate event. The contract reconciles a replay and a late arrival by the provider clock, not by arrival order. | | The agent is untrusted | An agent report is evidence level E0. It can never support VERIFIED. | ## How does an agent authenticate? - An API key `pv_...` in the `Authorization` header, hashed at rest under a server pepper, with scopes, an expiry, and rotation. - Or an OAuth access token from the pinned issuer, with the scope checked on each call. - The MCP server reads the bearer token inside each tool handler. No tool takes an API key as an argument. - The CLI reads the key from its configuration file or the environment. There is no `--api-key` flag. > A receipt that verifies against a key embedded in the receipt proves nothing. The validator needs a trusted key map that you control. Read [what a receipt proves](/receipts). ### Can Provely act on my provider account? No. The runtime never performs the action. It reads. Where a provider offers a restricted read-only key, use one. ### What reaches your servers? The operation, the contract id, the correlation keys, and the observations the contract needs. ## Read next - [Read what a receipt proves](https://provely.sh/receipts) - [Read the API reference](https://provely.sh/docs/api) - [See every agent integration](https://provely.sh/agents) --- # Which terms does Provely use? > One-sentence definitions of the Provely terms: intent, action, acknowledgement, outcome, completion, correlation, idempotency, evidence level, verdict. Canonical: https://provely.sh/glossary Last reviewed: 2026-09-05 **Provely uses one approved word for one meaning. This glossary defines each term in one sentence and links to the page that explains it.** | Term | Definition | | --- | --- | | [Intent](/glossary/intent) | What the user asked for, stated before any action. | | [Action](/glossary/action) | What the agent attempted against the provider. | | [Acknowledgement](/glossary/acknowledgement) | What the provider returned at once, such as HTTP 200 and an object. | | [Outcome](/glossary/outcome) | The observable resulting state in the real system. | | [Completion](/glossary/completion) | The outcome satisfies the completion contract. | | [Completion contract](/glossary/completion-contract) | A machine-readable, versioned, hashable definition of done for one operation. | | [Completion level](/glossary/completion-level) | One named promise of a service, proven by one contract. | | [Correlation](/glossary/correlation) | The binding of evidence to the exact operation through keys such as a resource id. | | [Idempotency](/glossary/idempotency) | The property that a retried request creates no second side effect. | | [Evidence level](/glossary/evidence-level) | The rank of a piece of evidence by its independence from the action path, E0 to E5. | | [Verdict](/glossary/verdict) | The result of one verification attempt: VERIFIED, PENDING, CONTRADICTED, FAILED, or UNVERIFIABLE. | | [PENDING](/glossary/pending) | The verdict while an operation can still make progress. | | [UNVERIFIABLE](/glossary/unverifiable) | The verdict when the evidence never became sufficient. | | [CONTRADICTED](/glossary/contradicted) | The verdict when the evidence shows a different outcome than the intent. | | [False VERIFIED](/glossary/false-verified) | A VERIFIED verdict for an outcome that did not happen. The highest-severity defect. | | [Evidence receipt](/glossary/receipt) | A signed, machine-readable record of what was verified and how. | | [Service verification skill](/glossary/skill) | A signed package of contracts, lifecycles, evidence channels, and tests for one provider. | | [Conformance](/glossary/conformance) | The mandatory test matrix a skill must pass before certification. | | [Intent compilation](/glossary/intent-compilation) | The step that turns a task in natural language into a completion contract. | | [Intent fidelity](/glossary/intent-fidelity) | The agreement between what the user asked for and what the contract checks. | | [REQUIRES_REVIEW](/glossary/requires-review) | The mark on a part of a task that no contract can check. | | [Drift](/glossary/drift) | A change in a provider schema, docs, or behaviour that can change a contract. | ## Read next - [Read how Provely works](https://provely.sh/how-it-works) - [Read what a completion contract contains](https://provely.sh/contracts) --- # How does outcome verification compare with other tools? > Honest comparisons of outcome verification with observability, LLM evaluation, and testing. Each answers a different question. Provely adds the verdict. Canonical: https://provely.sh/compare Last reviewed: 2026-09-05 **Observability, evaluation, and testing each answer a different question. None decides whether an external action reached its promised outcome. Each page states where the tool fits.** | Comparison | Question | | --- | --- | | [Outcome verification against observability](/compare/verification-vs-observability) | Is outcome verification the same as observability? | | [Outcome verification against LLM evaluation](/compare/verification-vs-evaluation) | Is outcome verification the same as LLM evaluation? | | [Outcome verification against testing](/compare/verification-vs-testing) | Is outcome verification the same as testing? | ## Read next - [Read how Provely works](https://provely.sh/how-it-works) - [Read the false-completion benchmark](https://provely.sh/benchmark) --- # Who builds Provely? > Macleod Labs builds Provely, a workflow verifier for AI agents. This page names the company and the one contact address. Canonical: https://provely.sh/about Last reviewed: 2026-09-05 **Macleod Labs builds Provely. Write to [macleod@macleodlabs.ai](mailto:macleod@macleodlabs.ai) for support, for privacy questions, and for legal questions. One address reaches a person.** Macleod Labs is a software company. It builds tools that decide whether an automated action reached its promised outcome. The company website is [https://macleodlabs.ai](https://macleodlabs.ai). ## What position does the product take? An agent performs the action. A separate verifier decides whether reality satisfies the promise. The two must stay apart. A verifier that also acts is no longer independent of the action that it checks. - A successful tool call is not a completed business outcome. - An agent assertion is evidence level E0. E0 is never sufficient on its own. - When the evidence is not sufficient, the answer is UNVERIFIABLE. The runtime does not guess. - A false VERIFIED is the most serious defect this product can have. ## What does the product not do? Provely does not read prompts. It does not judge the reason for an action. It does not classify a jailbreak. It compares what a person authorised with what the provider records, and the reason for a difference does not change the answer. > Provely is not an agent framework, a model gateway, or a general observability product. Each new feature must help decide whether an external action achieved its promised outcome. ## How do I contact the company? *One address serves every subject.* | Subject | Address | | --- | --- | | Support and sales | [macleod@macleodlabs.ai](mailto:macleod@macleodlabs.ai) | | Privacy and data requests | [macleod@macleodlabs.ai](mailto:macleod@macleodlabs.ai) | | Legal and terms | [macleod@macleodlabs.ai](mailto:macleod@macleodlabs.ai) | | Security reports | [macleod@macleodlabs.ai](mailto:macleod@macleodlabs.ai) | Report a security defect to the same address. Describe the class of the problem. Do not include a working exploit. ## Read next - [Terms of service](https://provely.sh/terms) - [Privacy policy](https://provely.sh/privacy) - [How verification works](https://provely.sh/how-it-works) --- # Terms of service > The agreement between Macleod Labs and the customer who uses Provely. It covers accounts, credentials, fees, and liability. Canonical: https://provely.sh/terms Last reviewed: 2026-09-05 **These terms are the agreement between Macleod Labs and you. They take effect on 2026-09-06. You accept them when you create an account or use the service.** > Write to [macleod@macleodlabs.ai](mailto:macleod@macleodlabs.ai) with a question about these terms. A separate written agreement, when one exists, takes precedence over this page. ## 1. The service Macleod Labs provides Provely, a workflow verifier. The service reads the systems that you connect, evaluates completion contracts against that evidence, and returns a verdict and a signed receipt. The service reports a verdict. It never performs a corrective action on your behalf. Your own host decides what to do with a verdict. You keep responsibility for every action that your agents take. ## 2. Your account - You must give correct account information and keep it current. - You are responsible for every action taken with your API keys. - You must not share an API key outside your organisation. - Tell us at once when you believe a key is exposed. We rotate it. - You must be at least 18 years old, or have the authority to accept these terms for an organisation. ## 3. The credentials that you connect You give the verifier credentials for the provider systems that you want it to read. Give read-only credentials wherever the provider permits them. We store credentials encrypted, and we use them only to collect the evidence that your contracts name. > Never give the verifier a credential that can move money, send messages, or change a record. The verifier does not need one, and it will not use one. ## 4. Acceptable use You must not use the service for any of the following purposes. - To break a law, or to help another party break a law. - To read a system that you do not own or have permission to read. - To present a receipt as proof of a verdict that the runtime did not produce. - To reverse engineer the service, except where the law permits it. - To resell the service without a written agreement. ## 5. Fees The pricing page states the current plans and the free allowance. We bill in advance for a plan and in arrears for usage above the plan. Fees exclude tax. We give 30 days notice by email before a price rises. We do not refund a paid period, except where the law requires it. Cancel a plan to stop the next charge. ## 6. What each party owns | Item | Owner | | --- | --- | | The service, the software, and the compiled skills | Macleod Labs | | Your code, your data, and the evidence collected from your systems | You | | A receipt that the runtime signs for your operation | You | | Aggregate statistics that identify no customer | Macleod Labs | You give us the licence we need to run the service for you: to read the systems that you connect, to store the evidence that your contracts name, and to show it back to you. ## 7. Availability We work to keep the service available. We do not promise an uptime figure on a plan without a written service level agreement. We may change or stop a feature. We give notice by email before we remove a feature that you use. ## 8. The limits of a verdict A verdict states what the evidence showed at the time of verification. It is not a warranty about the provider, the bank, or any third party. A provider can change a record after we read it. The service is provided "as is". We exclude every warranty that the law permits us to exclude, including a warranty of merchantability or fitness for a purpose. ## 9. Liability Neither party is liable for indirect loss, loss of profit, or loss of data. Our total liability in any 12 month period is limited to the fees that you paid in that period. Nothing here excludes liability that the law does not permit us to exclude. ## 10. The end of the agreement - You may close your account at any time. - We may suspend an account that breaks section 4, and we tell you why. - We may end this agreement with 30 days notice. - You can export your receipts before the account closes. We delete your data 30 days after closure. ## 11. Changes to these terms We may change these terms. We publish the new version on this page and give 30 days notice by email for a material change. Continued use after that date accepts the new version. ## 12. Law These terms follow the law of England and Wales. The courts of England and Wales decide a dispute. Write first to [macleod@macleodlabs.ai](mailto:macleod@macleodlabs.ai); most questions end there. ## Read next - [Privacy policy](https://provely.sh/privacy) - [About Macleod Labs](https://provely.sh/about) - [Pricing](https://provely.sh/pricing) --- # Privacy policy > What personal data Provely collects, why it collects it, how long it keeps it, who it shares it with, and how to exercise your rights. Canonical: https://provely.sh/privacy Last reviewed: 2026-09-05 **Macleod Labs is the controller of the personal data described here. This policy takes effect on 2026-09-06. Write to [macleod@macleodlabs.ai](mailto:macleod@macleodlabs.ai) to exercise any right in this policy.** ## What data do we collect? *Each row states one purpose and one retention period.* | Data | Why we hold it | How long we keep it | | --- | --- | --- | | Your name, email address, and the identity provider you signed in with | To create your account and to contact you | While the account is open, then 30 days | | Your organisation name and billing details | To bill you and to meet tax law | Seven years, because tax law requires it | | API keys, stored as a hash | To authenticate your calls | Until you rotate or delete the key | | Provider credentials that you connect, stored encrypted | To read the evidence that your contracts name | Until you remove the connection | | Operations, contracts, verdicts, and receipts | To verify your workflows and to show you the result | While the account is open, then 30 days | | Raw provider responses | To explain a verdict while you investigate it | A short time to live, off by default | | Request logs and error traces, with secrets redacted | To run the service and to find defects | 30 days | | Website analytics without a cookie | To count page views and to compare page designs | 12 months, in aggregate | ## What do we not do? - We do not sell personal data. - We do not use your data to train a model. - We do not give evidence to a language model. The runtime evaluates evidence with operators. - We do not write secrets to logs or to telemetry. - We do not set an advertising cookie. ## Why are we allowed to hold it? - Contract: we need the data to give you the service that you asked for. - Legal duty: tax law requires us to keep billing records. - Legitimate interest: we keep short logs to run the service and to keep it secure. ## Who else sees the data? We use a small number of processors. Each one holds a contract that limits it to our instructions. | Processor | Purpose | Location | | --- | --- | --- | | Amazon Web Services | Hosting, storage, and backups | Ireland (eu-west-1) | | Stripe | Payment and billing | United States, with standard clauses | | Google and GitHub | Sign-in, when you choose that provider | United States, with standard clauses | | Resend | Service email | United States, with standard clauses | We give data to a public authority only when the law compels it, and we tell you unless the law forbids it. ## What are your rights? - Ask for a copy of your personal data. - Ask us to correct data that is wrong. - Ask us to delete your data. - Ask us to limit how we use it. - Ask for your data in a portable format. - Object to a use that rests on a legitimate interest. - Complain to your data protection authority. In the United Kingdom that is the Information Commissioner’s Office. Write to [macleod@macleodlabs.ai](mailto:macleod@macleodlabs.ai). We answer within 30 days. ## Cookies The public website sets no cookie for advertising and no cookie for cross-site tracking. The application sets one session cookie after you sign in. That cookie is necessary, so no consent banner appears. > The home page shows one of several designs, chosen at random. The choice is not stored in a cookie, and it identifies nobody. ## Security - We encrypt data in transit and at rest. - We store API keys as a hash with a pepper, never in plain text. - Verifier credentials are read only wherever the provider permits it. - We redact provider responses before telemetry. - We sign every receipt with Ed25519, so you can check it without trusting us. Report a security problem to [macleod@macleodlabs.ai](mailto:macleod@macleodlabs.ai). Describe the class of the problem. Do not send a working exploit. ## Changes to this policy We publish a new version on this page. We tell you by email before a material change takes effect. ## Read next - [Terms of service](https://provely.sh/terms) - [About Macleod Labs](https://provely.sh/about) - [What a receipt proves](https://provely.sh/receipts) --- # Sign in to Provely > Sign in with Google or GitHub to verify your first workflow. The free plan verifies 1,000 actions and needs no card. Canonical: https://provely.sh/signin Last reviewed: 2026-09-05 **Sign in with Google or with GitHub. Provely creates your account on the first sign-in, and the free plan verifies 1,000 actions.** By signing in you accept the [terms of service](/terms) and the [privacy policy](/privacy). Write to [macleod@macleodlabs.ai](mailto:macleod@macleodlabs.ai) with a question. ## What does Provely read? - Your name and email address, to create the account and to contact you. - The identity provider you chose, and its own id for you. That pair is your identity. - Nothing else. Provely asks for no repository access and no provider credential here. ## What does it cost to try it? Nothing. The free plan verifies 1,000 actions each month and needs no card. Read the [quick start](/docs/quick-start) for the first verdict. > Provely never asks for a credential that can move money or send a message. A verifier credential is read only, and you add it later inside the dashboard.