Warddocs
Capabilities

Payment

One call for every payment: Ward works out who initiated it (cardholder, merchant, account holder or AI agent), routes it to the right engine, and returns a fraud probability and a decision under your cut-offs.

Type: payment · Endpoint: POST /api/v1/assess · Real-time (32K tokens per call)

Request

curl https://api.mandatelabs.ai/api/v1/decide \
  -H "X-API-Key: $WARD_API_KEY" -H "Content-Type: application/json" \
  -d '{"type": "payment", "input": {
        "amount": 249.90, "currency": "USD", "mcc": "5732", "merchant_name": "BESTTECH ONLINE", "country": "USA",
        "initiator": "cardholder",
        "card": {"presence": "card_not_present", "three_ds_result": "Y", "ip_country": "NGA", "device_id": "dv_7f1c"},
        "cardholder": {"profile": {"avg_ticket": 60, "home_country": "USA", "account_opened_at": "2023-04-02"}, "device_known": false},
        "external_ref": "auth_88231"}}'
d = client.decide("payment", {
    "amount": 249.90, "currency": "USD", "mcc": "5732", "merchant_name": "BESTTECH ONLINE", "country": "USA",
    "initiator": "cardholder", "card": {"presence": "card_not_present", "ip_country": "NGA"},
    "cardholder": {"profile": {"avg_ticket": 60, "home_country": "USA"}, "device_known": False},
    "external_ref": "auth_88231"})
const d = await client.decide("payment", {
  amount: 249.9, currency: "USD", mcc: "5732", merchant_name: "BESTTECH ONLINE", country: "USA",
  initiator: "cardholder", card: { presence: "card_not_present", ip_country: "NGA" },
  cardholder: { profile: { avg_ticket: 60, home_country: "USA" }, device_known: false },
  external_ref: "auth_88231" });

Input

Field Required Description
amount yes Transaction amount (> 0)
currency ISO 4217, default USD
rail CARD (default), A2A, WALLET, CRYPTO
initiator cardholder, merchant, accountholder, agent; inferred when omitted
mcc, merchant_id, merchant_name, country Merchant context (country ISO alpha-3)
card Card data elements: presence, pos_entry_mode, eci, three_ds_result, avs_result, cvv_result, bin, stored_credential, device_id, ip_address, ip_country, ip_proxy, billing_country, shipping_matches_billing, account_change_at, …
cardholder From your records: profile (home_country, avg_ticket, account_opened_at, kyc_level, …), recent transactions, device_known, events. Makes the first call as good as the hundredth
agent_id / agent_did, intent_context, runtime_evidence agent payments The agent, its declared intent and what it did before asking
a2a, crypto for those rails Bank-transfer or on-chain context
external_ref, idempotency_key, dry_run Your reference; dedupe; check only (records nothing)

How the initiator is decided

A declared initiator wins unless hard evidence contradicts it (a declared cardholder payment carrying an agent id and intent). Conflicts or no evidence give STEP_UP with the reason: nothing is guessed. Agent payments go through the agent engine (intent_context required); cardholder and merchant payments through the card analyzer; rail: "A2A" through the bank-transfer analyzer.

Result

Field Meaning
initiator, pipeline Who initiated and which engine decided, with how it was decided (declared / inferred, evidence, conflicts)
assessment.fraud_probability Fraud vs genuine (sums to 1 with legit_probability)
assessment.score_kind calibrated, heuristic, engine or unavailable
assessment.evidence_tier, advisory Claim ladder: STRUCTURE_ONLY → DISCRIMINATION → CALIBRATION
assessment.vectors Share of the evidence pointing at each typology
assessment.thresholds The cut-offs applied and their source (client or platform)
signals, typologies, notes What fired and why

Decision: STEP_UP at fraud_probability ≥ 0.40, DECLINE ≥ 0.80 by default; set your own with PUT /api/v1/thresholds (assess_step_up_at, assess_decline_at). No score means STEP_UP.

Calibration

POST /api/v1/assess/calibrate fits the probability to your own labelled card outcomes (at least 200 labels with 30 of each class), never pooled with other clients. Report outcomes with POST /api/v1/assess/{assessment_id}/outcome or decision feedback.