Integrating the Coinme Risk Engine

Introduction

The Coinme Risk Engine SDK is a library, distributed as an NPM package, that allows you to interact with the Coinme Risk Engine from your application. It provides utilities that allow you to integrate against the Coinme risk engine for the various transactional flows in your application so that Coinme may appropriately assess transactional risk when processing transactions.


The Coinme Risk Engine SDK is currently only available in React and React Native. Coinme is working on implementations for other languages, such as Flutter and Swift. Coinme will provide an update when this framework support is available.

⚠️

In order to utilize Coinme payment processing services from within your application (i.e. buying/selling with a debit card), you must implement and use the Coinme risk engine SDK.


ℹ️

What is it?

The Coinme risk engine aggregates data about user behavior for your application. It collects:

  • Device data such as the type of device, browser, etc.
  • Location data, such as where the user is connecting from.
  • Connection data, such as if the user is using a proxy or VPN, etc.

Behavioral data includes how a user interacts with your application, how quickly they enter data into fields, etc.

This data is used to determine the relative riskiness of the user/transaction.

Why is Risk Tagging Important?

Risk tagging allows the SDK to track user interactions tied to specific actions within your application. When an element is tagged, the risk engine can better assess whether a user behaves normally or if suspicious automation patterns are detected.

For example, if the risk engine determines that the user is connected with an unknown browser type via a VPN or proxy and that interactions with elements of your app are happening much faster than would be normal for a human, then the engine may determine automation is at play and rank the transaction as high risk.

How to Use the SDK

The Coinme Risk Engine SDK is an NPM package. You may install it as follows.

⚠️

This package is not public; you will need to access credentials or a package key in order to install it. You may obtain this by working with the Coinme Business Development team.

Installation

To install the package, you must configure your .npmrc or .yarnrc (or equivalent) to include your authentication token:

@coinme:registry=https://npm.coinme.com/coinme-security-wrapper/
//npm.coinme.com/coinme-security-wrapper/:_authToken=<AUTHENTICATION_TOKEN>
always-auth=true
📘

Replace <AUTHENTICATION_TOKEN> with your provided token.

Then install via:

NPM:

npm install @coinme/risk-sdk-js

Yarn:

yarn add @coinme/risk-sdk-js

PNPM:

pnpm add @coinme/risk-sdk-js

QuickStart

You can use the Coinme Risk Engine SDK in your project by following the steps below.


Setup the Coinme Risk Engine

The setup function initializes the Risk Engine and applies all necessary configurations.

import { setupCoinmeRiskEngine } from "@coinme/risk-sdk-js";

setupCoinmeRiskEngine({
  mode: "test",
  clientId: "client-id",
})
  .catch((error) => {
    console.error("Error setting up Risk Engine:", error);
  })
  .finally(() => {
    console.log("Risk Engine setup complete!");
  });
ℹ️

Note: setupCoinmeRiskEngine is not sufficient in and of itself to use the risk SDK; this call is to be made when your app starts up in order to initialize the risk engine. There are other conditions which will require you to update additional parameters dynamically during the user session, such as when a user starts a high-risk action like a transaction, after a user has onboarded and now there is a customerId, etc. In these cases, use updateCoinmeRiskEngine.

ℹ️

Key Takeaway: When should I use this?

You should call setupCoinmeRiskEngine when your application instantiates.

⚠️

You will need two clientIds, one for your development builds and one for your prod builds. You may obtain these from the Coinme business development team. It is very important that you pass the correctmode and clientId properties into the risk engine based on development or production usage, otherwise you may not stream your behavioral data to the correct environment, which can severely impact the risk engine’s ability to assess risk. This would ultimately negatively impact your transaction approvals.

Get Current Configuration

To check which risk parameters are applied, use:

import { getCoinmeRiskEngineConfig } from "@coinme/risk-sdk-js";

const config = getCoinmeRiskEngineConfig();
console.log(config);
⚠️

Note that the configuration is only available after setup completes.

Update Coinme Risk Engine Configuration

While setup handles initial configuration, you can and should manually update specific parameters when needed. An example would be after a user has onboarded or logged in, as at this point you will have a customerId available to you; this helps the risk engine associate user behavior with your user.

Another example is when you wish to update the flow identifier being sent to the risk engine. This is necessary so that when your user is entering a specific flow in your app such as onboarding, linking a payment method, or transacting, these special activities will be properly tagged; the risk engine examines user behavior in such flows closely. Therefore, you should tag these flows by updating the risk engine config by providing a flow identifier as seen below.

