Account takeover
A cardholder disputes a transaction. Was the account taken over first, or was it the holder? Ward reads the login and account-change logs before the transaction and answers with a likelihood, the evidence, a timeline and a dispute view.
Type: ato · Endpoint: POST /api/v1/ato/review
Request
curl https://api.mandatelabs.ai/api/v1/decide \
-H "X-API-Key: $WARD_API_KEY" -H "Content-Type: application/json" \
-d '{"type": "ato", "input": {
"disputed": {"occurred_at": "2026-10-30T02:14:00Z", "amount": 1200, "merchant": "GIFTCARDS4U", "device_id": "dv_new_91", "country": "ROU", "known_devices": ["dv_iphone_12"]},
"logs": [
{"event_type": "sim_swap", "occurred_at": "2026-10-29T21:02:00Z"},
{"event_type": "password_reset", "occurred_at": "2026-10-29T21:40:00Z", "device_id": "dv_new_91", "country": "ROU"},
{"event_type": "new_device_login", "occurred_at": "2026-10-30T02:05:00Z", "device_id": "dv_new_91", "ip_address": "185.220.101.4"}
]}}'
d = client.decide("ato", {"disputed": {"occurred_at": "2026-10-30T02:14:00Z", "amount": 1200, "device_id": "dv_new_91"},
"logs": [{"event_type": "sim_swap", "occurred_at": "2026-10-29T21:02:00Z"}]})
const d = await client.decide("ato", { disputed: { occurred_at: "2026-10-30T02:14:00Z", amount: 1200, device_id: "dv_new_91" },
logs: [{ event_type: "sim_swap", occurred_at: "2026-10-29T21:02:00Z" }] });
Input
| Field | Description |
|---|---|
disputed (required) |
occurred_at, and optional amount, merchant, device_id, country, known_devices |
logs[] |
Up to 90 days before: event_type, occurred_at, device_id, ip_address, country |
cardholder_ref |
Also read the events already sent to POST /api/v1/assess/events |
prior_undisputed_with_merchant |
Earlier purchases at the merchant that were not disputed |
Event types: login_success, failed_login, new_device_login, password_reset, credential_change, contact_change, mfa_change, sim_swap, otp_to_new_number, payee_added, wallet_provisioned, card_replacement, session. Device ids are hashed per client before comparison; nothing is stored by the endpoint.
What it weighs
| Points to a takeover | Weight |
|---|---|
| SIM swap within 72 h | 0.55 |
| Code sent to a newly added number within 24 h | 0.45 |
| Contact or two-factor change within 7 days | 0.35 |
| Password reset or credential change within 72 h | 0.30 |
| New-device login within 24 h; disputed transaction from that device | 0.30; +0.25 |
| New payee or wallet token within 24 h | 0.30 |
| 5+ failed logins in 24 h | 0.25 |
| Points to the holder in control | Weight |
|---|---|
| Disputed transaction from a long-used device | 0.30–0.45 |
| Earlier undisputed purchases at the merchant | 0.30 |
| No account change in 30 days | 0.25 |
likelihood = takeover × (1 − 0.5 × holder), each a noisy-OR.
Result and decision
likelihood, evidence, timeline (relative to the transaction), dispute_view (third-party fraud vs first-party misuse, with the usual scheme categories such as Visa 10.4 and Mastercard 4837), needs and typologies.
| Likelihood | Decision | Meaning |
|---|---|---|
| ≥ 0.60 | DECLINE |
Takeover likely: secure the account, accept the fraud claim |
| ≥ 0.30 | STEP_UP |
Possible takeover: review |
| holder evidence ≥ 0.50 | STEP_UP |
First-party indicators: review before accepting a fraud claim |
| otherwise | APPROVE |
No takeover evidence |