NAV Navbar
Frontend Backend (Ruby) Backend (PHP)

Introduction

Contact State is a regulatory technology platform specifically designed to build trust in two-sided markets like lead generation and affiliate marketing.

Contact State Certify allows Data Sellers to generate Certificates that serve as a record of provenance for consumer data, and then pass these certificates onto Data Buyers. This provides a trusted reference point for Data Buyers and Data Sellers.

Certify

The Certify product integration is the easiest way to generate trusted Certificates.

Certificates are generated in a two-part, real time process:

  1. Generation (frontend): The cscertify javascript library (loaded in the consumers browser) attaches itself to the form submit handler and gets triggered when a user presses the submit button. This makes a call to Contact State and a Claim URL is returned. The frontend then has to pass this Claim URL to the backend.

  2. Claiming (backend): The Certificate is claimed by making a POST request to the Claim URL with the correct Secret Key. The claiming process returns a Certificate URL which can be passed to the Data Buyer, along with other form data. Certificates are claimed for a particular Data Buyer and once claimed will be visible in the Data Buyers Contact State platform.

Example integration code can be found in this document and additionally at https://github.com/contactstate/certify-integration-examples

Credentials

In order to continue with the integration you will need credentials configured within Contact State.

To get your credentials please email support@contactstate.com, supplying the landing page URL Contact State Certify will be integrated on.

  1. Landing Page ID - Provided by Contact State. This identifies the landing page that your form is setup on.

  2. Secret Key - Provided by Contact State. This is used to sign claim requests on behalf of a particular Data Buyer. Important: A Secret Key is unique to a Data Buyer. If you are claiming Certificates for multiple Data Buyers with Contact State you will need multiple secret keys.

Standard Frontend Integration

There are two methods of Frontend integration: Standard and Advanced. Standard is for simple HTML forms that submit through the form action, without using javascript to validate or submit data.

<!-- Embed this code on every page of your website -->
<script>
  (function (w,d,s,o,f,js,fjs) {
    w['ContactStateCertify']=o;w[o] = w[o] || function () { (w[o].q = w[o].q || []).push(arguments) };
    js = d.createElement(s), fjs = d.getElementsByTagName(s)[0];
    js.id = o; js.src = f; js.async = 1; fjs.parentNode.insertBefore(js, fjs);
  }(window, document, 'script', 'cscertify', 'https://js.contactstate.com/certify-latest.js'));
  cscertify('init', { landing_page_id: 'REPLACE_ME_WITH_YOUR_LANDING_PAGE_ID' });
  // In the standard integration, we can attach Contact State directly to the form using the attach call
  cscertify('attach', { form_id: 'REPLACE_ME_WITH_YOUR_FORM_ID' });
</script>

To complete this integration you will need:

  1. Landing Page ID - The Landing page ID you will have received from Contact State.

  2. Form ID - The HTML element ID of the form you wish to attach to. In the following example snippet <form id="testForm" action="/backend" method="POST"> the form_id is testForm.

Attaching to the form

The Standard integration works through a single call to cscertify('attach', args), passing in the form ID as an argument.

The frontend embed code should be placed at the bottom of each page on the website. The Contact State javascript embed will now work unobtrusively with your form.

The cscertify javascript will append a new hidden element to your form automatically called contact_state_claim_cert_url which will be submitted with the form.

Loading, success and failure callbacks

You can customise the integration further through these optional callbacks:

<script>
  // (function (w,d,s...
  // cscertify('init'...
  cscertify('attach', { form_id: 'REPLACE_ME_WITH_YOUR_FORM_ID', 
    loading: function() {
      // This gets called before the submission to Contact State
      document.getElementById('submit-btn').value = 'Verifying with Contact State...';
    }, 
    success: function(claimUrl) {
      // This gets called after the Contact State submission (either success or failure),
      // and just before the form gets submitted as normal.
      document.getElementById('submit-btn').value = 'Submitting with Claim URL...';

      console.log('Claim URL is ' + claimUrl);
    },
    failure: function(err) {
      // The form will be automatically submitted if there is an error!
      // However, this callback is useful for debugging
      document.getElementById('submit-btn').value = 'Submitting without Claim URL...';

      console.log('Something went wrong with the Contact State submission: ' + err);
    }
  });
