VoilaNorbert API Reference

API Endpoint

Our API follows the REST principle.

All API requests must be made over HTTPS. Call made otherwise will fail.

API Endpoint

The API endpoint is https://api.voilanorbert.com/2016-01-04/.

Authentication

Authentication against our API is performed via HTTP Basic Auth.

Use the API key in show in Integrations[link] or that we also send you by email as the password. You can pass any string you want as the username (it’s ignored).

any_string:{secure_token}

An Python example:

requests.get('https://api.voilanorbert.com/2016-01-04/contacts/', auth=('any_string', '{secure_token}'))

How do we determine your credits

We only deduct 1 credit each time we return a successful result from a search, i.e. when we find at least one email.

Every time you lookup an email, a contact is created. If you search a second time for that same contact, we won’t deduct a second credits, except if you removed that contact from your account.

API Rate Limit

By default, we limit the number of requests to 120 requests per minutes. Some endpoints allow for less requests, like the search engine, to avoid overage.

The number of requests available and the time it will reset are given in the response of each requests. We use the standard X-RateLimit headers as follows:

X-RateLimit-Remaining: 100
X-RateLimit-Limit: 120
X-RateLimit-Reset: 1466368960

The 120 requests/minute is the default. We tell you if it is not in each endpoint. If you need something faster ask us.

HTTP Status Code

We use the traditional HTTP status codes to indicate the state of your request.

  • Codes in the 2xx range indicate success

  • Codes in the 4xx range indicate an error from your side

  • Codes in the 5xx range indicate a fatal error on our side

Some of the more often used status codes are:

For success :

  • 200 : Everything is good, with data provided

  • 202 : Processing the data submitted

  • 204 : No content (often returned with DELETE requests)

For errors :

  • 400 : Bad request, often along with a form submission

  • 401 : Account not found, when authenticating

  • 402 : No credits left, returned on the search page

  • 429 : Too many requets made in the timeframe indicated

Errors

We do our best to provide you with more informations whenever possible.

When we return additional details the content will be a JSON message with the following elements:

code
integer

It's the same value as the HTTP Status Code

error
string

Contains a more advanced message for the corresponding error.
For example : Too many requests in the allowed time frame (120 requests per minutes).

{
  "code": 429,
  "error": "Too many requests in the allowed time frame (120 requests per minutes)"
}

When you submit a form (POST), if there are errors with the data submitted the JSON response will be more detailed:

{
  "email": [
    "Invalid password or account does not exists."
  ]
}

Search Endpoint

Resource

POST /search/name
RequestsPythonCurl
Body
import requests, time

# Here's a quick sample Python code that implements the algorithm :

API_TOKEN = 'abcde'

req = requests.post(
  'https://api.voilanorbert.com/2016-01-04/search/name',
  auth=('any_string', API_TOKEN),
  data = {
      'name': 'Cyril Nicodeme',
      'domain': 'reflectiv.net'
  }
)

if req.status_code != 200:
  return None

result = req.json()

while True:
  contact_r = requests.get('https://api.voilanorbert.com/2016-01-04/contacts/{0}'.format(result['id']), auth=('any_string', API_TOKEN))
  if contact_r.status_code == 200:
      contact = contact_r.json()

  if contact['searching'] is False:
      # TODO : Update your database here
      if contact['email']:
          # Email found !
          print "Found email : {0} with score : {1}".format(contact['email']['email'], contact['email']['score'])
      else:
          print "Email not found!"

      break
  time.sleep(10)