ℹ️

A flow identifier is a string that acts as a tag to uniquely identify that data the risk engine is logging belongs to a contiguous and related flow of user actions.

import { updateCoinmeRiskEngine } from "@coinme/risk-sdk-js";

updateCoinmeRiskEngine({
  customerId: "customer-123",
  flow: "customer-onboarding",
})
  .catch((error) => {
    console.error("Error updating configuration:", error);
  })
  .finally(() => {
    console.log("Configuration updated");
  });

Flow Types

Certain flows are universal and are important to the operation of the Coinme Risk Engine. You can use a pre-defined FlowType in these cases to ensure you are properly tagging these flows. We export a FlowType enumeration that exposes these common flows, which the risk engine can understand and use when making risk decisions. This enum is structured as follows:

export enum FlowType {
  Onboarding = 'customer-onboarding',
  CardTransaction = 'card-transaction',
  CardLinking = 'payment-method-linking',
}

For maximum value, you should use the appropriate FlowType as the flow identifier when you are onboarding users, adding a payment method, or undertaking a transaction.

ℹ️

Why Use Flow Identifiers?

Flow identifiers help group multiple actions into a single session so that risk is assessed based on contextual user behavior. Instead of analyzing each interaction separately, the risk engine can detect patterns within a specific user journey.

For example:

  • If a user enters payment details too quickly after onboarding, this might indicate a scripted attack rather than a real person.
  • If a user switches IP addresses midway through a transaction, it could indicate a fraud attempt.
  • If a user is interacting normally but suddenly switches to rapid inputs, the system can adapt its risk evaluation in real time.

By tagging actions with the correct FlowType, your application provides the risk engine with the necessary context to assess transactional legitimacy.

⚠️

The Coinme risk engine requires the specific flow identifiers exposed by the risk SDK for any of these pre-defined flow types; if you do not use the supported identifier, your users and transactions may not be appropriately scored and you will be at risk of high denial rates for your transactions.


Usage Examples

Each example demonstrates when and how to use updateCoinmeRiskEngine with a specific flow type.

Example 1: Onboarding Flow

When a new user signs up, you must tag their session as onboarding so the risk engine can monitor suspicious activities.

import { updateCoinmeRiskEngine, FlowType } from "@coinme/risk-sdk-js";

updateCoinmeRiskEngine({
  customerId: "new-user-456",
  flow: FlowType.Onboarding,
})
  .catch((error) => {
    console.error("Error updating configuration:", error);
  })
  .finally(() => {
    console.log("User onboarding flow tracked.");
  });
ℹ️

When to use?

Call this when the user starts the signup process.


Example 2: After Onboarding or Sign-in

After a new user finishes signing up, or after a user has signed in, you must update the risk engine with their userID so that data can now be associated with the user rather than a session. This allows the risk engine to aggregate and interpret data over time.

import { updateCoinmeRiskEngine, FlowType } from "@coinme/risk-sdk-js";

updateCoinmeRiskEngine({
  customerId: "user-456",
})
  .catch((error) => {
    console.error("Error updating configuration:", error);
  })
  .finally(() => {
    console.log("User ID now tracked.");
  });
ℹ️

When to use?

Call this right after the user completes the signup or login process and the user’s permanent ID is known.


Example 3: Linking a New Card

If a user is adding a new payment method, this is a high-risk action that must be monitored.

import { updateCoinmeRiskEngine, FlowType } from "@coinme/risk-sdk-js";

updateCoinmeRiskEngine({
  customerId: "user-789",
  flow: FlowType.CardLinking,
})
  .catch((error) => {
    console.error("Error updating configuration:", error);
  })
  .finally(() => {
    console.log("Card linking flow tracked.");
  });
📘

When to use?

Call this when the user enters a process to add a payment method.


Example 4: Processing a Card Transaction

When a user makes a purchase or transaction, you should explicitly tag it.

import { updateCoinmeRiskEngine, FlowType } from "@coinme/risk-sdk-js";

updateCoinmeRiskEngine({
  customerId: "user-123",
  flow: FlowType.CardTransaction,
})
  .catch((error) => {
    console.error("Error updating configuration:", error);
  })
  .finally(() => {
    console.log("Card transaction flow tracked.");
  });
ℹ️

When to use?

Call this when the user enters a transactional flow such as when they start a buy or sell transaction.

⚠️

