Skip to content

Backend

Request the Javascript

To add the javascript protection to your page your backend must request it from FraudStop each time a user requests the page. The jsstring field must be added to the page so that it can collect data about the users device, see here for further instructions. To fetch a javascript string send a request to https://antifraud.empello.net/api/v2/js/fetch/, with the following fields:

Field Value Required
api_key API Key given to you by your account manager Required
merchant_name Merchant name exactly as presented on the dashboard Required
service_name Service name exactly as presented in the dashboard Required
country ISO 2 letter country code (eg GB, FR, CL) Required
carrier MCC-MNC Code separated by a hyphen (see here) Required
button_selector CSS selector referring to the subscribe button Required
record Boolean, record this journey using CertifEYE Optional
use_fraudstop Boolean, set to true (1) if you wish to use FraudStop with this transaction Required if you are using CertifEye
msisdn MSISDN or the encrypted MSISDN of the user to be subscribed Optional
price_point Use price point strings provided by your account manager Optional
test Boolean, set this field to true (1) if this a test transaction. This prevents the transaction from being counted on the dashboard and disables certain blocks Optional (defaults to false)
external_uuid Allows you to pass your unique user ID or transaction ID for querying later Optional
session_id Used for a multi page CertifEye implementation, all pages recorded must have the same session_id Required if you are using multi page CertifEye
param1, param2 ... param10 Allows you to store up to 10 additional parameters against this transaction, for example traffic source or campaign ID Optional

Warning

Please do not use unique identifiers (for example session ID or unique user ID) in the additional parameters. Instead use the external_uuid field to submit unique identifiers.

The API will respond with:

Field Value Required
status HTTP status eg 200 for a success Required
success Boolean value, if 0 then an error has occurred Required
message Success or error message output Required
token Token code of the javascript Required if success is true
jsstring The javascript snippet that should be added to your page Required if success is true

See the following example cURL request and JSON response:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
    curl -X POST \
    https://antifraud.empello.net/api/v2/js/fetch/ \
    -F api_key=JYAguvWE6Fn4wRmXPkY9kaAiD \
    -F 'merchant_name=My merchant' \
    -F 'service_name=My service' \
    -F country=GB \
    -F carrier=234-27 \
    -F 'button_selector=#myForm > button > div' \
    -F msisdn=10000000001 \
    -F use_fraudstop=1 \
    -F price_point=5_gbp_weekly \
    -F test=0
Example response:
1
2
3
4
5
  {"status": 200,
  "success": 1,
  "message": "Success",
  "token": "ukgxydsxrogqgioblcrkolllrbgbmkhphykypupahkclhzztnhzygqrotxlrjwrz",
  "jsstring": "!function(e){var t={};..."}

Validation API

To ensure that all checks have been passed and not circumvented we assign a token to each user. This token must be checked before a payment is processed, but after the user has confirmed (clicked). A call must be made to Empello's token api referencing this token and the api key provided. It will reply with a boolean variable is_valid, true for valid and false for invalid. If the token is invalid then the payment must not be accepted.

Warning

You must store the token alongside the transaction for audit purposes.

These are the fields that are accepted by the validate endpoint:

Field Value Required
token The token code assigned to this transaction Required
api_key The API key assigned to you Required
timestamp Timestamp associated with the transaction in ISO 8601 format Required
user_ip The users IP Required
user_agent The users useragent Required
msisdn The users MSISDN (can be an alias, ancrypted or plain text) Optional

The POST request sent to https://antifraud.empello.net/api/v2/token/validate/ should be sent as form-data. Here is an example cURL command (please note these are only example values):

1
2
3
4
5
6
7
    curl -X POST \
    https://antifraud.empello.net/api/v2/token/validate/ \
    -F api_key=JYAguvWE6Fn4wRmXPkY9kaAiD \
    -F timestamp=2022-12-31T12:59:59.000Z \
    -F user_ip=123.123.123.123 \
    -F 'user_agent=Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.3' \
    -F token=njgxydsxrogqgioblcrkolllrbgbmkhphykypupahkclhzztnhzygqrotxlrjwrz

For code examples of this cURL see here.

The endpoint will reply with the token and it's verification status. An accepted transaction (that is is_valid = true) looks like this:

1
2
3
4
    {"is_valid": true,
    "timestamp": "2018-12-31T12:59:59+00:00",
    "token": "bQzBYxvHNguXHhLMWiikEUHkQhmt2fxpT8fkJqaB7ddMoGGpEY6Hm3c2avH9G4mc",
    "status": 200}

