Skip to content
Outcome Assurance
AGENT OUTCOME ASSURANCE API

The agent reported success. That is a string it wrote about itself.

Send the outcome that was asked for, the world-state before and after, and the conditions you declared. Outcome Assurance evaluates every assertion against the actual states, diffs the two worlds to find changes no postcondition accounted for, and returns one of five verdicts: including unverifiable, which is what you get when there is nothing to check.

Free tier: 500 assured runs/month Paid from $249/month No card to run the demo
Live assurance Ready

Runs the same engine the paid endpoint uses. Nothing is stored and no key is needed.

Press “Assure this run” to call the live API.
The problem

You can see what the agent said it did. You cannot see what it did.

An agent finishes, writes {"status":"success"}, and the trace shows every tool call returning 200. None of that is evidence about the world. Whether an agent was allowed to act is a separate question, decided before the fact; this one is answered afterwards, against the state.

Self-reported success is the agent grading its own work

The model that decided to act is the same model reporting that the action worked. A tool call returning 200 says the request was accepted, not that the order is refunded, the seat is provisioned or the ticket is closed.

Nobody diffs the world

Teams check the one field the outcome was about. Nothing walks the rest of the state to ask what else moved: so an agent that hit its goal and quietly rewrote a customer tier, a permission or a balance looks exactly like an agent that did the job cleanly.

“It passed” is not a diagnosis

An eval harness returns a boolean. When it is false, someone re-runs the agent by hand to find out which condition broke, what the value actually was, and whether the check could even be evaluated against the state that was captured.

What it costs

The expensive failure is the one that also succeeded.

A run that fails loudly gets fixed the same day. A run that achieves its outcome and moves something else along the way passes every check you have, and is found weeks later by a customer.

  • Side effect
    The refund worked. The account was also downgraded.

    The postcondition was about the order status, so that is what got checked. The tier change was in the same write, in a field nobody asserted on, and there is no record that anything unusual happened: only a support ticket, later, from someone who lost a feature they paid for.

  • Money
    A balance moved by an amount nobody bounded

    Reconciliation catches it at the end of the month, in aggregate, without the run that caused it. Money in a state comparison is integer minor units and a currency mismatch is decided before any amount is compared: because 1000 JPY and 1000 USD are not the same number in different clothes.

  • False green
    A typo in an assertion path that passed for six months

    order.1188.status instead of orders.1188.status addresses nothing. A harness that treats a missing path as “not changed” reports a pass, forever, for a check that was never run. Here that is unevaluable, and an unevaluable assertion is never a pass.

What it returns

Five verdicts, because “did it work” has more than two answers.

You supply the two states and the conditions. The engine evaluates them deterministically and refuses to certify anything it could not check. No model judges the outcome; the same input always produces the same output.

VerdictWhen you get itWhat to do with it
achievedEvery postcondition held, no policy was broken, and nothing changed that was not accounted for.Ship it. This is the only verdict where certified is true.
achieved_with_side_effectsEvery postcondition held: and the run also moved something nobody declared, or broke a policy.Review the findings. The goal was met; the blast radius was larger than the goal.
partially_achievedSome postconditions held and some definitely failed.Retry or escalate. The failing assertions name themselves.
not_achievedNo postcondition held.Roll back. The run did not do the thing.
unverifiableNo after-state, no postconditions, a precondition that did not hold, or checks the state cannot support.Fix the instrumentation, not the agent. Nothing was certified and nothing is claimed.

Agent run Assertions State diff Side effects Policies Verdict

  • 01

    Eleven assertion operators

    equals, not_equals, changed, unchanged, increased, decreased, within_range, matches, exists, absent, count_equals. Every result carries its own reason code plus expected and actual, so a failure is a diagnosis rather than a boolean.

  • 02

    Side-effect detection over the diff

    Both states are flattened to leaf paths and compared. Every difference that no postcondition, no expectedChanges glob and no policy accounted for is reported, classified and counted. This is the part nothing else in your stack does.

  • 03

    Severity that ranks the irreversible first

    Money moved, state destroyed and destructively named fields are critical. Identity and permission material is high. An overwrite is medium, a new value low. The heuristics are deliberately over-inclusive: a false alarm costs one ignorePaths entry, a miss costs a silent transfer.

  • 04

    Policies that outrank declarations

    forbid_change, forbid_effect and max_delta say what must not happen, whatever the outcome. A path named in expectedChanges cannot buy permission for something a policy forbids: prohibitions win, always.

  • 05

    Effects that leave no trace in the state

    An email is sent once; a capture at a PSP is not undone by rewinding your database. Report what the run did outside the state and every effect the outcome never declared comes back classified: an undeclared payment is critical, an undeclared email is high.

  • 06

    Regression against a baseline run

    Attach a prior run of the same outcome and get back what changed: which assertions stopped holding, which side effects are new, which policy violations appeared. Regression is decided on the worst signal, not the net: a run that fixed one thing and broke another has regressed.