Responses200400
Headers
Content-Type: application/json
Body
{
  "company": {
    "description": null,
    "is_done": true,
    "keywords": [
      "Some",
      "Keywords",
      "For",
      "This",
      "Domain"
    ],
    "logo": "https://logo.clearbit.com/example.com",
    "name": "Example Website",
    "raw_url": "example.com",
    "title": "Example.com super website !",
    "url": "http://www.example.com"
  },
  "created": 1465371124000,
  "email": {
    "avatar_url": "https://secure.gravatar.com/avatar/abcde&s=128",
    "email": "email@example.com",
    "is_done": true,
    "score": 100
  },
  "id": 12345,
  "lists": [],
  "name": "Fake User",
  "owner": {
    "admin": true,
    "avatar_url": "https://secure.gravatar.com/avatar/54321?d=mm&s=128",
    "email": "user@voilanorbert.com",
    "firstname": "Cyril",
    "language": "en",
    "name": "Cyril"
  },
  "searching": false,
  "status": "LEAD"
}
Headers
Content-Type: application/json
Body
{
  "name": [
    "This field is required."
  ]
}
Body
curl -X POST https://api.voilanorbert.com/2016-01-04/search/name \
 -u any_string:{secure_token} \
 -d domain="example.com" \
 -d name="Fake User"
Responses200400
Headers
Content-Type: application/json
Body
{
  "company": {
    "description": null,
    "is_done": true,
    "keywords": [
      "Some",
      "Keywords",
      "For",
      "This",
      "Domain"
    ],
    "logo": "https://logo.clearbit.com/example.com",
    "name": "Example Website",
    "raw_url": "example.com",
    "title": "Example.com super website !",
    "url": "http://www.example.com"
  },
  "created": 1465371124000,
  "email": {
    "avatar_url": "https://secure.gravatar.com/avatar/abcde&s=128",
    "email": "email@example.com",
    "is_done": true,
    "score": 100
  },
  "id": 12345,
  "lists": [],
  "name": "Fake User",
  "owner": {
    "admin": true,
    "avatar_url": "https://secure.gravatar.com/avatar/54321?d=mm&s=128",
    "email": "user@voilanorbert.com",
    "firstname": "Cyril",
    "language": "en",
    "name": "Cyril"
  },
  "searching": false,
  "status": "LEAD"
}
Headers
Content-Type: application/json
Body
{
  "name": [
    "This field is required."
  ]
}

POST/search/name

Search emails are based on the full name plus the domain or company name.

When your account does not have sufficient credits an HTTP status code of 402 is returned.

Also, take into consideration that we check the domain for its validity. So even if you provide a correct name+domain set, we may return a HTTP status code of 400 for the domain if we can’t locate it.

Due to the complex work involved, this endpoint is limited to 120 requests per minutes, and up to 3,000 requests per day max.

You can provide a callback url using a webhook parameter. We will send a POST request to this URL and expect a status code of 2xx. If we get something else, we will try again 2 more times incrementing the interval 30 seconds between each of the requests. After the third request, the server will stop trying.

The searching boolean returned by the server will let you know if the server is searching for that contact of it has already been found. You can then try to send a GET request to the contact (GET /contact/{id}) to get the same response as this request, and wait for the searching parameter to be true.

The contact object returned also includes email data. When searching, this data is set to null. Once the search is done, if we found the corresponding email, the email becomes an object containing information including the email value and the score related to this email.

The score value can have multiple values :

  • 100 : We found the email and checked it against the mail server and it appears to be valid

  • 80 : We found the email but we were unable to validate it against the mail server.

  • 5 : We found the email using outside services but we can’t verify its validity.

A good rule of thumb is to send the POST request to the search endpoint, then do a while true to request GET /contacts/{id} until searching is true.

URI Parameters
HideShow
name
string (required) Example: "Larry Page"

Full name of the person to search.

domain
string (required) Example: "Google.com"

The domain of the company. (Either domain or company is required)

company
string (required) Example: "Google"

The name of the company. (Either domain or company is required)

webhook
string (optional) Example: "http://requestb.in/aaaaaa"

URL where the result will be POSTed

list_id
integer (optional) Example: 1

A List ID the contact will affected to.


Account

Resource

GET /account/
RequestsCurl
Body
curl https://api.voilanorbert.com/2016-01-04/account/ \
 -u any_string:{secure_token}
Responses200
Headers
Content-Type: application/json
Body
{
  "admin": true,
  "avatar_url": "https://secure.gravatar.com/avatar/54321?d=mm&s=128",
  "email": "user@voilanorbert.com",
  "firstname": "Cyril",
  "name": "Cyril",
  "language": "en",
  "api_token": "abcde"
}