Note on Using theupdateCoinmeRiskEngine Properly:
The updateCoinmeRiskEngine function is designed to modify the risk engine's configuration after the initial setup. However, since both setupCoinmeRiskEngine and updateCoinmeRiskEngine are asynchronous, calling them sequentially without ensuring the setup is complete may cause the update function to override the initial configuration.


How to Update Correctly

  • Ensure that setupCoinmeRiskEngine is completed before calling updateCoinmeRiskEngine.
  • If calling both on the first render (e.g., in a React setup), chain them properly using await or a state check.
  • Calling updateCoinmeRiskEngine before setupCoinmeRiskEngine finishes may lead to an incomplete or overridden configuration.
ℹ️

Example: Correct Usage - Await the Setup Before Updating

async function initializeRiskEngine() {
  await setupCoinmeRiskEngine({
    mode: "test",
    clientId: "client-id",
  });

  console.log("Setup complete:", getCoinmeRiskEngineConfig());

  await updateCoinmeRiskEngine({
    customerId: "[email protected]",
    flow: "flow-id",
  });

  console.log("Update complete:", getCoinmeRiskEngineConfig());
}

initializeRiskEngine();

Why is this correct?

  • Ensures setup completes before update can be called
ℹ️

Example: Incorrect Usage - Running Setup and Update in Parallel

setupCoinmeRiskEngine({
  mode: "test",
  clientId: "client-id",
});
updateCoinmeRiskEngine({
  customerId: "[email protected]",
  flow: "flow-id",
});

Why is this wrong?

  • updateCoinmeRiskEngine may execute before setupCoinmeRiskEngine completes.
  • The update call might override important setup details.
  • Leads to unpredictable behavior in the risk engine configuration.
ℹ️

Key Takeaway: When should I use this?

You should call updateCoinmeRiskEngine:

  • After a user has onboarded or logged in, and you have a customerId
    • By updating the risk engine with the customerId, you ensure that the risk engine can understand the user’s behavior over time, which leads to better risk modeling.
  • When a user begins a flow that needs to be explicitly identified, such as onboarding, linking a payment method, or transacting.
    • These are key actions that should be tagged with the correct flow identifier.

Tagging Elements

You can add Risk attributes to elements, components, or strings with the addCoinmeRiskTag function. The risk engine SDK automatically detects these tags and will flow behavioral metrics into the risk engine from any tagged entities automatically.

Examples:

  • Returning a pre-tagged HTML element:
import { addCoinmeRiskTag } from "@coinme/risk-sdk-js";

// Using a raw HTML string
const elementAsString = addCoinmeRiskTag({
  element: '<div>Hello, World!</div>',
  riskIdentifier: 'my-element',
});

console.log(elementAsString); // Outputs a div with the risk data attribute 'my-element' added.
  • Tagging an existing DOM element:
import { addCoinmeRiskTag } from "@coinme/risk-sdk-js";

// Using an existing DOM element
const divElement = document.createElement('div');

divElement.textContent = 'Hello, World!';

const taggedElement = addCoinmeRiskTag({ element: divElement, riskIdentifier: 'my-element' });

console.log(taggedElement.outerHTML); // Outputs a div with the risk data attribute 'my-element' added.
  • Tagging a React-Like object:
import { addCoinmeRiskTag } from "@coinme/risk-sdk-js";

// Tagging a React/Vue-style object
const reactLikeObject = {
  type: 'div',
  props: { children: 'Hello, World!' },
};

const taggedObject = addCoinmeRiskTag({ element: reactLikeObject, riskIdentifier: 'my-element' });

console.log(taggedObject); 
// Outputs a react / vue style object with the risk data attribute 'my-element' added.

Core Concepts

⚠️

You must provide your clientId to use the SDK. If you don't have your clientId, contact Coinme business development team.


The clientId uniquely identifies your partner integration within the Risk Engine.

  • It is provided by Coinme during onboarding.
  • Usually shared with other credentials like auth tokens or access scopes.
  • Without it, the SDK will throw an error and refuse to initialize.

UnderstandingsessionKey

The sessionKey is a unique identifier for tracking a specific user session.

BehaviorOutcome
Provide sessionKey in setupUsed & stored for session
Provide sessionKey in updateOverrides previous one
No sessionKey providedAuto-generated using FingerprintJS
Call resetStoredSessionKey()Clears stored key

Resetting thesessionKey

import { resetStoredSessionKey } from "@coinme/risk-sdk-js";

resetStoredSessionKey();
ℹ️

Use this when:

  • Logging out users.
  • Switching accounts.
  • Resetting state for tests.