Example output

Both postconditions passed. The verdict is still not achieved.

The refund agent did exactly what it was asked: the order is refunded and a refund id exists. It also downgraded the customer's tier and emailed them, neither of which anybody declared. Abridged output of POST /v1/runs for the run in the demo panel above.

{
  "runId": "run_7f3a91",
  "outcomeId": "refund_order_1188",
  "verdict": "achieved_with_side_effects",
  "verdictReason": "policy_violated",
  "certified": false,
  "postconditions": { "total": 2, "satisfied": 2, "failed": 0, "unevaluable": 0 },
  "sideEffects": {
    "evaluated": true,
    "changes": 4, "accounted": 3, "ignored": 0, "unaccounted": 1,
    "maxSeverity": "critical",
    "findings": [
      {
        "path": "customers.c_44.tier",
        "change": "modified",
        "before": "pro", "after": "free",
        "severity": "critical",
        "code": "forbidden_change",
        "source": "policy"
      }
    ]
  },
  "effects": {
    "total": 2, "accounted": 1, "unaccounted": 1, "maxSeverity": "high",
    "findings": [
      { "kind": "refund", "target": "psp.stripe", "accounted": true,  "code": "declared" },
      { "kind": "email",  "target": "ana@acme.test", "accounted": false, "code": "undeclared_effect" }
    ]
  },
  "policy": { "evaluated": 1, "compliant": false, "violations": [ … ] },
  "evaluatedAt": "2026-08-31T09:00:00.000Z"
}

Four changes, three accounted for

The order status and the refund id are covered by postconditions. The ledger movement is covered by an expectedChanges glob. The tier change is covered by nothing, so it is a finding: and because a policy names that path, it is critical and the run is compliant: false.

The email is not in the state at all

No diff can find it, so the run reports it and the API decides. A declared refund against the PSP is accounted for; an undeclared email to a customer is high: irreversible from the recipient's side, whatever your database says afterwards.

Nothing is stored

Every endpoint is stateless. You send both states with each request and get the report back. The API keeps no copy of your world, and the same input at the same evaluation instant returns the same bytes: so a stored report can be diffed.

This service is newly launched. We publish no uptime percentage, customer count, logo wall or certification claim until we have the operating history to support one. The verdict is arithmetic and comparison over the states you supply; it is only as complete as the state you capture.

How it works

Three calls to put a verdict behind every agent run

  • Capture both states

    Snapshot the slice of the world the outcome concerns, before the agent runs and after. The before state is required: without it there is no diff, and side-effect detection is the point.

  • Declare what success means

    Postconditions define the outcome. Preconditions define the world the run was valid from. expectedChanges declares what else you know will move; anything left over is a finding.

  • POST the run and branch on the verdict

    One run or up to 100 per call. Route achieved onward, hold achieved_with_side_effects for review, retry partially_achieved, and treat unverifiable as a bug in your instrumentation rather than in the agent.

Rules the engine never bends

Fail closed, or the verdict is worthless

  • An unevaluable assertion is never a pass. A missing path, a currency it cannot compare, a pattern against a number: each returns unevaluable with its own code, and the run is not certified.
  • A path absent from both states is a typo, not “unchanged”. Blessing it would let a mistyped assertion report green forever.
  • Money is integer minor units, and a currency mismatch is decided before any amount comparison. A fractional minor unit in the state is refused, not rounded.
  • A prohibition outranks a declaration. Naming a path in expectedChanges or ignorePaths cannot license a change a forbid_change policy covers.
  • Preconditions do not account for changes. Describing the world an agent could start from grants no permission to mutate it.
  • Output is deterministic and nothing is stored. Same run, same evaluation instant, same bytes: and findings are sorted worst-first, then by path.
Developer integration

Small surface, versioned, OpenAPI-first

Authenticate with Authorization: Bearer <key>. Every error returns a stable code and a requestId you can quote, and validation failures name the exact field in details.path.

