Account Takeover API

Overview

Account takeover (ATO) is when a fraudster gains control of an account that belongs to a genuine customer. Fraudsters can then make unauthorised transactions, sell the compromised accounts on and/or scrape personal information out of the account which can be sold.

Phishing, spyware and malware can all be used to commit more sophisticated ATO attacks. However, credential stuffing is the most common tactic used to launch ATO attacks.

Credential stuffing uses stolen username and password combinations to automate login requests in order to gain access to user accounts. Estimates on the average success rate of credential stuffing attacks range from 0.1-2% with a peak of 8% quoted by some sources.

Following a breach, stolen credentials are purchased on the darkweb and shared via cracking forums. Data breaches are therefore a major contributing factor to increasing levels of ATO attacks. Combined with high levels of password reuse, this is especially concerning.

Credential stuffing can be scripted by more skilled fraudsters. However, automated tools like Sentry MBA make credential stuffing very easy for anyone to commit. This means there is a range of actors involved in committing ATO; from sophisticated hackers through to teenagers looking to order a ‘free’ pizza.

ATO attacks have significant consequences for merchants. It’s not just the cost of replacing goods or refunding payments - it’s also the time spent by support teams dealing with angry customers and other teams tackling the legal and operational fallout. In addition, there is often significant reputational damage incurred.

How Ravelin Combats Account Takeover

Taking into account the nature of ATO, Ravelin have introduced a number of different ways to combat the issue.

Breached Credentials

Credential stuffing relies on a list of username and password combinations. In order to mitigate against this, we maintain a breached credentials database. Calls can be made to the database either via the v3/login event at login or via /v2/lookup/credentials/check during registration or password change to verify if we’ve seen the credentials in the wild. Though we cannot guarantee that every breached credential will be in our database, this can go a long way to preventing ATO. You can also search for and view users that have logged in with credentials that appear in our database - providing additional context during investigations.

Rate limits

We have added customizable rate limits at login around device, username and IP. Thresholds can be set for this depending on your specific operational requirements. Rate limits are useful for tackling high volume attacks.

In addition, we check for things we know can indicate that a user is a fraudster like proxies and TOR.

Rules

We can set ATO specific rules around device, username, IP and velocity. For example, if the same device tries to access X accounts within a set time frame. Rules are especially useful for tackling ‘low and slow’ volume attacks.

Collecting and surfacing login activity data

By leveraging data collected via v3/login event, we provide oversight of login activity within our dashboard. Login activity reporting is available to explore via our Analytics tool, making it easier to spot anomalies in ‘normal’ login activity across your customer base. In addition, you can interact with login data via a filterable login list and drill down to view login information for a specific customer on their customer profile.

Monitoring Account Changes

Account changes can be used as an important signal for ATO. For example, if a new device or location is detected at login or if there is a change made to account details like email or delivery address. We can also send you information on changes to account details so it can be used to verify that the change was legitimately made by the customer

Login Event

The point of login is a critical step in detecting account takeover. We want to prevent the malicious actor from being able to log in just like we want to prevent the fraudster from completing an order.

POST /v3/login?score=true

This is the endpoint used to tell Ravelin about every login attempt, both successful and unsuccessful. Unsuccessful logins can be important signals for an ATO attack. It will provide an ATO recommendation response if asked for via the query parameter score=true. Otherwise it will simply record the data without further processing.

 

Property

Type

Required

Description

timestamp

integer

yes

Unix timestamp with milliseconds, (Nanoseconds also accepted)

login

object

yes

Defined below

device

object

no

Not required but highly recommended. Defined below

location

object

no

Defined below