</script>

loading: This callback is executed before the submission to Contact State. We recommend setting a loading state on your form.

success: This callback is executed after the Contact State submission, for successful requests, and just before the form submission.

failure: This callback is executed on error, when something has gone wrong with the Contact State submission, and just before the form submission. An error object is passed to the function as the first argument with more detail.

Error handling

If the Contact State service is unavailable the form submission process will continue as normal, without the hidden field contact_state_claim_cert_url being submitted.

Additionally, further information on the error is provided in the error callback.

Advanced Frontend Integration

The Advanced integration works in a similar fashion to the standard integration, except you have to manually trigger a call to cscertify('send') in the correct place.

<!-- Embed this code on every page of your website -->
<script>
  (function (w,d,s,o,f,js,fjs) {
    w['ContactStateCertify']=o;w[o] = w[o] || function () { (w[o].q = w[o].q || []).push(arguments) };
    js = d.createElement(s), fjs = d.getElementsByTagName(s)[0];
    js.id = o; js.src = f; js.async = 1; fjs.parentNode.insertBefore(js, fjs);
  }(window, document, 'script', 'cscertify', 'https://js.contactstate.com/certify-latest.js'));
  cscertify('init', { landing_page_id: 'REPLACE_ME_WITH_YOUR_LANDING_PAGE_ID' });
</script>

To complete this integration you will need:

  1. Landing Page ID - The Landing page ID you will have received from Contact State.

  2. Form ID - The HTML element ID of the form you wish to attach to. In the following example snippet <form id="testForm" action="/backend" method="POST"> the form_id is testForm.

Configuring the javascript submit handler

The frontend embed code should be placed at the bottom of each page on the website.

In the javascript form submit handler, before form submission, a call will need to be made to cscertify('send') to retrieve the Claim URL. This URL should then be added to the submit payload and the form should be submitted as normal.

// And then you can put this code in your form submit handler

// Option 1. With callbacks
cscertify('send', { form_id: 'REPLACE_ME_WITH_YOUR_FORM_ID', 
  loading: function() {
    // This gets called before the submission to Contact State
    document.getElementById('submit-btn').value = 'Verifying with Contact State...';
  }, 
  success: function (claimUrl) {
    document.getElementById('submit-btn').value = 'Submitting form...';
    console.log("Page script: Claim URL is %s", certUrl);
    // Ajax request to backend to submit
  }, 
  failure: function (err) {
    console.error('Page script: There was an error!', err)
    // Ajax request to backend to submit
  } 
});

// Option 2: Using Promises (no loading state)
cscertify('send', { form_id: 'REPLACE_ME_WITH_YOUR_FORM_ID' })
.then(function (claimUrl) {
  console.log("Page script: Claim URL is %s", claimUrl);
  // Ajax request to backend to submit
})
.catch(function (err) {
  console.error('Page script: There was an error!', err)
  // Ajax request to backend to submit
});

// Option 2: Using Promises (with a loading state)
new Promise(function (resolve, reject) {
  // Update the loading UI
  document.getElementById('submit-btn').disabled = true;
  resolve()
}).then(function() {
  return cscertify('send', { form_id: 'REPLACE_ME_WITH_YOUR_FORM_ID' });
}).then(function (claimUrl) {
  // Debugging
  console.log("Page script: Cert URL is %s", claimUrl);

  // Updating the UI for the user
  document.getElementById('submit-btn').disabled = false;

  // Ajax request to backend
})
.catch(function (err) {
  console.error('Page script: Augh, there was an error!', err)
  document.getElementById('submit-btn').disabled = false;

  // Ajax request to backend to submit
});

Loading, success and failure callbacks

The Advanced integration is controlled through these callbacks:

loading: This callback is executed before the submission to Contact State. We recommend setting a loading state on your form.

success: This callback is executed after the Contact State submission, for successful requests, and just before the form submission.

failure: This callback is executed on error, when something has gone wrong with the Contact State submission, and just before the form submission. An error object is passed to the function as the first argument with more detail.

