One decision call, before your agent pays.
Fidren answers whether a counterparty should be paid, up to how much, and under what conditions. You call it before the payment; what happens next is yours.
This page documents the API as it exists today. Where something is not built, it says so rather than describing it in the present tense.
A decision layer, between evidence and execution. Not a replacement for either.
One layer of five.
Fidren does not ingest arbitrary third-party intelligence into the record today, and does not move your money. It turns a record into a recommended action, which is the step between the two that nothing else in a payment stack owns.
- Evidence settlement observed on chain and outcomes the parties report Upstream
- Fidren Decision API recommends an action from the record, the confidence in it, and the exposure you asked for Fidren
- A decision an action, a ceiling, confidence, reasons and evidence Fidren
- Your transaction policy decides what the answer means for this payment, alongside your own controls Yours
- Your wallet and payment rails enforce and execute. Fidren is not on this path Yours
Screening and blockchain-intelligence tools answer a different question and sit beside Fidren rather than inside it: there is no path today by which a third-party signal enters the record Fidren answers from. Run both, and combine them in your own transaction policy. Wallet and transaction-governance infrastructure sits downstream and does the enforcing. Fidren complements both; it is not a wallet, a custody provider, a payment processor or an execution engine.
No account. No API key. No card. No wallet. Copy the command, change the address, run it. There is no SDK to install — the integration is one HTTP call.
Your first decision, in one command.
curl -s -X POST https://api.fidren.net/v1/decision \
-H 'content-type: application/json' \
-d '{
"address": "0xf1d0000000000000000000000000000000000001",
"chain": "base",
"amount_cents": 5000,
"currency": "USD"
}'
That address is a documentation example with no history, so the
answer is an honest REVIEW: Fidren says it
does not know this counterparty rather than guessing. Change the
address to one you care about and run it again.
{
"decision_id": "dec_a3b2fb82ab9e56577e3e8e23a37826e2",
"decision": "REVIEW",
"trust_score": 50,
"exposure_level": 2,
"confidence": "LOW",
"recommended_limit_cents": 10000,
"requested_amount_cents": 5000,
"amount_status": "WITHIN_SUPPORTED_EXPOSURE",
"payment_action": "REVIEW",
"authorized_limit_cents": 0,
"currency": "USD",
"reasons": [
"Insufficient observations to assess this counterparty; treat as unknown, not as adverse"
],
"reason_codes": [
{ "code": "INSUFFICIENT_OBSERVATIONS" }
],
"evidence": [
{ "code": "NO_HISTORY", "detail": "Insufficient observations to establish a track record", "value": 0 },
{ "code": "NEW_ADDRESS", "detail": "Address first observed 0 day(s) ago", "value": 0 }
],
"evaluated_at": "2026-09-17T17:44:20.072Z",
"disputed": false,
"notification": "UNREACHABLE",
"scoring_model_version": "score-v1.1.0",
"decision_policy_version": "policy-v1.7.0"
}
Your decision_id and
evaluated_at will differ. Everything else
is the shape you receive.
What each field means
decision- What to do about this counterparty. One of five actions, not a score for you to interpret.
trust_score·confidence- How the record reads, and how much record there is. A low confidence score is not a bad counterparty — it is a thin one.
recommended_limit_cents- The exposure the evidence supports, independent of what you asked for.
amount_status·payment_action- These answer your amount, not the counterparty. The same party can be worth paying $50 and not worth paying $50,000, and these two fields are where that difference appears.
reasons·evidence- Why, in terms you can quote to whoever asks. Evidence carries codes and values, not prose alone.
evaluated_at- When the decision was made. Not the timestamp of the newest observation behind it.
scoring_model_version·decision_policy_version- Which model and which policy produced this answer, so an old decision stays re-derivable.
The counterparty assessment and the payment decision are different answers to different questions.
Same counterparty. Same evidence. Different exposure.
Same counterparty. Same evidence. Different exposure. Different payment decision. The trust score and the confidence are identical in both calls — only the amount moved.
A commercial allowance, reported on every response.
100 free decisions per day, per IP.
The allowance is counted against the network origin Fidren
observes for your request, and resets at
00:00 UTC. That origin comes from the
connection itself, not from a header you can set — so it cannot be
reset by changing one. Callers sharing one outbound IP, such as a
team behind a single gateway, share one allowance. There is no
signup: the first call is the first step, rather than a signup or a
conversation with us.
What does not spend an allowance
- A malformed request. A 400 costs you nothing.
- A failure on our side. If Fidren cannot serve a decision, you are not charged an allowance for it.
- A request the rate limiter refused — see below.
An allowance is only spent when a decision is actually produced and delivered.
A rate limit is not the end of your free tier.
They protect different things and answer with different codes.
You can receive a 429 with your whole
daily allowance still available. It means the burst was too fast,
not that the free tier ran out.
When the free allowance runs out.
The next valid decision returns 402 Payment
Required with the terms. Pay $0.01 USDC on Base, retry with
the signature, and the decision comes back. No account.
Fidren-Payment-Mode: x402
is a Fidren access preference, not part of the x402 standard: it
asks to be billed immediately instead of spending the free
allowance.
One key, two accepted headers.
Both are accepted because agent frameworks differ in which
headers they can set. Keys are 32 random bytes, base64url-encoded,
prefixed fdrn_. The plaintext is generated
server-side and shown once at creation; the database stores only a
SHA-256 digest, so a leaked database yields no usable credential. A
missing, malformed or unrecognised key all return the same
401 with the same message, so error text
cannot be used to enumerate valid keys.
If you send a key, that is the path you get. A valid one is
served as Enterprise and spends no free allowance. An invalid one
is 401 and stops there — it never falls
back to the free tier and never falls back to being charged.
A caller with a mistyped or expired key is exactly the one who
must not be quietly billed, because they never asked to pay.
No rotation workflow — revoke and create. No expiry. No scopes and no per-key permissions. No IP restrictions. No separate test and live keys, and no sandbox: the key you are issued talks to the real service. No self-service creation. Plan your integration around a single long-lived credential you keep out of source control.
Three required fields, two optional.
The request.
addressrequired- The counterparty you would be paying. Any casing.
chainrequired- base or polygon. See the coverage note below — they are not equally served.
amount_centsrequired- The requested exposure, in USD-equivalent minor units. Integer, zero or more.
currencyoptional- USD, USDC or USDT. Defaults to USD. Echoed back and recorded; stablecoins are read 1:1 with USD.
service_identifieroptional- A caller-side label for the service being paid. Yours, not interpreted.
The response.
All 17 fields below are present on every successful call.
dec_ followed by 32 hex characters. Store it beside your own payment record: it is how this answer is named in a later dispute. Opaque; do not parse it or infer anything from its ordering.amount_cents you sent, echoed back — the amount this decision was asked about.currency you sent, or USD if you sent none, echoed back. Recorded, not interpreted: it does not change the answer.requested_amount_cents sits against the exposure the record supports. NO_SUPPORTED_EXPOSURE means the record supports none at all, so a smaller request would not help.decision, which speaks about the counterparty. DO_NOT_PAY_AS_REQUESTED withholds this payment at this size; it says nothing against the recipient, and a smaller request may be supported. Treat a value you do not recognise as unhandled and fail closed.decision, not on a threshold of your own over this number.code is from a fixed set; value is an observation, never a weight.The per-dimension scoring breakdown is not in the response and is not published anywhere. Naming which lever moves a score would turn a risk signal into a checklist for gaming it.
Fidren returns the action. You enforce it — there is no path by which Fidren does.
What to do with each answer.
- ALLOW
Proceed with the payment you intended.
recommended_limit_centscomes back and is not below theamount_centsyou sent.- ALLOW_WITH_LIMIT
Treat
recommended_limit_centsas the ceiling for this decision, whatever produced it. Cap the payment there, or change your request and call again — a smalleramount_centswill not necessarily change the action.- ALLOW_WITH_ESCROW
Route settlement through an escrow you choose and control, still within
recommended_limit_cents. Fidren recommends the condition; it does not provide, operate or execute the escrow.- REVIEW
Do not treat REVIEW as a transient API error or put it in an automatic retry loop. Read
reasonsandevidenceand route the transaction for review.- BLOCK
Decline the payment on these terms. Your infrastructure does the declining; Fidren blocks nothing.
recommended_limit_centsstill comes back and is not permission.
This is handling. What the five actions mean, and how confidence differs from risk, is on Product. Treat a Fidren answer as one input to your transaction policy rather than as the only control.
The one place the contract is wider than the service.
Base is indexed. Polygon is not.
chain validates against
base and
polygon, but only Base is observed today —
nothing indexes Polygon. A Polygon request is accepted and answered
from an empty record, which will read as an unknown counterparty
whatever that address has actually done. That is a materially
different thing from support, so plan for Base.
Fidren is not chain-agnostic and this page will not describe it that way while one chain is served. When another lands, it will be named here.
One shape, whatever went wrong.
Every failure returns the same envelope.
The statuses below are the ones the contract documents. An
unhandled fault returns the same shape with a
500, which the contract does not yet
declare per route.
{
"error": {
"code": "VALIDATION_ERROR",
"message": "…",
"details": [{ "field": "amount_cents", "message": "…" }]
},
"request_id": "…"
}
details is present only when there is
something field-level to report.
400VALIDATION_ERROR- The body failed validation.
detailscarries a { field, message } per problem. 401UNAUTHORIZED- A presented key that is missing its value, malformed, or not recognised — all three answer identically, so error text cannot be used to enumerate keys. An anonymous caller whose allowance is spent is not refused: they receive a
402with the terms. Sending no credential at all while you still have free allowance returns 200, not 401. 402PAYMENT_REQUIRED- Payment is required for this call: either your free allowance is spent, or you sent
Fidren-Payment-Mode: x402to skip it. ThePAYMENT-REQUIREDheader carries the terms —exactscheme, USDC on Base, $0.01, valid for 300 seconds. Pay and retry the same request withPAYMENT-SIGNATUREto receive the decision. An invalid key is never charged: it is 401 and stops there. 404NOT_FOUND- No such resource. Not returned by the decision endpoint.
409CONFLICT- The report cannot be appended as submitted: an invalid lifecycle transition, a side already reported by a different address, or a chain that moved during the write. Only the last is worth retrying.
429RATE_LIMITED- Over the per-minute allowance.
503SERVICE_UNAVAILABLE- A dependency is unreachable. Safe to retry.
A per-minute allowance, reported on every response.
The bucket is chosen from a credential Fidren issued, never from the one in the request: a key the service does not recognise buys nothing and falls back to an allowance keyed on your network address. Authenticated callers draw a larger per-minute allowance than anonymous ones. The budget belongs to your organisation, not to an individual key: issuing a second key splits the same allowance rather than adding another one. Read the headers rather than hard-coding a number — the allowance is a deployment setting, not a published plan and not a per-key negotiation.
Over the limit you get 429 with the
same error envelope as every other failure, and a
Retry-After in whole seconds. The window is
a fixed minute, so that value is the time left in the current one:
wait it out and retry.
The counter is held in memory, per process, which is correct only because Fidren runs exactly one API instance — an invariant the service now enforces at start-up rather than merely documenting. Restarting it empties the counters, so a restart is worth at most one extra window to one caller. Restarting does not restore free decisions: the daily allowance is persisted in Postgres, so it survives restarts, deploys and any number of instances. Rate limiting is not billing — the per-minute limiter protects infrastructure, the daily allowance is a commercial quantity, and they are counted in different places for that reason.
The distinction that causes integration bugs.
A request ID is not a decision ID.
Every response carries
x-request-id, and every error body repeats
it as request_id. Supply your own on the
request header and it is honoured when it matches a conservative
pattern; anything else is replaced with a generated value rather
than sanitised, because a header is caller-controlled and log files
are read by tools that interpret what they find.
A request ID identifies one HTTP call, for support and
correlation, and it is what a failed call gives you. A
decision ID — decision_id, returned in
the body of every successful decision — is the durable name of
the decision itself. There is still no endpoint that reads a
decision back over the API, so store the response when you
receive it; keep the decision ID with it, and the record can be
named unambiguously later.
Not required to integrate. It is what makes the next answer better.
Telling Fidren how it went.
After an operation concludes, either side may report the outcome
to POST /v1/receipts. Each side keeps its
own hash chain and the server computes the links, so a reporter
cannot reorder or edit its own account afterwards. Three levels are
worth keeping apart:
- Recorded
- Name a side and an address in the request body. It is stored, attributed to your API key — no other endpoint or parameter is involved.
- Signed
- Optionally, the report carries a
personal_signsignature from the reporting address. Fetch the statement fromPOST /v1/receipts/signing-message, sign it, resubmit. A signature is verified and stored only if it verifies. Only a signature shows the reporter controls the address it names. - Corroborated
- Automatic once both sides have separately called this endpoint and their signed accounts agree — nothing further to call.
A reported outcome is never treated as verified truth — the chain establishes integrity and ordering against the reporter, not that the account is accurate. Separately signed reports can still come from parties under common control. Why that limit exists, and what it does and does not prove, is on Security.
You can call it without acting on it.
A practical first step is to call Fidren alongside your existing flow, log the answers and compare them, without gating any payment on them. Nothing is switched on at Fidren's end to do that — there is no mode, no flag and no parameter, because Fidren never had the ability to act in the first place. What changes is only whether your code honours the answer.
Shadow Mode describes the posture. Security boundaries, the non-custodial architecture and what is redacted from logs are on Security.
Optional. The free tier needs none of this.
Bring a system that is about to pay someone.
Free access requires no account and no API key. Enterprise credentials are provisioned per partner, for organisations that need higher volume or a commercial integration — not as a step on the way to trying Fidren.
The integration conversation is a short one when there is a real flow to point at. If you have one, we would like to hear about it.