{
    "device": {
      "approxDeviceIdRate": 0,
      "approxDeviceIdRateBlock": true,
      "approxIPAddressRate": 0,
      "approxIPAddressRateBlock": true,
      "browser": "string",
      "cookiesEnabled": true,
      "custom": {
        "additionalProp1": {},
        "additionalProp2": {},
        "additionalProp3": {}
      },
      "deviceId": "string",
      "firstSeen": "string",
      "ipAddress": "string",
      "location": {
        "city": "string",
        "country": "string",
        "custom": {
          "additionalProp1": {},
          "additionalProp2": {},
          "additionalProp3": {}
        },
        "geohash": "string",
        "latitude": 0,
        "longitude": 0,
        "neighbourhood": "string",
        "poBoxNumber": "string",
        "postalCode": "string",
        "region": "string",
        "street1": "string",
        "street2": "string",
        "zone": "string"
      },
      "manufacturer": "string",
      "model": "string",
      "os": "string",
      "screenResolution": "string",
      "type": "string",
      "userAgent": "string"
    },
    "location": {
      "city": "string",
      "country": "string",
      "custom": {
        "additionalProp1": {},
        "additionalProp2": {},
        "additionalProp3": {}
      },
      "geohash": "string",
      "latitude": 0,
      "longitude": 0,
      "neighbourhood": "string",
      "poBoxNumber": "string",
      "postalCode": "string",
      "region": "string",
      "street1": "string",
      "street2": "string",
      "zone": "string"
    },
    "login": {
      "approxUsernameRate": 0,
      "approxUsernameRateBlock": true,
      "authenticationMechanism": {
        "magiclink": {
          "email": "string",
          "failureReason": "string",
          "phoneNumber": "string",
          "success": true,
          "transport": "string"
        },
        "oneTimeCode": {
          "failureReason": "string",
          "success": true
        },
        "password": {
          "failureReason": "string",
          "passwordBcrypted": "string",
          "success": true
        },
        "recaptcha": {
          "failureReason": "string",
          "success": true
        },
        "rsaKey": {
          "failureReason": "string",
          "success": true
        },
        "smsCode": {
          "failureReason": "string",
          "phoneNumber": "string",
          "success": true
        },
        "social": {
          "failureReason": "string",
          "socialProvider": "string",
          "success": true
        },
        "u2f": {
          "failureReason": "string",
          "success": true
        }
      },
      "custom": {
        "additionalProp1": {},
        "additionalProp2": {},
        "additionalProp3": {}
      },
      "customerId": "string",
      "loginId": "string",
      "success": true,
      "username": "string"
    },
    "timestamp": 0
  }

Above is the full login request object. This is similar to our /v2/login endpoint but with additional information regarding the authentication attempt. This request is expected to be sent after all successful and unsuccessful logins from your backend system.

Login

Property

Type

Required

Description

username

String

yes

The username of the user. This is the unique string that ties this particular user to the authentication mechanism used. Typically this is the email address.

customerId

String

yes

customerId is the unique identifier for a user. This identifier does not change even if the username is changed. This is optional for login events as you will see failed logins against usernames that do not exist in your system and therefore do not have a customerId. Please send this on login attempts where a customerId is available. If you are using our fraud solution, this should be the same customerId as used there.

success

Boolean

yes

If the login attempt was successful and access was granted

authenticationMechanism

 

yes

At least one authentication mechanism must be provided. More than one may be provided. For example a password and a oneTimeCode may be used to authenticate.

 

password

   

Provided if the user is using a password to authenticate

   

passwordHashed

string

 