Error handling

If the Contact State service is unavailable you can catch the failure (either by promise or callback).

We recommend submitting your form as normal in these blocks.

Advanced Frontend Integration jQuery example

This is an example of an advanced integration using jQuery.

var form = $('form');
form.on('submit', function(e) {
  e.preventDefault();

  // Own logic, Validations etc.
  // ...

  // Submit the form to Contact State to receive a Certificate claim URL
  cscertify('send', {
    form_id: 'REPLACE_ME_WITH_YOUR_FORM_ID',
    loading: function() {
      $('#submit-btn').val('Verifying with Contact State...');
    },
    success: function(claim_url) {
      // You need to pass claim_url to your server backend
      // In this example we're adding it back to the form,
      // then serializing the form and submitting it in an ajax request
      $('<input>').attr({
        type: 'hidden',
        id: 'contact_state_claim_cert_url',
        name: 'contact_state_claim_cert_url',
        value: claim_url
      }).appendTo(form);

      // Set a status for the user
      $('#submit-btn').val('Submitting form...');

      // Submit to your backend as normal
      // The payload will now also include a field called
      // 'contact_state_claim_cert_url' with the Claim URL
      $.ajax({
        type : 'POST',
        data: form.serialize(),
        url: '/path/to/backend',
        dataType : 'json',
        success: function(res){}
      });
    },
    failure: function() {
      // Set a status for the user
      $('#submit-btn').val('Submitting form...');

      // We've failed to get a Contact State Claim URL
      // It's a good idea to submit your form anyway
      // so that the form data is not lost
      $.ajax({
        type : 'POST',
        data: form.serialize(),
        url: '/path/to/backend',
        dataType : 'json',
        success: function(res){}
      });
    }
  });
});

Widgets

We have provided a number of widgets which can be used to give the consumer confidence that their journey is protected by Contact State.

Enabling these is simply a case of adding cscertify('widget'); to the embed code, and then putting the appropriate <div> container in the correct place.

<script>
  (function (w,d,s,o,f,js,fjs) {
    w['ContactStateCertify']=o;w[o] = w[o] || function () { (w[o].q = w[o].q || []).push(arguments) };
    js = d.createElement(s), fjs = d.getElementsByTagName(s)[0];
    js.id = o; js.src = f; js.async = 1; fjs.parentNode.insertBefore(js, fjs);
  }(window, document, 'script', 'cscertify', 'https://js.contactstate.com/certify-latest.js'));
  cscertify('init', { landing_page_id: 'REPLACE_ME_WITH_YOUR_LANDING_PAGE_ID' });
  // Append the following line to the standard or advanced embed code
  cscertify('widget');
</script>

Protected by Contact State widget

This widget is designed to sit on each page of the Seller website or form. The bottom text can be turned off by passing 'data-text="false"' to the element.

<!-- Protected by Contact State widget -->
<div id="contact-state-protected-by-widget"></div>
<!-- Without bottom text -->
<div id="contact-state-protected-by-widget" data-text="false"></div>

Privacy notice

It's good practice to inform the consumer that Contact State is operating on the form before they press the submit button.

By including the <div> container in the right place, Contact State can automatically inject this text.

Here's an example:

<!-- Privacy notice -->
<div id="contact-state-privacy-notice"></div>

Thank you page

This widget is designed to sit on the "thank you" page of the website, after the consumer has completed the form and a Certificate has been generated.

<!-- Thank you widget -->
<div id="contact-state-thanks-widget"></div>

Backend Integration

The goal of this step is to turn a Claim URL into a Certificate URL which can then be passed to the Data Buyer. Claiming a Certificate is mandatory before any Contact State scoring is performed on the data.

Example integration code can be found in this document and additionally at https://github.com/contactstate/certify-integration-examples

To complete this integration you will need:

  1. Secret Key - Provided by Contact State. This is used to sign claim requests on behalf of a particular Data Buyer. Important: A Secret Key is unique to a Data Buyer. If you are claiming Certificates for multiple Data Buyers with Contact State you will need multiple Secret Keys.

  2. A Claim URL - Passed from the frontend through either a Standard or Advanced integration.

