Search code examples
node.jsexpressaudiodownloadwhatsapp-cloud-api

How to download a voice note through WhatsApp API?


I have an endpoint that is supposed to make a call to the WhatsApp API with the Media URL just like they said to do here: https://developers.facebook.com/docs/whatsapp/cloud-api/reference/media#download-media, and just return it the same way it was returned from whatsapp as well as save the file for later use.

   exports.downLoadMedia = async (req, res) => {
  const url = req.query.url;

  request.get(
    {
      url: url,
      headers: {
        Authorization: `Bearer ${process.env.AUTH_TOKEN}`,
        Accept: 'audio/ogg',
      },
      encoding: null, // Set encoding to null to receive binary data
    },
    function (err, resp, body) {
      if (err) {
        console.log("Error:", err);
        res.status(500).json({ error: "An error occurred." });
      } else {
          const fileName = 'downloaded_audio.ogg';
          const filePath = path.join(__dirname, fileName); // Construct file path

          fs.writeFile(filePath, body, 'binary', (writeErr) => {
            if (writeErr) {
              console.log("Error writing file:", writeErr);
              res.status(500).json({ error: "An error occurred while saving the audio." });
            } else {
              // Use res.download() to send the saved file as a download response
              res.download(filePath, 'downloaded_audio.ogg', (downloadErr) => {
                if (downloadErr) {
                  console.log("Error sending download:", downloadErr);
                  res.status(500).json({ error: "An error occurred while sending the download." });
                }
              });
            }
          });
      }
    }
  );
};

when i make a get request in Postman with the WhatsApp Media url directly it shows up like this:

enter image description here

and the audio plays as it should.

However, when i make a request to my endpoint above it shows up like this:

enter image description here

The audio is saved but it does not play.

Basically, my endpoint should be the proxy to get the audio/voice note file.


Solution

  • Got it to work after switching from using the request package to axios to handle the call to whatsapp api, then setting a couple more headers for the response.

    Also setting the response type as a stream, then piping the response using axios.

    The file is not saved; however, the response is the file itself, just like when i make the call to the url directly in postman, where i can download the file and it is easier to work with.

    exports.downLoadMedia = async (req, res) => {  
    
    const url = req.query.url;
    
      try {
        // Fetch the audio data from the external URL with the auth token
        const audioResponse = await axios.get(url, {
          responseType: 'stream',
          headers: {
            Authorization: `Bearer ${process.env.META_AUTH_TOKEN}`,
          }
        });
    
        // Set appropriate headers for streaming audio
        let fileName = Date.now().toString() + "_audio.ogg";
        res.setHeader('Content-Type', 'audio/ogg');
        res.setHeader('Content-Disposition', `attachment; filename=${fileName}`);
        res.setHeader('Transfer-Encoding', 'chunked');
    
        // Pipe the audio stream from the external response to the current response
        audioResponse.data.pipe(res);
      } catch (error) {
        res.status(500).send('Error fetching audio data: ' + error.message);
      }
    };