In the business world, it is very important to know as much as possible about your partners or counterparts. This might be useful in many cases, for example, in lead generation. FullContact – Enrich API is designed especially to help you with this, allowing to perform two similar tasks, person enrich (FullContact Person API) and company enrich (FullContact Company API). The working principle is simple: you enter some little piece of known information about the person or company, and the API returns you all available additional information about the object of interest. In this article, we will explain how to use FullContact API and show a basic example of the real-world application creation with Python using this API.
Quick Links
FullContact API Overview
To find this API on the RapidAPI marketplace, you can browse the Social APIs category or search directly for the name of the API in the search field.
Once you find the API, you can see that it is “Freemium”, which means that there is a free pricing plan limited by the specific number of requests over a period of time (day or month). The details about pricing you can see at the Pricing tab.
Also, all of the APIs on the RapidAPI have such sections as Endpoints, API Details, and Discussions. The main information about how to use the API is placed in the Endpoints section. If you need some additional details, you can find them under the API Details section. Also, you can ask support or community about something related to the API in the Discussions section. To start working with the API, you have to subscribe to it in the Pricing section.
Where can I get a FullContact API Key?
No external FullContact API key is required when you sign up with RapidAPI. You’ll receive a single API key for all APIs you are subscribed to within RapidAPI to manage all your apps and integrations.
The structure of the Endpoints section is the same for all available APIs. It is divided into 3 sections. From the left side of the page, you can see a list of the existing endpoints for the API. If you select the endpoint, the information on the rest of the page will be updated. In the middle, the form for the request filling for the endpoint will appear. It contains header parameters, required parameters, and optional parameters (if any). As you fill in the fields, the code in the snippet from the right side of the page is updated. After you click Test Endpoint, the request will be issued, and you will see the results of the request instead of the code snippet.
FullContact Person API
The FullContact Person API can be used to enrich a person’s contact information such as:
- phone number
- social media profiles
- and much more
The left and middle sides of the page for FullContact – Enrich API’s /person.enrich (FullContact Person API) endpoint are shown on the image below.
Notice that there is “Python” inscription at the top of the section. If you click on it, the dropdown menu will appear. You will be able to choose another programming language to view the code snippet on it. The following programming languages are available:
- Python
- Node JS
- PHP
- Ruby
- Java
- C#
- Objective-C
For FullContact – Enrich API the RapidQL unified interface is also supported.
See several examples of the requests in different languages below.
FullContact – Enrich API NodeJS
unirest.post("https://fullcontact-enrich-v1.p.rapidapi.com/person.enrich") .header("X-RapidAPI-Host", "fullcontact-enrich-v1.p.rapidapi.com") .header("X-RapidAPI-Key", "40aeaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") .header("Content-Type", "application/json") .send({"email":"bart@fullcontact.com","phone":"+ 13035551234","twitter":"@bartlorang"}) .end(function (result) { console.log(result.status, result.headers, result.body); });
FullContact – Enrich API PHP
$response = UnirestRequest::post("https://fullcontact-enrich-v1.p.rapidapi.com/person.enrich", array( "X-RapidAPI-Host" => "fullcontact-enrich-v1.p.rapidapi.com", "X-RapidAPI-Key" => "40aeaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "Content-Type" => "application/json" ), array ) "{"email":"bart@fullcontact.com","phone":"+ 13035551234","twitter":"@bartlorang"}" );
Learn more on how to use an API with PHP.
FullContact – Enrich API Ruby
response = Unirest.post "https://fullcontact-enrich-v1.p.rapidapi.com/person.enrich", headers:{ "X-RapidAPI-Host" => "fullcontact-enrich-v1.p.rapidapi.com", "X-RapidAPI-Key" => "40aeaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "Content-Type" => "application/json" } "{"email":"bart@fullcontact.com","phone":"+ 13035551234","twitter":"@bartlorang"}"
FullContact – Enrich API Java
HttpResponse response = Unirest.post("https://fullcontact-enrich-v1.p.rapidapi.com/person.enrich") .header("X-RapidAPI-Host", "fullcontact-enrich-v1.p.rapidapi.com") .header("X-RapidAPI-Key", "40aeaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") .header("Content-Type", "application/json") .body("{"email":"bart@fullcontact.com","phone":"+ 13035551234","twitter":"@bartlorang"}") .asJson();
Let’s go back to the exploration of the FullContact API. The API has two endpoints; both require the HTTP POST method for interacting with them. The first endpoint is used for person enrichment and is called /person.enrich. There is only one required parameter for this request. The parameter has to be specified in the body of the request. It should consist of a JSON object with three key-value pairs in any combination (but at least one field has to be included). Each field represents data about the person available before the request is made. It can be an email, a phone number, or a Twitter profile name.
FullContact Company API
Another endpoint, /company.enrich (or FullContact Company API), is even simpler. The JSON object for the request should contain only one field – the domain of the company’s website. For example, here is what we should pass to the API in order to find information about the RapidAPI company:
One important thing we want to focus your attention on is the Header Parameters section:
X-RapidAPI-Host and X-RapidAPI-Key parameters are used for identification and billing purposes – X-RapidAPI-Host for the API and X-RapidAPI-Key for your account and project. You should include these parameters in all requests you generate from any environment. While viewing endpoints in a browser, you can change the RapidAPI Project to change the key. Projects (apps) are created on the RapidAPI Dashboard page (Add New App tab):
Example Application
Now we would like to show you an example of how to use the API in real-world application creation. Obviously, it is unlikely that this API will be used as the main component of an application. It will rather be something like a useful and convenient feature embedded into a large application. Nevertheless, we will create a small Flask web application that will allow users to enter the information about a company or a person they want to know more about.
The first thing that we have to do is to create a folder for our new application. Let’s call this folder flask_app. Inside this folder, we want to create a virtual Python environment, because we want to avoid packages conflicts with our global environment. So, we will issue the following command from our app’s folder:
python3 -m venv venv
The virtual environment will be created in the folder named venv. In this virtual environment, we will install all the needed packages for our project, including Flask.
The rest of the flask_app folder has the following structure:
import os class Config(object): SECRET_KEY = os.environ.get('SECRET_KEY') or 'secret_key_fullcontact'
The enrichment.py file is the top-level file which defines the Flask application instance:
from app import app
All main application logic is located in the files of the app folder. It is a Python package as it contains __init__.py file. This file imports Flask and Config objects, then creates an instance of the Flask object and configures it using the Config object. The last line of this file imports routes from the app package. Below, you can find the code for the __init__.py file.
from flask import Flask from config import Config app = Flask(__name__) app.config.from_object(Config) from app import routes
Probably one of the most interesting files belonging to our application is the routes.py file. This file is responsible for different routes in the application. In other words, in this file we specify what the application should do when a user hits different URLs. At the top of this file we import all needed things (app from app package, request(), render_template(), redirect(), and url_for() functions from the flask library, forms from the app.forms module, and prepare_json() and api_call() functions from the app.api_logic module.
from app import app from flask import request, render_template, redirect, url_for from app.forms import CompanyForm, PersonForm, SelectForm from app.api_logic import prepare_json, api_call @app.route('/', methods=['GET', 'POST']) def index(): select_form = SelectForm() if select_form.validate_on_submit(): return redirect('/{}/'.format(select_form.radio.data)) return render_template('select_form.html', title='Home', form=select_form)
Below the import statements, we create our first routing function called index(). Using the Python decorators we specify that this function will be triggered when a user hits the home page of our application (‘/’ means, for example, https://localhost:5000/). We also allow both GET and POST HTTP methods for this endpoint. GET method will be used for the initial page loading, and POST method will be used for the form submission. Inside the function, we create an instance of the SelectForm object. To be able to use forms in your Flask application we need to install the Flask-WTF extension:
pip install flask-wtf
If the form passes the validation, we redirect the user to another page. The user will select what the page depends on, person or company enrichment. This is how the home page of our application looks like:
from flask_wtf import FlaskForm from wtforms import StringField, SubmitField, RadioField from wtforms.validators import DataRequired class SelectForm(FlaskForm): radio = RadioField('Options', choices=[('person', 'Person'), ('company','Company')], validators=[DataRequired()]) submit = SubmitField('Select') class CompanyForm(FlaskForm): domain = StringField('Domain', validators=[DataRequired()]) submit = SubmitField('Enrich!') class PersonForm(FlaskForm): email = StringField('Email') phone = StringField('Phone') twitter = StringField('Twitter') submit = SubmitField('Enrich!') def validate(self): if not self.email.data and not self.phone.data and not self.twitter.data: msg = 'At least one of the fields must be set' self.email.errors, self.phone.errors, self.twitter.errors = list(self.email.errors), list(self.phone.errors), list(self.twitter.errors) self.email.errors.append(msg) self.phone.errors.append(msg) self.twitter.errors.append(msg) return False return True
So, now we have a routing function in the routes.py file and the form class (SelectForm) in the forms.py file. Another thing needed to obtain the view from above is the HTML template. All our templates are defined in the templates folder. A template is an HTML scaffold mixed with Jinja2 templating language. It allows to dynamically substitute some variables with real data at runtime. The templates could be joined together. In our case, for each page of the application, we use base.html template to support stable navigation bar on each of the pages. Here is the code for this file:
<html> <head> {% if title %} <title>{{ title }} - Enrichment app</title> {% else %} <title>Welcome to the Enrichment application</title> {% endif %} </head> <body> <div>Enrichment app: <a href="{{ url_for('index') }}">Home</a></div> <hr> {% block content %}{% endblock %} </body> </html>
And here is the select_form.html template, which will be embedded as the block “content”:
{% extends "base.html" %} {% block content %} <h1>What do you want to enrich?</h1> <form action="" method="post" novalidate> {{ form.hidden_tag() }} {% for subfield in form.radio %} <tr> <td>{{ subfield }}</td> <td>{{ subfield.label }}</td> </tr> {% endfor %} <p>{{ form.submit() }}</p> </form> {% endblock %}
As you could see in the SelectForm’s code, if a user selects Person, then a “person” string will be included in the select_form.radio.data variable. The same is true for Company selection (the string will be “company” in this case). The string will be inserted into the new route in the index() function and then the user will be redirected to this URL.
Here are the routing functions from the routes.py file used to deal with the corresponding pages hits:
@app.route('/person/', methods=['GET', 'POST']) def person(): person_form = PersonForm() if person_form.validate_on_submit(): email = person_form.email.data if len(person_form.email.data) > 0 else None phone = person_form.phone.data.replace(' ', '') if len(person_form.phone.data) > 0 else None twitter = person_form.twitter.data if len(person_form.twitter.data) > 0 else None return redirect(url_for('person_results', email=email, phone=phone, twitter=twitter)) return render_template('person_form.html', title='Person', form=person_form) @app.route('/company/', methods=['GET', 'POST']) def company(): company_form = CompanyForm() if company_form.validate_on_submit(): domain = company_form.domain.data return redirect(url_for('company_results', domain=domain)) return render_template('company_form.html', title='Company', form=company_form)
For the “person” form page we have 3 fields which a user can fill in (email, phone, and Twitter). At least one has to be filled in. For checking this condition, we have prepared the validate() method in the PersonForm class in the forms.py file. Inside the person() function in the routes.py file, we check the existence of each field after the form submission and then redirect to the person_results page with a query string URL. Later, the person_results() function will use the query string to extract the parameters needed for the API call issuing. The logic for the “company” form is a little bit simpler because it has only one field and it is required to be not empty.
The person_form.html template:
{% extends "base.html" %} {% block content %} <h1>Person enrichment</h1> <form action="" method="post" novalidate> {{ form.hidden_tag() }} <p> {{ form.email.label }}<br> {{ form.email(size=32) }} {% for error in form.email.errors %} <span style="color: red;">[{{ error }}]</span> {% endfor %} </p> <p> {{ form.phone.label }}<br> {{ form.phone(size=32) }} {% for error in form.phone.errors %} <span style="color: red;">[{{ error }}]</span> {% endfor %} </p> <p> {{ form.twitter.label }}<br> {{ form.twitter(size=32) }} {% for error in form.twitter.errors %} <span style="color: red;">[{{ error }}]</span> {% endfor %} </p> <p>{{ form.submit() }}</p> </form> {% endblock %}
The company_form.html template:
{% extends "base.html" %} {% block content %} <h1>Company enrichment</h1> <form action="" method="post" novalidate> {{ form.hidden_tag() }} <p> {{ form.domain.label }}<br> {{ form.domain(size=32) }} {% for error in form.domain.errors %} <span style="color: red;">[{{ error }}]</span> {% endfor %} </p> <p>{{ form.submit() }}</p> </form> {% endblock %}
On the images below, you can see how the given pages look like (@elonmusk and google.com notices are added by ourselves, they are not the placeholders or default values):
The last two functions from the routes.py file we need to explore are person_results() and company_results(). The first one extracts the entered by the user parameters from the query string in the URL and joins them in the query variable. Then it calls two functions: prepare_json() to prepare the JSON object needed by the API, and api_call() to perform a request to the FullContact – Enrich API. We will look at these functions later. After receiving the response from the API, person_results() function capitalizes the field names of the response JSON object. Then it renders the person_results.html template using the response data.
app.route('/person_results/') def person_results(): email, phone, twitter = request.args.get('email', '_'), request.args.get('phone', '_'), request.args.get('twitter', '_') query = email + " " + phone + " " + twitter prepared_json = prepare_json(query, mode='person') r = api_call(prepared_json, mode='person') keys = list(r.keys()) for i in keys: r[i.capitalize()] = r.pop(i) return render_template('person_results.html', title='Person results', data=r) @app.route('/company_results//') def company_results(domain): prepared_json = prepare_json(domain, mode='company') r = api_call(prepared_json, mode='company') keys = list(r.keys()) for i in keys: r[i.capitalize()] = r.pop(i) return render_template('company_results.html', title='Company results', data=r)
The logic in the company_results() function is similar but slightly less complicated. It doesn’t parse the query string. Instead, it simply receives the variable from the URL, because we are now sure that this variable should exist.
The person_results.html template:
{% extends "base.html" %} {% block content %} <h1>Person results</h1> <hr> {% for key, value in data.items() %} <h3>{{key}}</h3> <p>{{value}}</p> <hr> {% endfor %} {% endblock %}
The company_results.html template:
{% extends "base.html" %} {% block content %} <h1>Company results</h1> <hr> {% for key, value in data.items() %} <h3>{{key}}</h3> <p>{{value}}</p> <hr> {% endfor %} {% endblock %}
Let’s now look at the api_logic.py file which includes the code for working directly with FullContact API:
import json import requests def prepare_json(query, mode='company'): d = {} if mode == 'company': d['domain'] = query elif mode == 'person': fields = query.split() if fields[0] != '_': d['email'] = fields[0] if fields[1] != '_': d['phone'] = fields[1] if fields[2] != '_': d['twitter'] = fields[2] json_d = json.dumps(d) return json_d def api_call(json_d, mode='company'): rapidapi_host = "fullcontact-enrich-v1.p.rapidapi.com" rapidapi_key = "04573xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" headers = { "X-RapidAPI-Host": rapidapi_host, "X-RapidAPI-Key": rapidapi_key, "Content-Type": "application/json" } if mode == 'company': response = requests.post("https://fullcontact-enrich-v1.p.rapidapi.com/company.enrich", headers=headers, data=(json_d)) elif mode == 'person': response = requests.post("https://fullcontact-enrich-v1.p.rapidapi.com/person.enrich", headers=headers, data=(json_d)) r = json.loads(response.text) return r
The prepare_json() function expects the string to analyze as input. Also, the parameter mode should tell about what type of enrichment we are going to do: for a person or for a company. Depending on the mode parameter, this function parses the string from the query variable and generates the appropriate JSON object which then can be used by the api_call() function to perform the API call.
Inside the api_call() function we specify the parameters needed for headers (host and key). As a body for the POST request, we use the JSON object. The API response is returned outside the function.
You can see that we use rapidapi_key variable in the api_call() function. Here is where we can take this key:
So, after you create your project on the RapidAPI platform, you can select it on My Apps page and then click on Security. The new page will be opened and you will be able to find a key there:
Here is how the page with the results of “google.com” enrichment looks like:
This is the page with the results of the person’s enrichment (we use @elonmusk twitter name as the departure point):
from app import app from flask import request, render_template, redirect, url_for from app.forms import CompanyForm, PersonForm, SelectForm from app.api_logic import prepare_json, api_call @app.route('/', methods=['GET', 'POST']) def index(): select_form = SelectForm() if select_form.validate_on_submit(): return redirect('/{}/'.format(select_form.radio.data)) return render_template('select_form.html', title='Home', form=select_form) @app.route('/person/', methods=['GET', 'POST']) def person(): person_form = PersonForm() if person_form.validate_on_submit(): email = person_form.email.data if len(person_form.email.data) > 0 else None phone = person_form.phone.data.replace(' ', '') if len(person_form.phone.data) > 0 else None twitter = person_form.twitter.data if len(person_form.twitter.data) > 0 else None return redirect(url_for('person_results', email=email, phone=phone, twitter=twitter)) return render_template('person_form.html', title='Person', form=person_form) @app.route('/company/', methods=['GET', 'POST']) def company(): company_form = CompanyForm() if company_form.validate_on_submit(): domain = company_form.domain.data return redirect(url_for('company_results', domain=domain)) return render_template('company_form.html', title='Company', form=company_form) @app.route('/person_results/') def person_results(): email, phone, twitter = request.args.get('email', '_'), request.args.get('phone', '_'), request.args.get('twitter', '_') query = email + " " + phone + " " + twitter prepared_json = prepare_json(query, mode='person') r = api_call(prepared_json, mode='person') keys = list(r.keys()) for i in keys: r[i.capitalize()] = r.pop(i) return render_template('person_results.html', title='Person results', data=r) @app.route('/company_results//') def company_results(domain): prepared_json = prepare_json(domain, mode='company') r = api_call(prepared_json, mode='company') keys = list(r.keys()) for i in keys: r[i.capitalize()] = r.pop(i) return render_template('company_results.html', title='Company results', data=r)
As you can see, our results are quite raw. You can add a more complex and attractive frontend if you want. Also, you can improve the application from many other aspects. For example, we are sure that a couple more validators should be added to the forms in order to avoid nasty errors. Also, our routes are not secured enough. Anyone can enter the URL of specific endpoint in his/her browser, and this will be a way to get around all our form validators. Eventually, as we have already mentioned, it is not very likely that this application will be used independently. Instead, we expect to use it as a component of a larger app. For example, for auto-completion mechanisms or for information checking. But it is more about the application architecture and specific components than about the interaction with the FullContact API. This interaction will remain similar in its core for all applications.
The interesting thing we want also to show is the Analytics section of your application on the RapidAPI My Apps page. There you can monitor how your application uses the API. For example, here is the graph with API calls, errors, and latency:
Conclusion
In this article, we introduced you one of the popular APIs available in the RapidAPI marketplace – FullContact – Enrich API which allows extracting a lot of different information about a specific company or person. It requires only some pointer(s) from you in order to know what object to search for. The functionality of this API could be useful in many cases, for example, in the lead generation process.
We created the model Flask web application to show how you can use this API and RapidAPI platform to build your own real-world apps. There are a lot more things to do in order to improve the application, but we hope that now you have got a general understanding and are able to design own solutions using different APIs.
Leave a Reply