Claiming a Certificate

To claim a Certificate, a POST request needs to be made to the Claim URL, passing in the secret key in the request body in a data element called secret_key.

In a Standard integration, on form submission, your form backend will receive a Certificate Claim URL in a field called contact_state_claim_cert_url.

In an Advanced integration, what this field is called it determined by you, although we would recommend calling it contact_state_claim_cert_url.

See the Ruby and PHP examples provided.

Successful response

A successful claim will return with a HTTP status code of 201 and the following JSON:

{ "cert_url": "https://cert.contactstate.com/certs/:id" }

The cert_url value is the Certificate URL. This can be saved and passed along to the Data Buyer with the rest of the form data.

Error handling

Errors will be returned with a HTTP status code of 500 and the following JSON:

{ "error": { "message": "Error message" } }

Top tip: Certificates must be claimed within 30 seconds of generation.

# Set your secret key in the variable below
# Your secret key is provided by Contact State
secret_key = 'REPLACE_ME_WITH_YOUR_SECRET_KEY'

# Claim URL is passed in from the form submission
claim_url = params[:contact_state_claim_cert_url]

if claim_url.present?
 # Make a POST request to claim the Certificate
 response = HTTParty.post(claim_url,
   body: {
     secret_key: secret_key
   }.to_json,
   headers: { 'Content-Type' => 'application/json' }
 )

  # Get the certificate URL from the response
  # This should be stored and passed along to the Data Buyer
 certificate_url = JSON.parse(response.body)['cert_url']
 puts "The certificate can be viewed at #{certificate_url}"
else
 # If we get here something has gone wrong with the javascript embed
 raise "No claim URL received" 
end
<?php
  # Set your secret key in the variable below
  # Your secret key is provided by Contact State
  $secret_key = 'REPLACE_ME_WITH_YOUR_SECRET_KEY';

  # Claim URL is passed in from the form submission
  $claim_url = $_POST['contact_state_claim_cert_url'];

  if(isset($claim_url) && $claim_url != '') {
    $content = json_encode(array('secret_key' => $secret_key));

    $curl = curl_init($claim_url);
    curl_setopt($curl, CURLOPT_HEADER, false);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/json"));
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $content);

    # Make a POST request to claim the Certificate
    $json_response = curl_exec($curl);
    $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);

    if ($status != 201) {
      die("Error: call to URL $claim_url failed");
    }
    curl_close($curl);

    # Get the Certificate URL from the response
    # This should be stored and passed along to the Data Buyer
    $response = json_decode($json_response, true);
    $certificate_url = $response['cert_url'];
    echo "The certificate URL is $certificate_url";
  } else {
    # If we get here something has gone wrong with the javascript embed
    die('Claim URL not set');
  }
?>
# Response JSON on success

{
  "cert_url": "https://cert.contactstate.com/certs/:id"
}

CRM & Database Integration

Data Sellers and Data Buyers can pull data from Contact State into their CRM solution to assist with internal reporting.

Data Buyers can push data from their CRM solution into Contact State to unlock more powerful reporting in the Contact State Platform.

Storing the Certificate URL

We recommend both Data Sellers and Data Buyers store the Certificate URL so they both have the same point of reference when discussing a data record. Storing the Certificate URL is an important prerequisite to further CRM integration for Data Buyers.

Data Sellers can simply store the Certificate URL once it has been generated in their CRM or database solution.

Data Buyers can store the Certificate URL in their own CRM solution, alongside the other consumer data that has been sent from the Data Seller.

We recommend creating a new field CRM or database field called Contact State Certificate URL to store the Certificate URL, which is at least 72 characters long.

Pulling Certificate Data

There are a number of Certificate attributes a Data Seller and Data Buyer may wish store in their own CRM systems to assist with internal reporting, like "scoring status".

Certificates are available as JSON by appending .json to a certificate URL. For example:

https://cert.contactstate.com/certs/ac5e67f3-d280-4209-a2d6-06474d3eae23.json

Important: Certificates are usually scored within one minute, but this process could take several minutes. Certificates sit in a "claimed" state until scoring has been completed. Data Sellers should not wait for scoring to complete to send the Consumer data and the Certificate as we make no guarantees on how long the scoring process will take.