The SHA256 hashed (https://en.wikipedia.org/wiki/SHA-2 ) form of the password. This is used to check the password against our ever updating list of breached credentials. This hash is not stored by Ravelin. It is used to check our breached credential database and then discarded.

   

success

boolean

yes

If the authentication was successful

   

failureReason

string

conditional

This is required if success is set to false. Valid values are: BAD_PASSWORD, UNKNOWN_USERNAME, INTERNAL_ERROR, RATE_LIMIT

 

social

   

Provided if the user authenticates via a social login provider

   

success

boolean

yes

If the authentication was successful

   

failureReason

string

conditional

This is required if success is set to false. Valid values are: TIMEOUT, UNKNOWN_USERNAME, INTERNAL_ERROR, RATE_LIMIT, SOCIAL_FAILURE

   

socialProvider

string

yes

The social provider of the used for the authentication process. Valid values are: google, facebook, twitter, microsoft, linkedin

 

oneTimeCode

   

Provided if a one time code such as those used by google Authenticator is used

   

success

boolean

yes

If the authentication was successful

   

failureReason

string

conditional

This is required if success is set to false. Valid values are: INVALID_CODE, CODE_TIMEOUT, INTERNAL_ERROR, RATE_LIMIT

 

u2f

   

Provided if u2f authentication is used as defined by the FIDO alliance. https://fidoalliance.org/download/

   

success

boolean

yes

If the authentication was successful

   

failureReason

string

conditional

This is required if success is set to false. Valid values are: INVALID_KEY, TIMEOUT, INTERNAL_ERROR, RATE_LIMIT

 

rsaKey

   

Provided if an rsaKey is used such as a Yubikey

   

success

boolean

yes

If the authentication was successful

   

failureReason

string

conditional

This is required if success is set to false. Valid values are: INVALID_KEY, TIMEOUT, INTERNAL_ERROR, RATE_LIMIT

 

smsCode

   

Provided if a one time code was used sent via sms

   

phoneNumber

string

yes

The number the sms was sent to

   

success

boolean

yes

If the authentication was successful

   

failureReason

string

conditional

This is required if success is set to false. Valid values are: INVALID_CODE, CODE_TIMEOUT, INTERNAL_ERROR, RATE_LIMIT

 

magiclink

   

Provided if a one time link was sent to the user via a trusted communication channel

   

transport

string

yes

The transportation mechanism for the magic link. Valid values include: email, sms

   

phoneNumber

string

conditional

The number the link was sent to. Required if transport is sms

   

email

string

conditional

The email the link was sent to. Required if transport is email

   

success

boolean

yes

If the authentication was successful

   

failureReason

string

conditional

This is required if success is set to false. Valid values are: INVALID_LINK, TIMEOUT, INTERNAL_ERROR, RATE_LIMIT

 

recaptcha

   

Provided if recaptcha was performed

   

success

boolean

yes

If the authentication was successful

   

failureReason

string

conditional

This is required if success is set to false. Valid values are: INTERNAL_ERROR, TIMEOUT, FAILED_TEST

Device

Device is a required field on the login event. Both the deviceId and the IP address must be present in request and are vital to any ATO product. The deviceId can be generated via our javascript library. Details about that can be found in the device fingerprinting section. Any other details can be very useful but are not strictly necessary. For more details about device tracking please see our API and the Guide.

Location

Location is not required as we are aware you will not typically have a location at login time. If you do have location as part of your flow this can be very useful to localise ongoing or repeat attackers. Please see here for details about the location object: Location API

Responses

Success

You can see an example of a successful response from the /v3/login endpoint below. This response is identical to other responses given by the Ravelin platform for payment fraud endpoints. Note that we do provide payment fraud scores at login time as well. The Payment fraud and ATO responses are both included. Ensure you use the correct action when dealing with ATO vs. Payment Fraud.

Property

Type

Description

status

integer

HTTP status code of the response

success

string

Indicates if the request was successful or not

timestamp

string

RFC3339Nano encoded timestamp for the response

credentialStatus

object

The status of the username and password

 

passwordBreached

bool

Indicates if the password + username combination appears in our breached credential database

 

usernameBreached

bool

Indicates if this username appears in our breached credential database

data

object

The Fraud and Account Takeover results. This is identical to fraud endpoint responses

 

ato

object

The Account Takeover specific results. All other results at the top level are indicative of payment fraud

   

action

string

The action to take regarding Account Takeover. One of BLOCK, WARN, PERMIT

   

rules

object

Indicates which rule was triggered to cause the given action

 

customerId

string

The customerId of customer in question

 

action

string

The action to regarding Payment Fraud. One of ALLOW, PREVENT, REVIEW.

 

score

integer

The score given regarding Payment Fraud

 

source

string

The source of the score given regarding Payment Fraud

 

scoreId

string

The scoreId of the given score regarding Payment Fraud

 

effectiveTime

string

The effective time the decision was made. All data sent before this time as measured by ravelin servers will be included in the decisions. The time is formatted as RFC3339Nano.

Example response:

{
    "checks": {
      "additionalProp1": {
        "action": "string"
      },
      "additionalProp2": {
        "action": "string"
      },
      "additionalProp3": {
        "action": "string"
      }
    },
    "credentialStatus": {
      "passwordBreached": true,
      "usernameBreached": true
    },
    "data": {
      "action": "string",
      "ato": {
        "action": "string",
        "rules": {
          "passiveAction": "string",
          "triggered": [
            {
              "action": "string",
              "description": "string",
              "state": "string",
              "triggered": true
            }
          ]
        }
      },
      "cachedScore": true,
      "comment": "string",
      "connect": {
        "fraudulent": true
      },
      "customerId": "string",
      "effectiveTime": "string",
      "lookup": {
        "lookupAction": "string",
        "lookupResult": {
          "email": {
            "address": "string",
            "hasChargebacks": true,
            "reviewedAsFraudster": true
          },
          "hasChargebacks": true,
          "industry": "string",
          "ipAddress": {
            "address": "string",
            "fromTime": 0,
            "hasChargebacks": true,
            "reviewedAsFraudster": true,
            "toTime": 0
          },
          "reviewedAsFraudster": true,
          "telephone": {
            "hasChargebacks": true,
            "number": "string",
            "reviewedAsFraudster": true
          }
        }
      },
      "market": {
        "city": "string",
        "country": "string",
        "region": "string"
      },
      "rules": {
        "passiveAction": "string",
        "triggered": [
          {
            "action": "string",
            "description": "string",
            "state": "string",
            "triggered": true
          }
        ]
      },
      "score": 0,
      "scoreId": "string",
      "source": "string",
      "thresholds": {
        "prevent": 0,
        "review": 0
      },
      "warnings": [
        {
          "class": "string",
          "help": "string",
          "msg": "string",
          "state": "string"
        }
      ]
    },
    "message": "string",
    "status": 0,
    "success": "string",
    "timestamp": "string",
    "traceId": "string",
    "warnings": [
      {
        "docs": "string",
        "id": 0,
        "message": "string"
      }
    ]
  }

Failure

You can see an example of a failed response from the /v3/login endpoint below. A failure response will indicate why the failure happened and will try to direct you to relevant documentation.

{
    "docs": "string",
    "errors": [
      {
        "Docs": "string",
        "Error": "string",
        "Path": "string"
      }
    ],
    "message": "string",
    "retryable": true,
    "status": 0,
    "success": "string",
    "timestamp": "string",
    "traceId": "string"
  }

Action

Using the information supplied to Ravelin, logins and other events are categorized in one of three buckets: PERMIT WARN BLOCK

This information is sent in the response body to scored POST requests (with ?score=true) as defined above.

Requesting an action

Events sent to Ravelin using POST requests get an empty response body by default. The information is stored in our system and no further action is taken during the request. To force an immediate evaluation based on the information received up to and including an event add the ?score=true query parameter.

This will do two things: 1. Process the event payload 2. Force immediate recalculation of the action and return it

The score will be calculated based on the information in this event, and in all events previously received and met with a 200 OK status.

Suggested handling

The ?score=true query parameter is available on every event endpoint. This includes both ATO and Payment Fraud related endpoints. Specify it when you want to make a decision regarding a login attempt.

The most important field in the payload is action under the ATO object:

On this action

In your system

PERMIT

Allow this login or account detail change to proceed - no action is required

WARN

We advise that you allow the login but take extra validation steps for this login or account detail change. Additional validation could include enforcing 2FA if you have a verified phone number, notifying the user that there has been suspicious account activity and asking them to cnfirm if the activity was legitimate or not or prompting the user to complete a recaptcha

BLOCK

We advise that you block this login or account change and show a generic error message which does not explain why the user was prevented from login. This is important as we do not want to make it obvious to the fraudster that we have detected the attempt. If we return a BLOCK response once a user is already logged in, we recommend that you invalidate their token immediately and review all recent activity on the account. You can also inform of the user and ask them to confirm if the activity was legitimate or not. However, it is important to remember that a fraudster may change the contact details associated with an account as part of an ATO attack so you may want to check if any account details were recently changed. If the email has been changed recently, we advise that you send any communications to the previously saved email.

Other fields are provided for analytic and debugging purposes.

Credentials Check

POST /v2/lookup/credentials/check

Ravelin maintains an up to date list of breached credentials that can be found in the public domain. At login, you can view whether the login attempt was using breached credentials by looking at the credentialStatus object within the /v3/login response.

You can use the database to check if a user is attempting to register a new account, or update an existing one, with credentials that have been seen in the wild via our v2/lookup/credentials/check endpoint. The below request is expected to be sent at password creation or update. The response will tell you if the username and/or password is found in our breached credential database.

Request

Passwords are extremely sensitive, so please do not send us plaintext passwords. Instead, please hash the password with SHA256 and HEX encode it before sending it. We do not store the hashed password, and discard it immediately after processing your request.

If you are still concerned about sending us a hash of the password please contact us for alternative options.

{
    "username": "string",   
    "passwordHash": "string"
}

Response

{
    "usernameBreached": true,
    "passwordBreached": true
}

There are three distinct flows where we check if a users credentials have been breached. For each flow, you may want to take a different action. Below we have outlined what we suggest for each flow.

Authentication

While your backend is processing a login request, you can call our v3/login endpoint. Our response will indicate within the credential status object whether or not the username and password appear in Ravelin’s breached credential database.

Credential Status Action
...
"credentialStatus": {
    "usernameBreached": false,
    "passwordBreached": false
  },
...
If the response is PERMIT and the credential status is FALSE for both username and password, we suggest you allow the login - no action is required.
...
"credentialStatus": {
    "usernameBreached": true,
    "passwordBreached": false
  },
...
If the credential status is only true for username, we suggest you take no action.
...
"credentialStatus": {
    "usernameBreached": true,
    "passwordBreached": true
  },
...
If the credential status is true for both username and password, we suggest you take at least one of the following actions taking into account your risk appetite:
  • Force the user to reset their password before allowing them to login
  • Prompt the user via email or text to reset their password after they login
  • Force the user to reset their password after they complete their session
  • Prompt the user to reset their password after they complete their session
  • Use 2FA if you have a verified phone number associated with the account

Registration

At registration, you can call our v2/lookup/credentials/check endpoint. We will return the responses outlined below.

Credential Status Action
...
"credentialStatus": {
    "usernameBreached": false,
    "passwordBreached": false
  },
...
No action is required if we return false.
...
"credentialStatus": {
    "usernameBreached": true,
    "passwordBreached": false
  },
...
If the credential status is only true for username, we suggest you take no action.
...
"credentialStatus": {
    "usernameBreached": true,
    "passwordBreached": true
  },
...
If a user is trying to register using credentials that appear in the breached database, we advise that you do NOT allow the user to set that password at registration.

Password Updates

During an account update (e.g. forgot password, password change), you can call our v2/lookup/credentials/check endpoint. We will return the responses outlined below.

Credential Status Action
...
"credentialStatus": {
    "usernameBreached": false,
    "passwordBreached": false
  },
...
No action is required if we return false.
...
"credentialStatus": {
    "usernameBreached": true,
    "passwordBreached": false
  },
...
If the credential status is only true for username, we suggest you take no action.
...
"credentialStatus": {
    "usernameBreached": true,
    "passwordBreached": true
  },
...
If a user is trying to update their account using credentials that appear in the breached database we advise that you do NOT allow the user to use the password at time of update.

Account Changes

When a customer makes changes to their account those details should be sent to Ravelin. This can be done via the core API. We will take these updates as signals to aid in account takeover detection. Further we are able to return these detected changes as well as the previous value to you in the response of the request. This includes a URL that can be used to verify that the customer was indeed the one to make those changes. This is typically done by sending an email to the customer asking if they recognize the new details.

Response

The response object will be inside the typical scoring response. As an example, this is the response received when a customer changes their email address on a new device:

{
  ...
  "customerChanges": [
  {
    "changeId": "abc-123-XYZ",
    "customerId": "customer1",
    "changeType": "EMAIL",
    "newValue": { 
      "email":{
        "email": "newEmail@example.com",
        "timestamp": "2019-02-11T15:23:05.468789646Z"
      }
    },        
    "previousValue": { 
      "email":{
        "email": "oldEmail@example.com",
        "timestamp": "2018-10-11T17:12:06.584698542Z"
      }
    },
    "timestamp": "2019-02-11T15:23:06.741447896Z",
    "verificationURL": "https://api.ravelin.com/v2/change/verify?id=Y2xpZW50SWTCp2N1c3RvbWVySWTCp2NoYW5nZUlk"
  },
  {
    "changeId": "XYZ-abc-123",
    "customerId": "customer1",
    "changeType": "DEVICE",
    "newValue": { 
      "device":{
        "deviceId": "new-device-id",
        "deviceType": "phone",
        "deviceManufacturer": "google",
        "deviceModel": "Pixel XL",
        "deviceOS": "android",
        "ipAddress": "10.11.12.13",
        "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
        "timestamp": "2019-02-11T15:23:05.468789646Z"
      }
    },        
    "previousValue": { 
      "device":{
        "deviceId": "old-device-id",
        "deviceType": "phone",
        "deviceManufacturer": "apple",
        "deviceModel": "iPhone X",
        "deviceOS": "iOS",
        "ipAddress": "10.11.12.13",
        "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
        "timestamp": "2018-11-03T17:43:05.468789646Z"
      }
    },
    "timestamp": "2019-02-11T15:23:06.741447896Z",
    "verificationURL": "https://api.ravelin.com/v2/change/verify?id=X48IkdxpZW50SWTCp2N1c3RvbWVySWTCp2NoYW5nZUlk"
  }
]
  ...
}

Property

Type

Description

customerChanges

array

An array containing all the changes detected as a result of this request

 

changeId

string

The ID of this change. This is globally unique.

 

customerId

string

customerId is the unique identifier for a user

 

changeType

string

Identifies the type of change this is. Valid Values are: DEVICE, IP_LOCATION, EMAIL, PASSWORD, PHONE, DELIVERY_ADDRESS, BILLING_ADDRESS

 

newValue

object

Holds the value of the change in question. More details

 

previousValue

object

Holds the value prior to the change in question. More details

 

timestamp

string

The RFC3339Nano encoded time that the change took place

 

verificationURL

string

The URL that is used to verify a change with a customer. More details

Verification URL

If you chose to verify that the changes were legitimate by requesting confirmation from the user, it is important to use the URL we provide as we can use this data to improve how we detect account takeover.

We recommend that you email the previously listed email for confirmation if the email address has been updated as part of the account changes.

The verification URL is given in the change response. Making a GET request on this URL will inform the ravelin system of updates to the verfication status. There are a number of query parameters that may be used. They are as follows:

Query Parameter Description
verified This is a required field. This can be set to true or false. It indicates if the change is verified to be made by the customer (true) or if the change is not made by the customer (false)
r r is an optional parameter that will tell Ravelin to return a redirect to the client. The expectation here is that you may construct a simple, static page on your domain thanking the customer for verifying a change. You can put the Ravelin Verification URL directly in an email and when the customer clicks it they will be directed to this page. In this way it will keep branding and domains consistent for the customer experience.
id This parameter is prepopulated, it contains an ID that allows Ravelin to tie this verification to the particular change. This must be included and should not be changed
all all is an optional parameter that will verify all the changes from a particular response. This can be set to true or false. For example, if a customer is updating their email from a new device on a different IP we could have 3 changes in one event: DEVICE, IP_LOCATION and EMAIL. By adding all=true against any one of these verificationURLs, the endpoint will verify all 3.

These query parameters may be added to the end of the URL. This is what a complete request may look like:

GET https://api.ravelin.com/v2/change/verify?id=Y2xpZW50SWTCp2N1c3RvbWVySWTCp2NoYW5nZUlk
    &verified=true
    &all=true
    &r=https://www.ravelin.com

The highlighted parameters are examples of what would be added by you. When the r query parameter is set, the response will contain a 303 status with the contents of the r query parameter in the Location header. This will redirect the browser to that URL. This allows you to host a static result page on your domain thanking the user for this verification while still only needing to put this link into an email.

Verification Patterns

The verification process requires more complexity than most aspects of the Ravelin integration. This includes emailing customers and, optionally, providing an API within your backend in which the customers are able to verify changes. We recommend contacting Ravelin to discuss your options.

To get the most out of change verification, you need to know the result of the verification within your own backend. This allows you to take immediate further action as well as reassuring customers as the link in the email will be within your domain. To do this we recommend you set up an endpoint in your system which accepts the verification request from the email. You can then use the VerifciationURL we provide to forward that response to us.

If the customer clicks on the link indicating they don’t recognize a change, we recommend you reset the customers password, locking them (and any intruder) out of the account. At the same time, send them a password reset email so they can recover the account. We suggest you verify if the email associated with the customer account has been changed recently. If the email has been changed, we advise you send any password reset information to the previously used email. Then the customer can be redirected to a page informing them of what has happened and the next steps that they should take to recover the account

If the verification comes back as a true change, no further action against the customer account is required. You can forward them to a page thanking them for the feedback.

In both cases the result of the verification must be forwarded to us.

Suggestion #2

If your team can not prioritize the construction of a backend API, you can embed the links we provide directly into the email. This will allow us to know about verification status without the need for a backend api on your part.

That said, you will have to construct a landing page for both the yes and no verification requests that Ravelin can redirect the user to. These can be simple static pages that must be hosted on your domain.

You should add a redirect on to the links for both verifying yes and no with the appropriate page.

The page indicating an unrecognized change should include information on resetting their password and a suggestion to contact customer support immediately. When the customer clicks this link we will use this information to update the customers account which will greatly increase the likelihood any login attempt on this account will be blocked by the Ravelin system if we receive no indication that the account has been reclaimed.

The page indicating a change was recognized should simply thank them for their feedback.

Change Values

The change values in the response define what change is actually being made and what the previous value was before the change. They are defined as follows:

{
  "device":{
      "deviceId": "string",
      "deviceType": "string",
      "deviceManufacturer": "string",
      "deviceModel": "string",
      "deviceOS": "string",
      "ipAddress": "string",
      "userAgent": "string",
      "timestamp": "string"
  },
  "ipAddress":{
      "ipAddress": "string",
      "timestamp": "string",
      "city": "string",
      "countryISO": "string",
      "continentISO": "string",
      "isp": "string",
      "ipAddrId": "string"
  },
  "email":{
      "email": "string",
      "timestamp": "string"
  },
  "password":{
      "timestamp": "string"
  },
  "telephone":{
      "telephone": "string",
      "telephoneCountry": "string",
      "timestamp": "string"
  },
  "deliveryAddress":{
      "streetAddress1": "string",
      "streetAddress2": "string",
      "addressLocality": "string",
      "addressRegion": "string",
      "addressCountry": "string",
      "addressCountryISO": "string",
      "postOfficeBoxNumber": "string",
      "postalCode": "string",
      "latitude": 0.0,
      "longitude": 0.0,
      "timestamp": "string",
      "locationId": "string"
  },
  "billingAddress":{
      "streetAddress1": "string",
      "streetAddress2": "string",
      "addressLocality": "string",
      "addressRegion": "string",
      "addressCountry": "string",
      "addressCountryISO": "string",
      "postOfficeBoxNumber": "string",
      "postalCode": "string",
      "latitude": 0.0,
      "longitude": 0.0,
      "timestamp": "string",
      "locationId": "string"
  }
}