For a blocked transaction the reply will look like this:

1
2
3
4
5
6
    {"is_valid": False,
    "threat_code": 16,
    "threat_flags": "BOT_ACTIVITY|GENERAL_ACTIVITY",
    "token": "njgxydsxrogqgioblcrkolllrbgbmkhphykypupahkclhzztnhzygqrotxlrjwrz",
    "status": 200,
    "timestamp": 2019-03-14T16:19:53.389721}

Warning

If you are seeing Suspicious Token as a block reason in implementation testing then please see the troubleshooting page.

Note

Threat flags are separated by a #!|, for a full list of threat codes and flags visit the threat codes reference.

Validation API Code Examples

Feel free to use the examples below to implement the API query on your backend. Remember to replace YOUR_API_KEY with the API key given to you by Empello (if you do not have one please contact us) and replace YOUR_TOKEN with the token to be queried.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost("https://antifraud.empello.net/api/v2/token/validate/");
httpPost.setHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");

List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("api_key", "YOUR_API_KEY"));
params.add(new BasicNameValuePair("timestamp", DateTimeFormatter
        .ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS")
        .withZone(ZoneOffset.UTC)
        .format(Instant.now())));
params.add(new BasicNameValuePair("user_ip", getUserIP()));
params.add(new BasicNameValuePair("user_agent", getUserAgent()));
params.add(new BasicNameValuePair("token", "YOUR_TOKEN"));

httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));

ResponseHandler<String> responseHandler = response -> {
    HttpEntity entity = response.getEntity();
    return entity != null ? EntityUtils.toString(entity) : null;
};

String responseBody = httpclient.execute(httpPost, responseHandler);
JSONObject responseObj = new JSONObject(responseBody);

if (responseObj.has("message")) {
    System.out.println("Message: " + responseObj.get("message"));
} else {
    System.out.println("Status:           " + responseObj.get("status"));
    System.out.println("Token:            " + responseObj.get("token"));
    System.out.println("Timestamp:        " + responseObj.get("timestamp"));
    System.out.println("IsValid:          " + responseObj.get("is_valid"));
    System.out.println("ThreatCode:       " + responseObj.get("threat_code"));
    System.out.println("ThreatFlags:      " + responseObj.get("threat_flags"));
    System.out.println("HasAllDatapoints: " + responseObj.get("has_all_datapoints"));
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
val url = URL("https://antifraud.empello.net/api/v2/token/validate/")
val conn: HttpURLConnection = url.openConnection() as HttpURLConnection
conn.requestMethod = "POST"

val arguments: MutableMap<String, String> = HashMap()
arguments["api_key"] = "YOUR_API_KEY"
arguments["timestamp"] = DateTimeFormatter
    .ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS")
    .withZone(ZoneOffset.UTC)
    .format(Instant.now())
arguments["user_ip"] = getUserIP()
arguments["token"] = "YOUR_TOKEN"
arguments["user_agent"] = getUserAgent()

val sj = StringJoiner("&")
for ((key, value) in arguments) sj.add(
    URLEncoder.encode(key, "UTF-8") + "=" + URLEncoder.encode(value, "UTF-8")
)
val out: ByteArray = sj.toString().toByteArray()
val length = out.size

conn.doInput = true
conn.doOutput = true

conn.setFixedLengthStreamingMode(length)
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
conn.connect()
conn.outputStream.use { os -> os.write(out) }

val response: String
if (conn.responseCode == 200) {
    response = conn.inputStream.bufferedReader().readText()
    val responseObj = JSONObject(response)

    println("Status:           " + responseObj.get("status"))
    println("Token:            " + responseObj.get("token"))
    println("Timestamp:        " + responseObj.get("timestamp"))
    println("IsValid:          " + responseObj.get("is_valid"))
    println("ThreatCode:       " + responseObj.get("threat_code"))
    println("ThreatFlags:      " + responseObj.get("threat_flags"))
    println("HasAllDatapoints: " + responseObj.get("has_all_datapoints"))

} else {
    response = conn.errorStream.bufferedReader().readText()
    val responseObj = JSONObject(response)

    println("Message: " + responseObj.get("message"))
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<?php
function getUserIP()
{
    if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
        $ip = $_SERVER['HTTP_CLIENT_IP'];
    } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
    } else {
        $ip = $_SERVER['REMOTE_ADDR'];
    }
    return $ip;
}