<?php
$cert_url = 'https://cert.contactstate.com/certs/ac5e67f3-d280-4209-a2d6-06474d3eae23.json';

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $cert_url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$cert_json = curl_exec($curl);
curl_close($curl);
$cert = json_decode($cert_json, true);

echo "Cert ID is " . $cert['data']['id'];
echo "Scoring status is " . $cert['data']['attributes']['status'];

?>
cert_url = 'https://cert.contactstate.com/certs/ac5e67f3-d280-4209-a2d6-06474d3eae23.json'

response = HTTParty.get(cert_url, format: :plain)
cert = JSON.parse(response, symbolize_names: true)

puts "Cert ID is #{cert[:data][:id]}"
puts "Scoring status is #{cert[:data][:attributes][:status]}"
{
  "data": {
  "id": "f7cb639a-2e90-4703-b35c-f416dd68573e",
  "type": "contact-state-certificate",
  "attributes": {
    "url": "https://cert.contactstate.com/certs/f7cb639a-2e90-4703-b35c-f416dd68573e",
    "status": "certified",
    "scored_at": "2019-10-05T15:16:33.577+01:00",
    # ...
    }
  }
}

Pushing Sales Data (Data Buyers only)

Pushing sales data to Contact State from a CRM system

To complete this integration you will need:

  1. Certificate URL: The Certificate to which the sent data will be applied. You should have completed the "Storing the Certificate URL" step.

  2. Secret Key: This key authorises the CRM system to send data to the Certificate. Contact State will supply you with this.

Data fields

# Example method to map an internal CRM status to
# a status that Contact State will accept.
def internal_status_to_contact_state_status(internal_status)
  {        
    'Unassigned' => 'NEW',
    'With advisor' => 'TRANSFER',
    'Quoted' => 'QUOTE',
    'Sale' => 'SOLD',
    'Wrong product' => 'INELIGIBLE',
    'Not Interested' => 'NOT_INTERESTED',
    'Cancelled' => 'CANCELLED',
    'Could not contact' => 'NO_CONTACT',
    'Invalid' => 'INVALID',
    'Wrong phone' => 'INVALID_PHONE',
    'Wrong email' => 'INVALID_EMAIL',
    'Hoax' => 'INVALID_HOAX',
    'Dupe' => 'DUPLICATE',
    'Test' => 'TEST'
  }.fetch(internal_status, 'NEW') # default to 'NEW'
end

# HTTP POST call to push data to Contact State
def update_contact_state(crm_record)
  secret_key = 'REPLACE_ME_WITH_YOUR_SECRET_KEY'

  HTTParty.post(crm_record[:cert_url],
    body: {
      secret_key: secret_key,
      status: internal_status_to_contact_state_status(crm_record[:status]),
      status_at: crm_record[:sold_at],
      status_by: crm_record[:sold_by],
      received_at: crm_record[:received],
      internal_identifier: crm_record[:id],
      internal_status: crm_record[:status],
      internal_status_at: crm_record[:sold_at],
      notes: crm_record[:notes],
      sale_sold_at: crm_record[:sold_at],
      sale_sold_by: crm_record[:sold_by],
      sale_currency: crm_record[:currency],
      sale_revenue: crm_record[:revenue],
      sale_lead_cost: crm_record[:cpl],
      sale_costs: crm_record[:costs],
      sale_gross_profit: crm_record[:profit],
    }.to_json,
    headers: { 'Content-Type' => 'application/json' }
  )
end

# Example CRM/database record
# Remember to encode the datetimes as ISO8601!
# In the example below the dates contain British Summer Time zone info
crm_record = {
  cert_url: 'https://cert.contactstate.com/certs/ac5e67f3-d280-4209-a2d6-06474d3eae23',
  id: 'QWERTY1',
  received: '2020-01-10T15:15:30+0100',
  status: 'Sale',
  sold_at: '2020-01-15T12:00:45+0100',
  sold_by: 'John S',
  notes: 'Lovely stuff',
  currency: 'GBP',
  revenue: '1000.90',
  cpl: '35.15',
  costs: '20.99',
  profit: '944.76'
}