GET/account/

Returns information about the current account.


Organization

Resource

GET /organization/
RequestsCurl
Body
curl https://api.voilanorbert.com/2016-01-04/organization/ \
 -u any_string:{secure_token}
Responses200
Headers
Content-Type: application/json
Body
{
"id": 1,
"company_name": "Voilanorbert",
"company_vat": null,
"address": "",
"zipcode": "90800",
"city": "BELFORT",
"country": "France",
"is_auto_renew": true,
"auto_renew_at": 10,
"auto_renew_quantity": 1000,
"cc_expires": 1575158400000,
"plan": {
  "credits": 10000,
  "id": 3,
  "name": "Advisor",
  "price": 249,
},
"is_yearly": false,
"next_payment": 1466899200000,
"credits": {
  "remains": 1234,
  "total": 12345
}
}

GET/organization/

Retrieve information about the organization.


Credits

Resource

GET /organization/credits/
RequestsCurl
Body
curl https://api.voilanorbert.com/2016-01-04/organization/credits \
 -u any_string:{secure_token}
Responses200
Headers
Content-Type: application/json
Body
{
  "remaining": 50,
  "total": 100
}

GET/organization/credits/

Retrieve the current remaining credits and the total available.


Contacts

Resource

GET /contacts/
RequestsCurl
Body
curl https://api.voilanorbert.com/2016-01-04/contacts/?order_by=-name&name=larry \
 -u any_string:{secure_token}
Responses200
Headers
Content-Type: application/json
Body
{
  "has_next": true,
  "has_prev": false,
  "page": 1,
  "pages": 1,
  "result": [
    {
      "company": {
        "description": null,
        "is_done": true,
        "keywords": [
          "Some",
          "Keywords",
          "For",
          "This",
          "Domain"
        ],
        "logo": "https://logo.clearbit.com/example.com",
        "name": "Example Website",
        "raw_url": "example.com",
        "title": "Example.com super website !",
        "url": "http://www.example.com"
      },
      "created": 1465371124000,
      "email": {
        "avatar_url": "https://secure.gravatar.com/avatar/abcde&s=128",
        "email": "second@example.com",
        "is_done": true,
        "score": 100
      },
      "id": 12345,
      "lists": [],
      "name": "Second User",
      "owner": {
        "admin": true,
        "avatar_url": "https://secure.gravatar.com/avatar/54321?d=mm&s=128",
        "email": "user@voilanorbert.com",
        "firstname": "Cyril",
        "language": "en",
        "name": "Cyril"
      },
      "searching": false,
      "status": "LEAD"
    },
    {
      "company": {
        "description": null,
        "is_done": true,
        "keywords": [
          "Some",
          "Keywords",
          "For",
          "This",
          "Domain"
        ],
        "logo": "https://logo.clearbit.com/example.com",
        "name": "Example Website",
        "raw_url": "example.com",
        "title": "Example.com super website !",
        "url": "http://www.example.com"
      },
      "created": 1465371184000,
      "email": null,
      "id": 12346,
      "lists": [],
      "name": "Fake User",
      "owner": {
        "admin": true,
        "avatar_url": "https://secure.gravatar.com/avatar/987654?d=mm&s=128",
        "email": "user@voilanorbert.com",
        "firstname": "Cyril",
        "language": "en",
        "name": "Cyril"
      },
      "searching": false,
      "status": "CONTACTED"
    }
  ],
  "total": 2
}

GET/contacts/

Return a list of all your contacts.

You can filter them using the following parameters:

URI Parameters
HideShow
ids
List of Integers (optional) Example: 1,2,3

List of ids to get an exact set of contacts

query
String (optional) Example: "larry"

A search query that will used against the name, email, domain and company name of the contacts

name
String (optional) Example: "larry"

A partial name of the contact

email
String (optional) Example: "@google.com"

A partial email of the contact

company
String (optional) Example: "goog"

A partial name of the company

