Skip to main content

Anti-fraud

Anti-fraud is mandatory and it starts on your page. It is not a setting we switch on for you: it needs three things from your integration, and a flow that skips any of them is refused at the final step.

Read this before you build a flow, not after. It is the most common way a first integration fails, and the failure is misleading: a request whose page never loaded the script is refused with what looks like a fraud decline. Teams lose a day looking at the wrong end.

Your three obligations

1. Fetch the script from your backend, never from the browser.

GET /api/sp/v1/dcb/antifraud/script?shortCode=…&serviceId=…&ti=…&ts=…&te=…&flow=…

All six are required. flow is lp for the PIN flow on this page and he for header enrichment; it tells the provider which journey it is scoring, and the two are not interchangeable.

Your server calls us, we fetch the protection script using the platform's own anti-fraud account, and we return it for you to embed. You never hold anti-fraud credentials and never register with the provider.

danger

If your web page calls this endpoint directly, your API token is published to every visitor. This endpoint looks like a front-end concern because its output is a script. It is not.

2. Load the script on the page: once, before your other scripts.

Embed it in <head>, ahead of anything else. Load it exactly once per page. Loading it twice does not double the protection; it produces a page whose behaviour we cannot interpret.

3. Send the same ti and ts through the whole flow.

The identifiers you generate for the script call must be the ones you send on verification. They are required.

te: required here, whatever the provider's own docs say

te is the CSS selector of the element the subscriber actually clicks: your submit button, or the form containing it.

The anti-fraud provider's public documentation lists te as optional. That is true only of a different integration style, which this platform does not use. For this integration it is mandatory: it is how the interaction is observed at all.

Your page shapeWhat te should target
One page, updated in place (JavaScript swaps the view)the confirmation button: the second click, not the first
Two pages (number, then code)put the script on the code page, and target the form wrapping the input and its submit button

Encoding te: pass the raw selector, unless you are writing the URL by hand

te is a query parameter, so the # in an id selector has to arrive as %23. Who does that encoding is the part that catches people.

How you build the requestWhat to pass
An HTTP client or library (fetch, Guzzle, requests, Axios…)the raw selector: #confirm-button
A URL you assemble as a string yourself, or a tool that substitutes variables literallypre-encoded: %23confirm-button

Passing %23 to a client that encodes for you sends %2523, and the platform then receives the literal characters %23confirm-button as the selector. That matches no element on any page, so the provider has nothing to observe. Nothing errors: the script call succeeds, the page looks healthy, and verification is refused several steps later for a reason that points nowhere near this.

If you are unsure which kind your tool is, send one request and read the URL back from the requestId's log entry with the operator team - it is cheaper than inferring it.

What expires, and when

Lifetime
The protection kit48 hours
A session token6 hours

Fetch the script per page load rather than caching it. A cached script that has outlived its token produces a page that looks perfectly healthy and fails at verification.

What a refusal means

Two different failures produce two different codes, and telling them apart matters:

  • Declined: the check ran and returned a negative verdict. The interaction was assessed. Do not retry; the answer will be the same.
  • Unavailable: the check could not be completed. This is transient and retryable, and nothing was consumed by the attempt.

There is also a third case worth recognising: a transaction identifier we have no record of. That means the script step did not happen for this ti: most often the page never fetched the script, or fetched it with a different identifier. It has its own code, precisely so that it does not get mistaken for a decline.

Why this is stricter for Header Enrichment

In a PIN flow, the subscriber also proves possession of the number by typing a code they received. In header enrichment there is no second factor: one tap is the entire consent. So the anti-fraud check is not one signal among several there; it is the only one. Expect no leniency.

Testing a blocked flow

Testing support for blocked-verdict flows is available on request through the operator team. Contact them and they will arrange it for your test service: you cannot self-serve it, and it does not require you to commit anything fraudulent.

Until the anti-fraud integration is switched on for an environment, every verdict there is allow, so a flow that passes in an environment without it is not evidence that it will pass with it.