Start free

Your AI agent says "done." Don't believe it.

Your agent can finish a task, report success, and still be wrong. DidWork checks the result independently before your workflow moves on.

Catches
wrong results

$39.99 instead of $49.99? We'll catch it.

Stops
incomplete work

No half-done tasks get through.

Blocks
fake success

No more "it worked" when it didn't.

Lets real
work continue

Verified results move forward.

Stripe Without DidWork

Agent reported

“The customer has been refunded $49.99.”

Stripe recorded

$39.99

Refund succeeded. Amount didn’t match.

The agent said done.
The customer was still owed $10.

Works with your stack

First-party adapters for the tools your software already uses.

Read-only connections, plus any public URL, no connection at all.

Stripe GitHub GitLab Linear
Jira Sentry Slack Resend
SINCERITY ISN’T EVIDENCE

Made for agents that finish the job

An agent that gets it wrong isn’t lying. It believes its tools. DidWork closes the loop with independent evidence, so “done” means done.

const v = await did.verify({
  type: "stripe.refund",
  expected: {
    payment: "pi_123",
    amount: 4999
  }
});
State the claim
"evidence": [{
  "source": "stripe",
  "observation":
    "1 refund(s) found",
  "data": [{ "amount": 3999,
    "status": "succeeded" }]
}]
DidWork gathers evidence
{ "status": "failed",
  "reason": "AMOUNT_MISMATCH" }

if (v.status !== "verified")
  escalate();
// unknown also stops the line
Gate on the verdict

Verification that runs the way production runs

Give your agent the tool.

One command, any MCP host. Then one line of instructions: verify before you report success.
claude mcp add didwork \
  -e DIDWORK_API_KEY=dk_… \
  -- npx -y @didwork/mcp

Connect once, read-only.

Verifications run against your accounts. DidWork never needs the power to cause outcomes, only to prove them.

Watch what must stay true.

Cancelled users stay locked out. Checkout keeps working. Signed webhooks, retried for hours.
did.watch({
  type: "http.ok",
  expected: { url, status: 401 },
  every: "10m"
})

UNKNOWN is an answer.

Provider down, record invisible, outcome undecidable. DidWork refuses to guess. When it says VERIFIED, that has to be true.
VERIFIED FAILED UNKNOWN

Every check on the record.

Claim, evidence, and verdict stored separately: an audit trail for what your software actually did.
GET /v1/verifications
GET /v1/verifications/:id

Know what a tool can do before the agent calls it.

A tool’s description is intent, not proof. DidWork reads the implementation and reports what it can actually affect, with the line of code as evidence, and says UNKNOWN when it can’t tell.
$ npx @didwork/inspect inspect

refund_customer      HIGH      HIGH
  financial.refund        stripe.refunds.create
  communication.external  resend.emails.send
update_customer      MODERATE  DECLARATION MISMATCH
admin_action         UNKNOWN   INSUFFICIENT EVIDENCE

Capabilities on the receipt.

Pass the tools that did the work. The receipt then answers what was requested, what those tools could affect, and whether it actually happened, kept apart from the evidence and never an input to the verdict.
did.verify({
  type: "stripe.refund",
  expected: { payment, amount },
  tools: [refundCustomer]
})

Receipts, not vibes

Real failure modes DidWork catches. Each one was reported as a success by the software that caused it.

See every claim type

“Refund processed.”

reason: AMOUNT_MISMATCH
expected: 4999
observed: 3999
stripe.refund

“PR merged, shipping now.”

reason: PR_CLOSED_NOT_MERGED
state: closed
merged: false
github.pr_merged

“I’ve resolved the bug.”

reason: ISSUE_REGRESSED
status: unresolved
substatus: regressed
sentry.issue_resolved

“Confirmation email sent.”

reason: BOUNCED
last_event: bounced
email.delivered

“Ticket closed out.”

reason: ISSUE_CANCELED
state: Canceled
linear.issue_completed

“Subscription upgraded.”

reason: PRICE_MISMATCH
expected: price_enterprise
observed: [price_pro]
stripe.subscription_active

Pricing

Start with 250 checks a month. Upgrade for more checks, frequent monitoring, and failure alerts.

Hobbyist

$0 forever

For trying verification on your own projects.

  • 250 checks/month; stops at the limit
  • Monitor one outcome every hour
  • Keep verification evidence for 7 days
  • One API key
Start free

FAQ

Verification

What happens when DidWork can’t tell?

You get UNKNOWN, on purpose. Provider unreachable, record not visible, outcome not yet decidable. DidWork refuses to guess. Treat UNKNOWN as “do not proceed yet.” False verification is the failure mode we optimize against hardest.

How do agents actually use it?

Add the MCP server with one command, then one line in the agent’s instructions: after any consequential action, call did_verify before reporting success, and proceed only on verified. SDKs and the raw API do the same job for non-agent code.

Can DidWork tell me what my agent’s tools actually do?

Yes. That’s Capability Trust. npx @didwork/inspect inspect reads the MCP tool handlers in a TypeScript project and reports each tool’s evidenced capabilities (financial.refund, communication.external, data.delete, …) with file:line evidence, a risk level, a separate confidence level, and a DECLARATION MISMATCH when the code exceeds what the tool declares. It runs locally and uploads nothing. Agents get the same answer from the did_inspect_tool MCP tool before they call something consequential. UNKNOWN means “not shown to be safe,” never “low risk.”

What if a provider I need isn’t supported?

http.ok verifies any public URL with no connection at all, your own endpoints included. For first-party adapters, tell us at hello@didwork.sh; Bitbucket, Azure DevOps, and Teams are next.

Access & security

Does DidWork need write access to my accounts?

Never. Adapters read authoritative state: a restricted Stripe key, a fine-grained GitHub token, a read-scoped Linear key. DidWork proves outcomes; it never needs the power to cause them.

How are my credentials stored?

Encrypted at rest with AES-256-GCM, shown only as a last-4 hint after entry, and validated against the provider before we store them. API keys themselves are hashed, so we can’t read them back either.

Billing

What counts as one verification?

One claim checked once. A did.verify() call and one run of a did.watch() cost the same. Requests refused at the free-tier cap are never counted or billed.

What happens at the free limit?

Without a payment method, requests past 250/month return 402 and the watch pauses. No verification is deleted for this reason, and everything resumes the moment billing is set up.

How long is evidence kept?

7 days on Hobbyist, a year on Pro, counted from when the verification ran. Past that the record is deleted permanently, so on Hobbyist, something verified today can’t be produced as proof three weeks from now. Capture verifications with a webhook if you need them to outlive the window.

What does Pro actually add?

Not the answer: every claim type, verdict, and piece of evidence is identical on both plans. Pro lifts what you need once something depends on that answer: unlimited watches down to 5 minutes, a year of evidence, email alerts when a watch turns FAILED, and separate keys per environment.