found
Boolean (optional) Example: 1

Filter the result with only contacts found or all. Accepts true, 1 as “true” values

history
Boolean (optional) Example: 1

Returns only contacts that are available in the search history

lists
Integer/List of integers (optional) Example: 1,2

Filter the contacts that are in the given lists. Accepts one id or an array of ids.

created
string (required) Example: "2016

04-01 10:00" (String, optional) - Filter by creation date. Allow accept more advanced search when appending >, <, >=, <= to the date to find for before/after equal a specific date.

order_by
string (required) Example: "

-created" (String, optional) - Order by any specific field present in the contact. You can append - to reverse the order (DESC)


Resource

GET /contacts/
RequestsCurl
Body
curl https://api.voilanorbert.com/2016-01-04/contacts/12345 \
 -u any_string:{secure_token}
Responses200
Headers
Content-Type: application/json
Body
{
  "company": {
    "description": null,
    "is_done": true,
    "keywords": [
      "Some",
      "Keywords",
      "For",
      "This",
      "Domain"
    ],
    "logo": "https://logo.clearbit.com/example.com",
    "name": "Example Website",
    "raw_url": "example.com",
    "title": "Example.com super website !",
    "url": "http://www.example.com"
  },
  "created": 1465371124000,
  "email": {
    "avatar_url": "https://secure.gravatar.com/avatar/abcde&s=128",
    "email": "second@example.com",
    "is_done": true,
    "score": 100
  },
  "id": 12345,
  "lists": [],
  "name": "Second User",
  "owner": {
    "admin": true,
    "avatar_url": "https://secure.gravatar.com/avatar/54321?d=mm&s=128",
    "email": "user@voilanorbert.com",
    "firstname": "Cyril",
    "language": "en",
    "name": "Cyril"
  },
  "searching": false,
  "status": "LEAD"
}

GET/contacts/

Return a specific contact.

The object email is either null when the email is not found, or contains an object with at least email (the email string) and the score.


Lists

Resource

GET /lists/
RequestsCurl
Body
curl https://api.voilanorbert.com/2016-01-04/lists/ \
 -u any_string:{secure_token} \
Responses200
Headers
Content-Type: application/json
Body
{
  "result": [
    {
      "contacts": 45,
      "created": 1466070977000,
      "id": 2,
      "name": "My great list"
    },
    {
      "contacts": 22,
      "created": 1464860382000,
      "id": 1,
      "name": "Awesome leads"
    }
  ]
}

GET/lists/

Returns a list of … your lists.

URI Parameters
HideShow
name
String (optional) Example: "My List"

Filter the results with lists that contains the given name parameter.

order_by
String (optional) Example: "name"

Order the results by the given parameter. You can use - to change the order to DESC.


Resource

POST /lists/
RequestsCurl
Body
curl -X POST https://api.voilanorbert.com/2016-01-04/lists/ \
 -u any_string:{secure_token} \
 -d "name=Awesome leads"
Responses200400
Headers
Content-Type: application/json
Body
{
  "contacts": 0,
  "created": 1464860382000,
  "id": 2,
  "name": "Awesome leads"
}
Headers
Content-Type: application/json
Body
{
  "name": [
    "This field is required."
  ]
}

POST/lists/

Create a new list.

URI Parameters
HideShow
name
string (required) Example: "My Great List"

The list’s name


Resource

GET /lists/
RequestsCurl
Body
curl https://api.voilanorbert.com/2016-01-04/lists/1 \
 -u any_string:{secure_token}
Responses200404
Headers
Content-Type: application/json
Body
{
  "contacts": 0,
  "created": 1464860382000,
  "id": 1,
  "name": "Awesome leads"
}
Headers
Content-Type: application/json
Body
{
  "code": 404,
  "error": "Page not found."
}

GET/lists/

Returns the details of one of your lists.


Resource

PUT /lists/
RequestsCurlCurl
Body
curl -X PUT https://api.voilanorbert.com/2016-01-04/lists/1 \
 -u any_string:{secure_token} \
 -d "name=My New Name"
