Logging calls in your database
Best practices to know before storing calls metadata

Storing call data outside from Aircall is one of the most built feature by our Technology Partners.

Aircall renders lots of useful metadata via the Public API on Calls, like the Agent who took the call, the Number the call was made on, the duration, and even specific reasons if a call is missed.

Here, we will store Aircall Calls' metadata in an external database.

This tutorial is oriented for Technology Partners but it is still useful if you are an Aircall customer! Authorize your request using Basic Authentication method instead of OAuth.

Before getting started

There are two ways to synchronize Aircall Calls with your system:

I. Real-time synchronization: using Webhooks, Aircall will notify your system each time a call is updated. This is the recommended method.

II. Batch syncing: a recurring task will fetch the latest calls via Aircall Public API.

All requests made to Aircall Public API and explained in this tutorial are authenticated. Make sure to follow our OAuth Authentication tutorial first!

I. Real-time synchronization

Real-time synchronization only requires setting a web server with one public POST endpoint!

It's definitively the easiest, most reliable and scalable way to retrieve call information from Aircall: we won't have to deal with Public API rate limiting, pagination and automation as we will rely 100% on Webhook events sent by Aircall.


  1. Setup an Aircall Webhook via Public API
  2. Store call metadata in your database

1. Setup an Aircall Webhook via Public API

The following tutorial will give you more insights on how to create a Webhook via the Public API.

Create a Webhook from the Aircall Dashboard
Beginner guide to create a Webhook and listen to Aircall events.

Here, we will listen to all the Call events:

/** * create-webhook.js */ const https = require('https'); // Takes a User accessToken // and creates a Webhook in your User's Aircall account const createWebhook = (accessToken) => { // Define the HTTP options: let options = { host: 'api.aircall.io', path: '/v1/webhooks', method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + accessToken } }; // Define the Webhook's body, listening only to call events const body = { 'custom_name': 'YOUR_APP_NAME', 'url': 'https://your.server.com/aircall/webhook', 'events': [ 'call.created', 'call.ringing_on_agent', 'call.agent_declined', 'call.answered', 'call.transferred', 'call.hungup', 'call.ended', 'call.voicemail_left', 'call.assigned', 'call.archived', 'call.tagged', 'call.untagged', 'call.commented' ] }; // Define the POST request: const req = https.request( options, res => { let payload = ''; res.on('data', data => { payload += data }); res.on('end', () => { // Here the Webhook has been created // The unique token can be extracted from the payload: const webhookToken = payload.webhook.token; // TODO: store this webhookToken on your User model }); } ); // Attach the body to the request and execute it req.write(JSON.stringify(body)); req.end(); }

2. Store Calls metadata in your database

Now that the Aircall Webhook is created, we will start receiving all events related to calls on the following endpoint:

[POST] https://your.server.com/aircall/webhook

Each time a Webhook event is sent to this endpoint, we will either create or update a call in our database.

/** * server.js * Using express to run a NodeJS server */ const express = require('express'), bodyParser = require('body-parser'); const app = express(); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); // [POST] /aircall/webhook // URL used by Aircall to send Webhook events app.post('/aircall/webhook', (req, res) => { createOrUpdateCall(req.body.data); res.sendStatus(200); }); const createOrUpdateCall = (callData) => { // TODO: save this callObject in your database // Check the Tips & tricks section of this tutorial to get inputs on what fields to store }; const PORT = 5000; app.listen(PORT, () => { console.info('[server] server started'); console.info('[server] visit http://localhost:' + PORT); });

II. Batch syncing

Another way to fetch call metadata is by using the [GET] /v1/calls endpoint. This endpoint is paginated, with maximum 50 calls per page.

If you want to retrieve all your calls, you will need to take in consideration the following:

  1. Aircall Public API is rate limited to 60 requests per minute. If you request the Public API more than 60 times in less than a minute, your API token will be blocked by Aircall. It will be unblocked 60 seconds after the 60th request.

  2. As the Public API is paginated with 50 items maximum, you will need to iterate through several pages and send multiple requests. As Aircall Public API is rate limited (see above), we recommend that you delay each Public API request to avoid hitting the rate limit.

  3. With the pagination system, Aircall Public API will limit you to retrieve only 10,000 calls. To pass over this limit, we encourage you to use the from query param as much as you can!

/** * create-webhook.js */ // Using axios' package to leverage async/await const axios = require('axios'); /** * Main function retrieving all calls, iterating over all pages */ const getCalls = async () => { let calls = []; let url = 'https://api.aircall.io/v1/calls?per_page=1&order=desc'; while (!!url) { let payload = await _sendCallRequest(url); // re-assigning the URL to the next one, with next page index url = !!payload.meta && payload.meta.next_page_link; calls.push(payload.calls); } return calls; } /** * Method sending the GET request to Aircall's API */ const _sendCallRequest = async (apiUrl) => { // TODO: retrieve the user accessToken from your Database const accessToken = 'USER_ACCESS_TOKEN'; // Define the HTTP options: let options = { headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + accessToken } }; try { const payload = await axios.get(apiUrl, options); return payload.data; } catch (e) { console.error('Error while retrieving Aircall calls:', e.response.status); return {}; } } // Then, to use the function wherever you want: getCalls() .then((calls) => { // Do whatever you want with the list of calls console.log(calls) })

Tips & tricks

Here are some useful information to follow if you want to log Aircal calls in your app.

☝ī¸ Log comments and tags

Comments (or notes) and Tags are submitted by Agents from the Phone, often while on call. We highly recommend logging this data in your app!

☝ī¸ Contact information

The contact field will be populated with Contact info if it existed when the call happened. The contact field will be null if contact was retrieved from a CRM or Helpdesk

☝ī¸ How does the teams field work?

The teams array represents all the teams on which an inbound call rang. It can be null if call's direction is outbound, even if the agent who started the call is part of a team: it's impossible for Aircall to guess from which team the call was initiated from.

☝ī¸ Download call recordings or voicemails

Both the recording and voicemail fields link to MP3 file if not null. For security reasons URLs are valid for 10 minutes only. Please read the following tutorial if you want to download those files on your own server:

Store call recordings on a dedicated server
Import your recordings and voicemail in your infrastructure and add an extra layer of security.

☝ī¸ Was a call missed?

The type of a call is not rendered in the Call object, but there's several ways to defined if an inbound call was missed or not.

  1. status must be done.
  2. missed_call_reason must be defined.

☝ī¸ Get the incall duration

The duration field available in the Call object represent the whole call duration, from the moment when the call was created to the time when the call was ended. This field is computed by started_at - ended_at.

If you need to have the incall duration, you can compute it by answered_at - ended_at.

We wrote other tutorials to help you out
building awesome integrations

Discover them now