4

currently I am trying to make a thin wrapper around Whatsapp Cloud API. One of the problem I am currently facing is that the uploading media files isn't working.

Looking through the documentation for uploading files, it seems that it expects a multipart/form-data payload to the endpoint.

Here is my current implementation

import FormData from 'form-data';
import fs from 'fs';
import axios from 'axios';

const formData = new FormData();

formData.append('file', fs.createReadStream('path/to/my/file.jpg'));
formData.append('messaging_product', 'whatsapp');
formData.append('type', 'image/jpeg');

await axios.post('https://graph.facebook.com/v14.0/PHONE_NO_ID/media', formData, {
  headers: { 'Authorization': ACCESS_TOKEN }
});

Looking at the error that it returns, it seems that I am somehow missing the messaging_product field even though I have properly add it in the formData.

{
  "error": {
    "message": "(#100) The parameter messaging_product is required.",
    "type": "OAuthException",
    "code": 100,
    "fbtrace_id": "FBTRACE_ID"
  }
}

The Postman collection works for uploading media file, so I am thinking that the file field of the formData is the problem. Is fs.createReadStream on a file equivalent to how Postman handle file uploading

EDIT: The question has been solved, the problems was not adding in the headers generated by the formData, Thanks Phil below!

Phil
  • 157,677
  • 23
  • 242
  • 245
Yu Yue Ng
  • 53
  • 5
  • have you added the authentication token in the header? – turivishal Aug 09 '22 at 10:02
  • Yes I did I am very sorry that I didn't make this clear, this is not a authentication issue as I tried sending a text message and it was working – Yu Yue Ng Aug 10 '22 at 01:12
  • this is not `messaging_product` parameter issue, this error message is a glitch in WA-API. there might be auth token or file selection issue. try to check in postman and use this [predefined postman api](https://documenter.getpostman.com/view/13382743/UVC5FTHT?fbclid=IwAR18IoroumKt09aN_m9dR7fZ0ns8IXREWSRO0p2-zyAsY6WNCffcLnIdSog#39a02bc0-ede1-4848-b24e-4ac3d501aaea). – turivishal Aug 10 '22 at 05:19
  • Hi, thanks for giving me that postman collection, I tried it and it works so this is most definitely something wrong with my code. I am not sure how postman handles file in the context of NodeJS, would opening a read stream be equivalent to what is postman is doing under the hood? – Yu Yue Ng Aug 10 '22 at 05:57

2 Answers2

4

Love the documentation... they say type is a required parameter then go on to show a curl example without it .

Also, file is not the...

Path to the file stored in your local directory

but instead a mime-encoded binary.

In any case, the type needs to be part of the mime-encoding by way of the content-type meta data and you then need to forward the content-type header generated by FormData.

You also may be missing the Bearer authentication token scheme.

const PHONE_NO_ID = "something";
const ACCESS_TOKEN = "something";

const formData = new FormData();

formData.append("file", fs.createReadStream("path/to/my/file.jpg"), {
  contentType: "image/jpeg",
});
formData.append("messaging_product", "whatsapp");

try {
  const {
    data: { id: mediaId },
  } = await axios.post(
    `https://graph.facebook.com/v14.0/${PHONE_NO_ID}/media`,
    formData,
    {
      headers: {
        Authorization: `Bearer ${ACCESS_TOKEN}`, // "Bearer" prefix
        ...formData.getHeaders(), // merge in FormData headers
      },
    }
  );
  console.log("media ID", mediaId);
} catch (err) {
  console.error("upload", err.toJSON());
}
Phil
  • 157,677
  • 23
  • 242
  • 245
-1

Try this, it worked for me:

    var axios = require('axios');
    var FormData = require('form-data');
    var fs = require('fs');
    var data = new FormData();

    data.append('messaging_product', 'whatsapp');
    data.append('file', fs.createReadStream('./images/fly.jpg'));
    data.append('type', 'image/jpeg');

    var config = {
      method: 'post',
      url: 'https://graph.facebook.com/v13.0/phone_number_id/media',
      headers: { 
        'Authorization': 'Bearer access_token', 
        ...data.getHeaders()
      },
      data : data
    };

    axios(config)
    .then(function (response) {
      console.log(JSON.stringify(response.data));
    })
    .catch(function (error) {
      console.log(error);
    });
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Sep 21 '22 at 09:07