Responses200
Headers
Content-Type: application/json
Body
{
  "contacts": 0,
  "created": 1464860382000,
  "id": 1,
  "name": "My New Name"
}
Body
curl -X PUT https://api.voilanorbert.com/2016-01-04/lists/1 \
 -u any_string:{secure_token} \
 -d "removed=1"
Responses202
This response has no content.

PUT/lists/

Update or set to deletion a given list.

URI Parameters
HideShow
name
string (required) Example: "My New Name"

The new list’s name

removed
Boolean (optional) Example: 1

Set this value to either true, 1 to mark this list to deletion. In this case, the list will be removed the next day. Call again the PUT request to abort the deletion.


Resource

POST /lists/
RequestsCurl
Body
curl -X POST https://api.voilanorbert.com/2016-01-04/lists/1 \
 -u any_string:{secure_token} \
 -d "company=Google"
Responses200
Headers
Content-Type: application/json
Body
{
  "contacts": 150,
  "created": 1464860382000,
  "id": 1,
  "name": "My New Name"
}

POST/lists/

Effect a given list of contacts to that list.

The list of contacts is generated from the same query returned from the GET request to /contacts/, with the same parameters. This let you apply a big number of contacts to this list

@see GET /contacts/


Verify Endpoint

Resource

POST /verifier/upload
RequestsPythonCurl
Body
import requests, time

# Here is a quick sample Python code snippet that implements the algorithm:

API_TOKEN = 'abcde'

req = requests.post(
  'https://api.voilanorbert.com/2016-01-04/verifier/upload',
  auth=('any_string', API_TOKEN),
  data = {
      'data': 'testme@voilanorbert.com',
      'webhook': 'http://mywebhook.com'
  }
)

if not req.success:
  return None
Responses200402400
Headers
Content-Type: application/json
Body
{
"success": True,
"status": "Processing ...",
"token": "unique_token",
"channel": "channel_token"
}
Headers
Content-Type: application/json
Body
{
  "code": "402",
  "error": "Please provide a webhook to which we will post the verify results"
}
Headers
Content-Type: application/json
Body
{
  "code": "400",
  "error": "Please provide a file size lower than 100Mb. If you need more, please contact us."
}
Body
curl -X POST https://api.voilanorbert.com/2016-01-04/verifier/upload \
 -u any_string:{secure_token} \
 -d data="testme@voilanorbert.com" \
 -d webhook="http://mywebhook.com"
Responses200402400
Headers
Content-Type: application/json
Body
{
"success": True,
"status": "Processing ...",
"token": "unique_token",
"channel": "channel_token"
}
Headers
Content-Type: application/json
Body
{
  "code": "402",
  "error": "Please provide a webhook to which we will post the verify results"
}
Headers
Content-Type: application/json
Body
{
  "code": "400",
  "error": "Please provide a file size lower than 100Mb. If you need more, please contact us."
}

POST/verifier/upload

Verifies the given list of emails.

In case your account does not have a sufficient Verify API balance the service will try to auto refill the balance by charging using the billing details of the account. If it fails to charge, an HTTP status code of 402 will be returned.

The endpoint accepts two types of inputs. One is a csv file and other is emails on one line a piece as a POST parameter. At least one of these parameters should be provided.

You should provide a callback url using the webhook parameter. We will send a POST request to this URL and expect a status code of 2xx. If we get something else, we will try again 2 more times with incrementing interval of 30 seconds between each request. After the third request, the server will stop trying.

Webhook will be called with a results parameter. ‘results’ will include list of objects for each email entry that is sent for verification. The object will include email, is_deliverable, is_risky, is_bounce, error_msg fields.

URI Parameters
HideShow
data
string (optional) Example: "testme@voilanorbert.com\ntestit@voilanorbert.com"

Line separated emails

files
file (optional) Example: File content

CSV File content which includes the list of emails in it

webhook
string (required) Example: "http://requestb.in/aaaaaa"

URL where the result will be POSTed


Generated by aglio on 19 Nov 2017