Aller au contenu

Feedback and fraud labels

Ce contenu n’est pas encore disponible dans votre langue.

A decision is a prediction. Weeks later you find out whether it was right: a chargeback arrives, a customer complains that money left their wallet, or an investigation clears the payment. Feedback tells SpeculaPro what really happened.

You can send:

What Values Typical source
Final status completed, failed, reversed, chargeback, cancelled Your payment system, as soon as it knows
Fraud label fraud, legitimate, unknown Chargebacks, customer complaints, your fraud team
Fraud type (with a fraud label) account_takeover, card_testing, social_engineering, sim_swap, identity_theft, first_party, mule, merchant, other Your fraud team
Step-up result true (passed) or false (failed) Your payment system, after a step_up answer
Note Free text, up to 1,000 characters Anyone

There are two ways to send it: your systems call POST /api/v1/feedback, or a person labels the decision on the Decisions page.

Labels are how you find out whether a real-time rule catches fraud or only annoys good customers.

Each real-time rule’s page on Rules shows a line like this, over the last 30 days:

A real-time rule's page, Payout soon after a SIM swap: live hits, shadow hits, alerts on Customer, action Block; and the line Decisions · 30d: 1 fired. Of 1 labelled afterwards, 1 were fraud and 0 legitimate (100% precision) A real-time rule's page, Payout soon after a SIM swap: live hits, shadow hits, alerts on Customer, action Block; and the line Decisions · 30d: 1 fired. Of 1 labelled afterwards, 1 were fraud and 0 legitimate (100% precision)
  • Fired counts the decisions in which the rule fired in its live slot.
  • Labelled afterwards counts those that someone labelled fraud or legitimate.
  • Precision is the share of labelled ones that were fraud: fraud ÷ (fraud + legitimate).

You need rules.view to see it. Until something is labelled, the line says None labelled yet.

Worked example. Over 30 days, New device and new payee fired on 400 decisions. Your fraud team labelled 50 of them: 10 fraud, 40 legitimate. Precision is 20%: four in five of the customers it stopped were genuine. Before tightening it, check what those 40 had in common, for example a segment that changes phones often, and tune the rule.

Labels and statuses also show in the decision’s What really happened box, and the Labelled tab of the Decisions page lists every labelled decision.

You need an API key with the decide or ingest:write scope. Feedback works for transactions sent through either API, so your chargeback system can use its existing ingest key.

  1. Collect the outcomes you have learned since your last call: final statuses, chargebacks, step-up results, your fraud team’s findings.

  2. Send them in one batch of up to 500, each identified by the transaction’s external_id:

    Terminal window
    curl -s https://speculapro.example.com/api/v1/feedback \
    -H "Authorization: Bearer $SPECULAPRO_DECIDE_KEY" \
    -H 'Content-Type: application/json' \
    -d '{
    "items": [
    {"external_id": "MOMO-2026-10-09-000201117", "status": "failed", "label": "fraud", "fraud_type": "sim_swap"},
    {"external_id": "CARD-AUTH-88213409", "status": "completed", "step_up_passed": true},
    {"external_id": "MOMO-2026-10-02-000187340", "status": "chargeback", "label": "fraud", "fraud_type": "account_takeover",
    "note": "Customer reported phone stolen", "reported_at": "2026-10-08T09:15:00Z"}
    ]
    }'
  3. Check each result. The answer has one result per item, in order:

    {
    "results": [
    {"external_id": "MOMO-2026-10-09-000201117", "status": "recorded"},
    {"external_id": "CARD-AUTH-88213409", "status": "recorded"},
    {"external_id": "MOMO-2026-10-02-000187340", "status": "not_found"}
    ]
    }
    status Meaning What to do
    recorded Stored Nothing
    not_found No transaction with that external_id in your workspace Check the ID. A transaction sent moments ago may not be registered yet: retry later
    rejected The item breaks a rule; errors says which Fix it. See below
  • Send at least one of status, label, step_up_passed or note. Otherwise: send at least one of status, label, step_up_passed or note.
  • fraud_type needs "label": "fraud". Otherwise: fraud_type needs label fraud.
  • reported_at is when you learned the outcome; it defaults to now.

Each call adds to what is already known: fields you leave out keep their earlier value. So your payment system can send status within seconds, and your fraud team a label weeks later, without overwriting each other.

Two exceptions: a new label replaces the earlier one together with its fraud_type (a legitimate label clears the type), and the most recent call decides who the box names as the source (your systems, or a person).

Nothing is lost when a label is replaced: every change, through the API or on screen, is written to the audit log as decision.feedback, with the feedback before and after and the API key or person who sent it.