AbuseZero

Outcomes

What happened after AbuseZero allowed a claim, and how that history protects every claim that follows.

An outcome records what happened after AbuseZero allowed a claim: did the user actually receive the benefit? Outcomes are the claim history that every later evaluation is checked against.

Why it matters

An allowed claim isn't always a delivered benefit. A card can fail after the trial starts, or you may refund a purchase and take the credits back. Outcomes keep AbuseZero's history in step with what really happened. A user whose claim fell through can try again, and a benefit you actually delivered keeps counting.

Key capabilities

  • Recorded outcomes. Every granted outcome becomes history that later evaluations check, across every identifier the claim carried.
  • Two tracking models. AbuseZero can treat every allowed claim as delivered, or wait for your app to confirm delivery.
  • Missing outcome behavior. When your app is expected to confirm delivery but doesn't, AbuseZero settles the outcome by the rule you chose for that benefit.
  • Outcome corrections. Only valid changes are accepted, such as granted to reversed. Conflicting reports are refused with OUTCOME_CONFLICT, and every change is recorded in your audit log.
  • Outcome conflicts. Under release_eligibility, when a delivery is confirmed after its deadline and other claims have since used the same identifiers, the response lists those overlapping outcomes in conflicts so you can review them.
Evaluate the claimallowReport the outcomeThe outcome becomes historyfor future evaluationsYour serverAbuseZero
Evaluate the claimallowReport the outcomeThe outcome becomes historyfor future evaluationsYour serverAbuseZero

Tracking models

Each benefit chooses one in config.outcome_tracking.

ModelHow it worksChoose it when
assume_granted (default)Every allowed claim counts as delivered straight away, with the state assumed_granted. You report only corrections.Your app grants the benefit as soon as AbuseZero allows it.
report_outcomeAn allowed claim starts as awaiting_outcome, with a due_at time returned in the evaluation. Your app reports granted or not_granted before then.Delivery can still fail after the evaluation, for example at a payment step.

When a report is due but doesn't arrive, the outcome becomes outcome_unknown. The benefit's config.missing_outcome_behavior then decides whether it counts:

  • hold_eligibility (default): the claim still counts as an earlier claim.
  • release_eligibility: the claim doesn't count, and the user can claim again.

Outcome states

StateMeaningCounts as an earlier claim
assumed_grantedAllowed under assume_granted.Yes
awaiting_outcomeAllowed under report_outcome, waiting for your report.Yes
grantedYour app confirmed the user received the benefit.Yes
not_grantedYour app reported that the user didn't receive it.No
reversedThe benefit was delivered, then taken back.Yes
outcome_unknownThe report window closed without a report.Depends on missing_outcome_behavior

Reporting an outcome

Report against the evaluation that allowed the claim, with POST /v1/evaluations/{id}/outcome:

Request
{ "outcome": "not_granted", "reason": "Card declined at checkout", "external_outcome_id": "order_20481" }
Response
{
  "object": "outcome_report",
  "evaluation": "eval_9a41c7e2-5b3d-4e8f-a216-0c7d3b9e5f81",
  "state": "not_granted",
  "conflicts": []
}
FieldMeaning
outcomegranted, not_granted or reversed.
reason3 to 500 characters. Required for not_granted and reversed.
external_outcome_idOptional. Your own ID for this outcome, unique within your workspace.
You reportAccepted from
grantedawaiting_outcome, outcome_unknown, assumed_granted
not_grantedawaiting_outcome, outcome_unknown, assumed_granted
reversedgranted, assumed_granted

Reporting the state an outcome already has is safe and changes nothing. Every report needs an Idempotency-Key, so a retry never applies twice.

Outcomes and eligibility

claim_id ties evaluations and outcomes to one claim in your system:

  • Already allowed: evaluating the same claim again returns allow with the reason previously_authorized. It doesn't count a second claim.
  • Reported not_granted: the claim is evaluated afresh.
  • Report overdue: under report_outcome, a claim whose report window closed without a report returns OUTCOME_CONFLICT when evaluated again. Report its outcome first.

Response data

GET /v1/outcomes lists outcomes, and each one looks like this:

{
  "object": "outcome",
  "id": "out_6e3b9a12-4c7d-4f58-b0a9-1d2e8c5f7a36",
  "evaluation": "eval_9a41c7e2-5b3d-4e8f-a216-0c7d3b9e5f81",
  "state": "granted",
  "source": "evaluation",
  "occurred_at": "2026-10-28T16:02:11.000Z",
  "due_at": "2026-10-28T16:12:11.000Z"
}

source is evaluation for outcomes created by an evaluation, and import for outcomes you imported.

Programmatic access

InterfaceUse
AbuseZero REST APIPOST /v1/evaluations/{id}/outcome, GET /v1/outcomes, GET /v1/outcomes/{id}, and POST /v1/imports for outcome history
AbuseZero Node.js SDKoutcome(), importOutcomes(), outcomes(), getOutcome()
AbuseZero CLIabusezero outcomes report, list, get
AbuseZero MCP serverabusezero_report_outcome, abusezero_list_outcomes, abusezero_get_outcome
DashboardEvaluations, and Developers → Data import for outcome history

Next steps

How is this guide?

Last updated on

On this page