$postdata = http_build_query(
    array(
        'api_key' => "YOUR_API_KEY",
        'timestamp' => date('Y-m-d\TH:i:s.ZZZZZZ', time()),
        'user_ip' => getUserIP(),
        'token' => 'YOUR_TOKEN',
        'user_agent' => $_SERVER['HTTP_USER_AGENT'],
    )
);

$options = array(
    'http' => array(
        'method' => 'POST',
        'header' => "Content-type: application/x-www-form-urlencoded",
        'content' => $postdata,
        // We ignore errors, because we also want to parse the body of 400 errors
        'ignore_errors' => '1',
    ),
);

$context = stream_context_create($options);

$api_json = @file_get_contents("https://antifraud.empello.net/api/v2/token/validate/", false, $context);
$api_data = json_decode($api_json, true);

?>

<?php if (isset($api_data['message'])) {?>

    <b>message:</b>             <?php print $api_data['message'];?><br>

<?php } else {?>

    <b>status:</b>             <?php print $api_data['status'];?> <br>
    <b>token:</b>              <?php print $api_data['token'];?> <br>
    <b>timestamp:</b>          <?php print $api_data['timestamp'];?> <br>
    <b>is_valid:</b>           <?php print $api_data['is_valid'] ? 'true' : 'false';?> <br>
    <b>threat_code:</b>        <?php print $api_data['threat_code'];?> <br>
    <b>threat_flags:</b>       <?php print $api_data['threat_flags'];?> <br>
    <b>has_all_datapoints:</b> <?php print $api_data['has_all_datapoints'];?> <br>

<?php }?>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
const request = require('request');

const queryEmpelloToken = (params) => {
  return new Promise((resolve) => {
    request.post(
      'https://antifraud.empello.net/api/v2/token/validate/',
      { form: params },
      (error, response, body) => {
        const jsonBody = error ? null : JSON.parse(body);
        resolve({ error, response, body: jsonBody });
      }
    );
  });
};

const getUserIP = (req) => {
  if (req.header('client-ip')) {
    return req.header('client-ip');
  }
  if (req.header('x-forwarded-for')) {
    const forwardedIPs = req.header('x-forwarded-for');
    return forwardedIPs.split(',')[0];
  }
  return req.connection.remoteAddress;
};

const getUserAgent = (req) => {
  return req.header('user-agent');
};

app.get('/', async (req, res) => {
  const { error, body } = await queryEmpelloToken({
    api_key: 'YOUR_API_KEY',
    timestamp: new Date().toISOString(),
    token: 'YOUR_TOKEN',
    user_ip: getUserIP(req),
    user_agent: getUserAgent(req),
  });

  if (error) {
    return res.send(error);
  }

  if (body && body.message) {
    return res.send(body.message);
  }

  const {
    status,
    token,
    timestamp,
    is_valid,
    threat_code,
    threat_flags,
    has_all_datapoints,
  } = body;

  res.send(`
    <b>status:</b>             ${status} <br/>
    <b>token:</b>              ${token} <br/>
    <b>timestamp:</b>          ${timestamp} <br/>
    <b>is_valid:</b>           ${!!is_valid} <br/>
    <b>threat_code:</b>        ${threat_code} <br/>
    <b>threat_flags:</b>       ${threat_flags} <br/>
    <b>has_all_datapoints:</b> ${has_all_datapoints} <br/>
  `);
});
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import * as request from "request";

const getUserIP = () => {
  return "1.2.3.4";
};

const getUserAgent = () => {
  return "MY_USER_AGENT";
};

request.post(
  "https://antifraud.empello.net/api/v2/token/validate/",
  {
    form: {
      api_key: 'YOUR_API_KEY',
      timestamp: new Date().toISOString(),
      token: 'YOUR_TOKEN',
      user_ip: getUserIP(),
      user_agent: getUserAgent(),
    },
  },
  (error, _, body) => {
    const jsonBody = error ? null : JSON.parse(body);

    if (error) {
      console.log(error);
      return;
    }

    if (jsonBody && jsonBody.message) {
      console.log(jsonBody.message);
      return;
    }

    const {
      status,
      token,
      timestamp,
      is_valid: isValid,
      threat_code: threatCode,
      threat_flags: threatFlags,
      has_all_datapoints: hasAllDatapoints,
    } = jsonBody;

    console.log(`
      status:              ${status}
      token:               ${token}
      timestamp:           ${timestamp}
      is_valid:            ${!!isValid}
      threat_code:         ${threatCode}
      threat_flags:        ${threatFlags}
      has_all_datapoints:  ${hasAllDatapoints}
    `);
  }
);