Patterns from running Fidacy on the money path. They keep your integration correct, safe, and fast as you scale from your first payment to production volume.
approveClear the payment; forward the mandate with its injected risk_data.
reviewDo not clear. Route to step-up auth or a human. Treat it as "not yet" — and remember it is also the safe-fallback for internal faults.
denyBlock, and surface a reason from rejection_reasons to the user.
Never collapse review into approve to reduce friction. It is the line between a careful system and an exploitable one.
Re-assessing the same mandate returns the original verdict (keyed by content hash), so retries are safe — you will never get two divergent decisions for one mandate. Use your own idempotency_key for request-level tracing.
audit.status: pendingNormal — the hash chain is sealed asynchronously. The entry_id is already stable; it becomes anchored shortly after.
refinement.status: pendingA reasoning pass is queued for a review-band case. If it changes the verdict, you receive an assessment.refined webhook — wire it up if you enable the reasoning layer.
Verify the Risk Payload JWS against the JWKS before trusting a forwarded mandate, and verify the x-fidacy-signature on every webhook. Both use the same public keys — fetch by kid, cache, and check.
Treat policy changes like code: draft, backtest against recent history, review what it would have decided, then activate. Keep the previous version — rollback is just re-activating it.
scopesA read-only dashboard gets assess:read; a checkout service gets assess:write. Don’t share one all-powerful key.
rotationRotate on a schedule; revoke instantly on exposure.
Each response carries per-stage timings in x-fidacy-server-timing (and the standard Server-Timing off-platform): kya, policy, risk, sign, persist, total. Track these to spot a slow dependency early.
x-fidacy-server-timing: kya;dur=1, policy;dur=2, risk;dur=1, sign;dur=2, persist;dur=3, total;dur=11
If Fidacy returns an error or times out, treat the payment as review on your side — hold, don’t clear. The engine is built to never approve under fault; your integration should mirror that.