# Call the update
# This would be triggered from a CRM 'create' or 'update' hook
response = update_contact_state(crm_record)
<?php

# Example function to map an internal CRM status to
# a status that Contact State will accept.
function internal_status_to_contact_state_status($internal_status) {  
  $lookup = array(
    'Unassigned' => 'NEW',
    'With advisor' => 'TRANSFER',
    'Quoted' => 'QUOTE',
    'Sale' => 'SOLD',
    'Wrong product' => 'INELIGIBLE',
    'Not Interested' => 'NOT_INTERESTED',
    'Cancelled' => 'CANCELLED',
    'Could not contact' => 'NO_CONTACT',
    'Invalid' => 'INVALID',
    'Wrong phone' => 'INVALID_PHONE',
    'Wrong email' => 'INVALID_EMAIL',
    'Hoax' => 'INVALID_HOAX',
    'Dupe' => 'DUPLICATE',
    'Test' => 'TEST'
  );

  if(isset($lookup[$internal_status])) {
    return $lookup[$internal_status];
  } else {
    return 'NEW'; # default to 'NEW'
  }
}

# HTTP POST call to push data to Contact State
function update_contact_state($crm_record) {
  $secret_key = 'REPLACE_ME_WITH_YOUR_SECRET_KEY';

  $content = json_encode(array(
    'secret_key' => $secret_key,
    'status' => internal_status_to_contact_state_status($crm_record['status']),
    'status_at' => $crm_record['sold_at'],
    'status_by' => $crm_record['sold_by'],
    'received_at' => $crm_record['received'],
    'internal_identifier' => $crm_record['id'],
    'internal_status' => $crm_record['status'],
    'internal_status_at' => $crm_record['sold_at'],
    'notes' => $crm_record['notes'],
    'sale_sold_at' => $crm_record['sold_at'],
    'sale_sold_by' => $crm_record['sold_by'],
    'sale_currency' => $crm_record['currency'],
    'sale_revenue' => $crm_record['revenue'],
    'sale_lead_cost' => $crm_record['cpl'],
    'sale_costs' => $crm_record['costs'],
    'sale_gross_profit' => $crm_record['profit']
  ));

  $curl = curl_init($crm_record['cert_url']);
  curl_setopt($curl, CURLOPT_HEADER, false);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-type: application/json'));
  curl_setopt($curl, CURLOPT_POST, true);
  curl_setopt($curl, CURLOPT_POSTFIELDS, $content);

  # Make a POST request to claim the Certificate
  $json_response = curl_exec($curl);
  $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);

  if ($status != 201) {
    die("Error: call to URL {$crm_record['cert_url']} failed");
  }
  curl_close($curl);

  # Get the Certificate URL from the response
  # This should be stored and passed along to the Data Buyer
  $response = json_decode($json_response, true);
  return $response;
}

# Example CRM/database record
# Remember to encode the datetimes as ISO8601!
# In the example below the dates contain British Summer Time zone info
$crm_record = array(
  'cert_url' => 'https://cert.contactstate.com/certs/ac5e67f3-d280-4209-a2d6-06474d3eae23',
  'id' => 'QWERTY1',
  'received' => '2020-01-10T15:15:30Z+0100',
  'status' => 'Sale',
  'sold_at' => '2020-01-15T12:00:45+0100',
  'sold_by' => 'John S',
  'notes' => 'Lovely stuff',
  'currency' => 'GBP',
  'revenue' => '1000.90',
  'cpl' => '35.15',
  'costs' => '20.99',
  'profit' => '944.76'
);

$response = update_contact_state($crm_record);

?>

It's possible to update the Certificate with the following fields. Please note, the only required filed is 'Status', the rest are optional. This API should be called every time the status changes, or there is new information to send.