Typical Session Flow Example

// Setup with auto-generated sessionKey
await setupCoinmeRiskEngine({
  mode: 'prod',
  clientId: 'client-id',
});

// Later — Update without providing sessionKey (uses stored one)
await updateCoinmeRiskEngine({
  flow: 'customer-onboarding',
});

// On session end (e.g., logout)
resetStoredSessionKey();

// Start new user/session
await setupCoinmeRiskEngine({
  mode: 'prod',
  clientId: 'client-id',
});

API Reference

The Coinme Risk Engine SDK provides the following functions for interacting with the Risk Engine.

You can find detailed information about each function below

setupCoinmeRiskEngine

Sets up the Coinme Risk Engine with the provided options.

ParamTypeRequiredDescription
mode`'test' \'prod'`Operating environment
clientIdstringPartner-specific risk engine client ID
partnerIdstringoptionalPartner identifier
customerIdstringoptionalCustomer identifier
sessionKeystringoptionalCustom session tracking key
flow`string \FlowType`optionalFlow context

Example:

import { setupCoinmeRiskEngine } from "@coinme/risk-sdk-js";

setupCoinmeRiskEngine({ mode: "test", clientId: "client-id" })
  .catch((error) => {
    console.error("Error setting up Risk Engine:", error);
  })
  .finally(() => {
    console.log("Risk Engine setup complete!");
  });

getCoinmeRiskEngineConfig

Retrieves the latest risk assessment settings applied to the current session.

Returns:

  • Record<string, any>: An object containing the current Risk Engine configuration.
  • If no configuration has been set, it returns {}.

Example:

const config = getCoinmeRiskEngineConfig();
console.log(config); // Outputs: { partnerId: "...", sessionKey: "...", ... }

updateCoinmeRiskEngine

Updates the Coinme risk assessment settings for the current session. This ensures that risk evaluations, such as device fingerprinting and geolocation tracking, are correctly applied.

Parameters:

ParamTypeRequiredDescription
partnerIdstringoptionalPartner identifier
customerIdstringoptionalCustomer identifier
sessionKeystringoptionalOverride session key
flow`string \FlowType`optionalFlow context
parentSessionKeystringoptionalParent session key
enableBiometricsbooleanoptionalEnable biometric signals
enableGeoLocationbooleanoptionalEnable geo-location
enablePortScanningbooleanoptionalEnable port scanning

Example:

import { updateCoinmeRiskEngine } from "@coinme/risk-sdk-js";

updateCoinmeRiskEngine({
  customerId: "customer-123",
  flow: "onboarding",
})
  .catch((error) => {
    console.error("Error updating configuration:", error);
  })
  .finally(() => {
    console.log("Configuration updated");
  });

addCoinmeRiskTag

Enhances an element, component, or string representation of HTML by tagging the element with a risk tag. The risk engine SDK automatically detects these tags and will flow metrics into the risk engine from any tagged entities automatically.

Parameters:

PropTypeRequiredDescription
element`HTMLElement \object \string`Target element
riskIdentifierstringUnique risk tag


Returns:

The same element with the risk tag applied.

Example:

import { addCoinmeRiskTag } from "@coinme/risk-sdk-js";

const element = addCoinmeRiskTag({
  element: '<div>Hello, World!</div>',
  riskIdentifier: 'my-element',
});

console.log(element); // Outputs a div tagged with the specified risk tag

withCoinmeRiskTag

Creates a higher-order component that adds a risk tag to the props (or equivalent) of the wrapped component.

Parameters:

ParamTypeRequiredDescription
ComponentfunctionThe component function to wrap.
idstringUnique risk tag to apply.

Returns:

  • A wrapped component with the risk tag attribute added to props or its equivalent.

Examples

Wrapping a simple component:

import { withCoinmeRiskTag } from "@coinme/risk-sdk-js";

const MyComponent = (props) => `<div>${props.text}</div>`;

const TaggedComponent = withCoinmeRiskTag(MyComponent, 'my-element');

console.log(TaggedComponent({ text: 'Hello, world!' }));
// Outputs a div tagged with the given risk tag

Wrapping an object-based component:

import { withCoinmeRiskTag } from "@coinme/risk-sdk-js";

const MyObjectComponent = (props) => ({
  type: 'div',
  props: { children: props.text },
});

const WrappedObject = withCoinmeRiskTag(MyObjectComponent, 'object-component');

console.log(WrappedObject({ text: 'Hello, world!' }));
// Outputs an object tagged with the specified risk tag