Get started

Your agent says it’s done. DidWork checks.

Independent verification for agent work. Give your agents clear gates, catch incomplete work, and only continue when the job is actually done.

Stop self-verification

The worker doesn’t determine whether its own work succeeded.

Catch incomplete work

Verify the requested outcome, not merely execution.

Automate supervision

Stop manually checking everything your agents do.

Unlock autonomy

Safely chain actions and agents behind verified gates.

Try it from your terminal — no key, no signup, one real verdict. Point it at any URL you own:

curl -s https://api.didwork.sh/v1/verify \
  -H 'content-type: application/json' \
  -d '{"type":"http.ok","expected":{"url":"https://your.app/health"}}'

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

Receipts, not vibes

Real failure modes DidWork catches — each one 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

The unit is a verification performed. Free while you find out whether it works; Pro once something depends on the answer.

Free

$0 forever

No card, every month

  • 1,500 verifications/month
  • All 38 claim types
  • MCP server, SDKs, and API
  • One watch, hourly
  • 7 days of evidence
Get started

Enterprise

Custom

For verification at volume

  • Committed volume and SLAs
  • Private adapters
  • Longer evidence retention
  • Security review support
Talk to us

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.

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 — 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 1,500/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 Free, a year on Pro, counted from when the verification ran. Past that the record is deleted permanently — so on Free, 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.