Field
Description
Status
status (String)
The Contact State sales status. Please find a list of available statuses in the appendix.
Status at
status_at (ISO 8601 timestamp)
The time that the Contact State sales status changed.
Status by
status_by (String)
A string identifying the person that caused the status to change (e.g. the sales advisor).
Received at
received_at (ISO 8601 timestamp)
The time the consumer data was received by the CRM.
Internal identifier
internal_identifier (String)
The unique internal CRM ID. We recommend this is a numeric ID and not anything personally identifiable, like an email address.
Internal status
internal_status (String)
The CRM status as it exists in the Buyer's CRM. This is used for debugging status related issues.
Internal status at
internal_status_at (ISO 8601 timestamp)
The time that the CRM status in the Buyer's CRM system changed. This is used for debugging status related issues.
Notes
notes (String)
Any notes concerning the consumer data.
Sale sold at
sale_sold_at (ISO 8601 timestamp)
The time the sale was made.
Sale sold by
sale_sold_by (String)
A string identifying the person that made the sale.
Sale currency
sale_currency (ISO 4217 currency code)
Currency the sale happened in. Defaults to GBP.
Sale revenue
sale_revenue (Decimal as string)
Revenue attributed to the sale. e.g. '99.99'
Sale lead cost
sale_lead_cost (Decimal as string)
CPL for this sale. e.g. '30.00'
Sale costs
sale_costs (Decimal as string)
Any other costs associated with this lead. e.g. '0.99'
Sale gross profit
sale_gross_profit (Decimal as string)
Gross profit for this lead. Defaults to revenue - costs but can be explicitly set in this field.

Sending a push

A POST request needs to be made to the Certificate URL. For example

POST https://cert.contactstate.com/certs/ac5e67f3-d280-4209-a2d6-06474d3eae23

with a body that conatins a secret key and then a list of fields to be updated.

On success the endpoint will return an HTTP 201 and a body containing the Certificate attributes.

Error handling

Errors will be returned with a HTTP status code of 500 and the following JSON:

{ "error": { "message": "Error message" } }

CRM triggers

Contact State can easily work with the majority of CRM systems on the market.

Most CRM systems provide a mechanism to subscribe or hook into CRM lifecycle events (e.g. create, update) and trigger an action. On each of these events a call to Contact State can be made, sending along an updated lead status.

We recommend sending at least two updates:

  1. On create: When the lead is first received the Internal ID, Received At time and initial Status are sent.
  2. On update: When the Status changes both the Status and Notes fields get updated too.

If you have a custom in-house CRM, you will need to get your development team to create this functionality. If you're using an off the shelf solution then please consult their documentation.

Support

Please email support@contactstate.com for integration support.

Appendix

Certificates

Contact State believes that all data transfer in the future will have an accompanying Certificate that records where that data came from and documents the environment it was generated in.

The output of all Contact State integrations is a Certificate. Certificates look like this

An example Contact State Certificate

and are accessible through URLs that look like this

https://cert.contactstate.com/certs/534ede1d-9430-4bc9-8aa5-6626d2ab5a12

Certificates are designed to be passed from Data Seller to Data Buyer and serve as a record of a particular consumer transaction.

Data privacy

Contact State is designed with privacy and security by default.

All data that is sent to us is hashed with the SHA-256 Cryptographic Hash Algorithm.

In a Certify integration the data is hashed client side in a browser before it is sent to our servers. We never see plain text customer data and all data transfer is secure and happens over TLS 1.2.

A hashing algorithm is a deterministic, one way transformation of data that always produces the same output for a given input. For example, the string "hello" produces the SHA-256 hash of 2cf24dba5fb0a30e26e83b2ac 5b9e29e1b161e5c1fa7425e73 043362938b9824

Contact State is unable to see the original input. Instead, Contact State looks for patterns in the data to power features on the platform.

CRM Sales Statuses

The lead statuses that can be sent to Contact State are:

State Description
NEW New lead
TRANSFER Lead is with an advisor
QUOTE The lead has been quoted
SOLD The lead has been sold to
INELIGIBLE The lead is outside of product criteria
NOT_INTERESTED The lead was not interested
CANCELLED The lead cancelled
NO_CONTACT The lead was uncontactable
INVALID The lead data was invalid
INVALID_PHONE The phone number was invalid
INVALID_EMAIL The email was invalid
INVALID_HOAX The lead was a hoax
DUPLICATE The lead is a duplicate
TEST The lead was a test