POST/v1/keysPublic. Emails a one-time claim token to the address you give it. No key is returned on this call, proving the mailbox is what stops anyone minting a key on your account.
POST/v1/keys/claimPublic. Spends the emailed token and returns the key, shown once: 500 assured runs a month, no card.
POST/v1/runsAssure one run or up to 100. Billed one assured run per entry; an attached baseline is not billed separately.
POST/v1/demo/assurePublic. Real engine, capped at 20 assertions and 200 state values. No key required.
GET/v1/assertion-typesPublic. Every operator, verdict, reason code, severity and policy kind, with meanings.
curl -X POST https://outcomeassurance-api.com/v1/runs \
  -H "Authorization: Bearer $OUTCOME_ASSURANCE_KEY" \
  -H "content-type: application/json" \
  -d '{"run":{"runId":"run_7f3a91","outcome":{"id":"refund_order_1188"},
        "before":{"orders":{"1188":{"status":"paid","refundId":null}}},
        "after":{"orders":{"1188":{"status":"refunded","refundId":"re_9021"}}},
        "postconditions":[
          {"op":"equals","path":"orders.1188.status","value":"refunded"},
          {"op":"exists","path":"orders.1188.refundId"}]}}'
Pricing

Priced per assured run, capped so a backfill can’t surprise you

One unit is one agent run assured. A baseline attached for regression comparison is assured with the same engine and is not billed separately: charging for it would price you out of the regression testing this API exists to make routine. Every plan includes an allowance, then a per-unit overage that is hard-capped per billing period: your worst-case bill is the base price plus the cap, never more.

Developer
$249 /month
  • 10,000 assured runs included
  • $0.05 per additional assured run
  • Overage capped at $500 per period
  • Full API access, Python and TypeScript SDKs
Start with this plan
Scale
$2,499 /month
  • 250,000 assured runs included
  • $0.02 per additional assured run
  • Overage capped at $5,000 per period
  • Full API access, Python and TypeScript SDKs
Start with this plan
Enterprise
$5,000+ /month
  • 800,000 assured runs included
  • $0.01 per additional assured run
  • Overage capped at $10,000 per period
  • Full API access, Python and TypeScript SDKs
Contact sales

Free tier: 500 assured runs per month, no card. Prices in USD, billed monthly. Payment is processed by Square through our shared billing platform; card details never touch this site.

What counts as an assured run?
One run object in one call. A batch of 50 runs bills 50 units. A baseline attached to a run for regression comparison is evaluated by the same engine and billed nothing: the unit is the run you are certifying, and pricing the comparison separately would only teach you to skip it.
Is this the same thing as deciding whether the agent was allowed to act?
No, and the two are deliberately separate. Authorisation is a question about intent, answered before the action, against a mandate. This API is answered afterwards, against the world: given what the state looked like before and after, did the requested outcome actually happen, and what else moved?
Does a model judge the outcome?
No. Every assertion is a deterministic comparison over the states you supply, and the side-effect diff is structural. The same input at the same evaluation instant returns the same bytes, which is what makes a stored verdict worth keeping and a regression comparison meaningful.
What if I only have the state after the run?
The before state is required, because without it nothing can be diffed and side-effect detection cannot run at all. If you omit after instead, the verdict is unverifiable: the postconditions come back with the reason they could not be evaluated, and nothing is certified.
Won't the severity heuristics flag ordinary noise?
Sometimes, on purpose. Field-name matching for monetary, destructive and access-related fields is deliberately over-inclusive, because a false alarm costs you one ignorePaths entry and a miss files a silent transfer as “a value was modified”. Timestamps and audit fields are one glob: **.updatedAt.
Can I evaluate it before paying?
Yes. The demo at the top of this page is the real engine with no key at all (the caps are on size, never on behaviour) and the free tier gives you 500 assured runs a month against the full authenticated surface.

Stop taking the agent's word for it.

The free tier is 500 assured runs a month, no card. Create a key, post one run with both states, and the response tells you what the agent achieved: and what else it touched.

One email address, no password, no card. Prefer the terminal? The same key, in two calls:

curl -X POST https://outcomeassurance-api.com/v1/keys \
  -H "content-type: application/json" \
  -d '{"email":"you@company.com","name":"Evaluation key","source":{"source":"web","medium":"landing"}}'

# 202 Accepted. A one-time token is emailed to that address — spend it,
# and the response carries the key, shown once.

curl -X POST https://outcomeassurance-api.com/v1/keys/claim \
  -H "content-type: application/json" \
  -d '{"token":"<token from the email>"}'