Receiving Documents from WhatsApp Cloud API Webhook: Downloading and Writing to Local File

Moshood Alimi
3 min readApr 15, 2024

--

The WhatsApp Cloud API allows you to receive text and documents sent by users through a webhook. In this tutorial, we’ll walk through the process of setting up a webhook endpoint, handling incoming document messages, and downloading the received documents to a local file using code examples.

Hand holding a black phone with whatsapp logo on the screen
Photo by Mika Baumeister on Unsplash

Prerequisites

Before we dive into the code, make sure you have the following prerequisites set up:

1. A WhatsApp Cloud API account and an access token.
2. A server or hosting environment capable of running Node.js applications.
3. Basic knowledge of JavaScript and Node.js.

Step 1: Set up the Webhook Endpoint

First, let’s create a simple Express.js server with a `/webhook` endpoint to receive incoming messages from WhatsApp:


const express = require('express');
const app = express();
const port = 3000;
app.use(express.json());
app.post('/webhook', async (req, res) => {
// Handle the webhook request here
// …
res.sendStatus(200);
});
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});

Step 2: Handle the Webhook Request

Next, we’ll add code to handle the incoming webhook request and check if it contains a document message:

app.post('/webhook', async (req, res) => {
if (req.body.object && req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]) {
const body = req.body.entry[0].changes[0].value;
if (body.messages[0].type === 'document') {
console.log('Received document!!');
const MEDIA_ID = body.messages[0].document.id;
const fileName = body.messages[0].document.filename.replace(/ /g, '_');
// Process the document here
// …
} else {
console.log('Unknown message type. Nothing to do.');
}
} else {
res.sendStatus(404);
}
res.sendStatus(200);
});

Step 3: Fetch the Document

Now, let’s create a function to fetch the document’s URL from the WhatsApp API using the document ID:

const axios = require('axios');
const token = 'YOUR_ACCESS_TOKEN';
async function fetchMediaData(MEDIA_ID) {
try {
const response = await axios.get(`https://graph.facebook.com/v19.0/${MEDIA_ID}/`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
return response.data;
} catch (error) {
console.error(error);
}
}

Step 4: Download the Document

Next, we’ll create a function to download the document from the URL and save it locally:

const fs = require('fs');
async function getFile(URL, FILE_NAME) {
try {
const response = await axios.get(URL, {
headers: {
Authorization: `Bearer ${token}`,
},
responseType: 'stream',
});
const writer = fs.createWriteStream(FILE_NAME);
response.data.pipe(writer);
await new Promise((resolve, reject) => {
writer.on('finish', () => resolve(FILE_NAME));
writer.on('error', reject);
});
console.log(`Downloaded file: ${FILE_NAME}`);
return FILE_NAME;
} catch (error) {
console.error(error);
throw error;
}
}

Step 5: Putting It All Together

Finally, let’s update the `/webhook` endpoint to handle the document downloading and writing to a local file:

app.post('/webhook', async (req, res) => {
if (req.body.object && req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]) {
const body = req.body.entry[0].changes[0].value;
if (body.messages[0].type === 'document') {
console.log('Received document!!');
const MEDIA_ID = body.messages[0].document.id;
const fileName = body.messages[0].document.filename.replace(/ /g, '_');
const document = await fetchMediaData(MEDIA_ID);
const filePath = await getFile(document.url, fileName);
console.log(`Document downloaded: ${filePath}`);
// You can perform further operations on the downloaded file if needed
} else {
console.log('Unknown message type. Nothing to do.');
}
} else {
res.sendStatus(404);
}
res.sendStatus(200);
});

In this example, we’re fetching the document’s URL from the WhatsApp API, downloading the file using the `getFile` function, and writing it to a local file with the provided filename. The downloaded file path is logged to the console.

Good luck

--

--