For agent builders · versioned commitment

The refusal contract

Any market API can tell your agent what happened. This is a commitment about the harder case: what Fahali does when it cannot answer.

An autonomous system acting on financial data needs to distinguish “no risk detected” from “the measurement failed.” Those are opposite conclusions and most APIs render them identically — as a zero, an empty array, or a confident-looking default. Fahali will not do that, and this page is the guarantee you can build against.

Version 1.0Effective 20 Aug 2026Applies to REST + MCP

Four mechanisms, already shipping

This contract does not describe intended behaviour. Each clause below is enforced in production code today and covered by tests that fail if it is removed.

01 / SHAPE

Absence arrives with its cause

Agent-consumed fields are never a bare null. A value that could not be produced carries the reason it could not be produced, in the same object.

// never this
"historicalWinRate": null

// always this
"historicalWinRate": {
  "value": null,
  "reason": "insufficient_sample"
}
02 / THRESHOLD

Below threshold is withheld, not rounded

Every measured claim carries a publishable flag. A figure that has not cleared its effective-sample and lift thresholds is withheld — it is not softened, hedged, or published with a caveat.

Read the flag, never the number. A percentage present in a payload is not a percentage we stand behind unless publishable is true.

03 / REASON

A withheld value is machine-readable

Refusals use stable reason codes, not prose. Your agent branches on the code; the human-readable message is for your logs, and may change.

"highestRiskSymbol": null,
"highestRiskTiedCount": 12,
"highestRiskWithheld":
  "tied_top_score_no_separated_leader"

That example is real: when many symbols share the top score, we publish the size of the tie rather than naming whichever one the database returned first.

04 / FAILURE

Failure degrades to the prior answer, never to a new one

When a derived surface cannot parse what it was given, it leaves the previous verified statement standing rather than emitting a partial one.

The rule is fail closed: a broken pipeline produces the last thing we could prove, or nothing — never a plausible-looking value assembled from what survived.

What Fahali will never do

These are the commitments that cost us conversions, which is the only reason they are worth publishing.

  • Never substitute a plausible value for a failed measurement. A missing number is reported as missing. The most common way risk tooling misleads is that absence renders as safety.
  • Never round a sub-threshold figure up into publication. If it does not clear the gate, you get a refusal, not a smaller claim.
  • Never present a tie as a leader. When the top item is not separated from second place, we publish the count, not a name.
  • Never return a directional instruction. Fahali is read-only and has no path to capital. Outputs are observations, not advice, and must not be relayed as trade instructions.
  • Never publish a single platform-wide “accuracy” figure. It is not a meaningful quantity across horizons and instrument classes, and any single number would be selected rather than measured.

How to depend on this

Three rules that make your agent correct rather than merely working.

DoInstead ofBecause
Branch on reasonBranching on the message stringReason codes are stable and versioned; messages are not
Check publishableReading the percentageA number can be present and still be one we withhold
Treat a 403 as under-scopedTreating it as an outagePaid refusals return an upgrade object naming the plan, price and checkout URL
Preserve as_of and horizon in citationsQuoting the value aloneA risk read without its horizon is not the same claim

Versioning

A contract you cannot rely on across deploys is not a contract.

Questions, or a shape that would make this easier to build against: the developer portal · the public evidence ledger · machine-readable guide