0

I'm trying to create a web form where users can input their phone number to initiate an SMS conversation run through Twilio's AutoPilot. I'm getting hung up between tutorials on Webhooks and tutorials on fetch-node and could use some help.

Goal is to:

  • Accept phone number from web form
  • Pass into Twilio Function
  • Parse phone number
  • Redirect to Twilio Autopilot to start SMS conversation

The web form is on a website hosted by Duda, their API documentation on getting form submissions is here: https://developer.duda.co/reference#get-contact-form-data

What I can't figure out:

  1. I created a Function (code below) and put that webhook into the UI of my form - is that correct?

  2. I'm getting no errors in the Twilio error log, which I'm taking to mean I'm not connected or passing data through to Twilio at all. Correct assumption?

  3. The code. It's hacked together from several different places, so take it easy!

exports.handler = function(context, event, callback) {
const fetch = require('node-fetch');

fetch('https://api.duda.co/api/sites/multiscreen/get-forms/e5712b84', {
        method: 'GET',
        headers: {
            'Authorization': 'Basic ZGZmOTIzMTA3Yzp3Rk9jMnRDTjRHbk8='
        }
    })
    .then(response => response.json())
    .then(json => {
         console.log("Phone Number:");
         console.log(json[0].Phone);
})

let actions = [];
  let end = {   
      "redirect":{
                    "method": "POST",
                    "uri": "task://greeting"
                }
    };

actions.push(end);

    let respObj = {
        'actions': actions
    };
    callback(null,respObj);
};

Error Log from recommended solution in comments:

UnhandledPromiseRejectionWarning: Unhandled promise rejection: TypeError: Cannot read property 'fieldsData' of undefined
    at Object.exports.handler (/var/task/handlers/ZNbaee490d934cb9ca27e0f14907c04089.js:2:33)
    at Object.exports.handler (/var/task/node_modules/runtime-handler/index.js:310:10)
    at Runtime.exports.handler (/var/task/runtime-handler.js:17:17)
    at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)
crossbeats
  • 65
  • 1
  • 14

1 Answers1

0

Twilio developer evangelist here.

So, you want to trigger an outbound message to a user when they input a phone number into a Duda form. You can get Duda to send webhooks for the form submission to a Twilio Function, that is a good start. Let's look into what we should do from there.

The Duda form submission webhook is documented here. You should be able to access the data that is submitted using the event object in the Twilio function. There's a data object that contains fieldsData which is an array of the fields in your form. I am guessing, based on your code, that the phone number is being input to a field called "Phone", so you will need to find this field in the array and get its field_value.

Here's some example code for this step so far. Note that we don't need to fetch the data from the Duda API because the webhook should include all the data.

exports.handler = async function(context, event, callback) {
  const fieldsData = event.data.fieldsData;
  const phoneField = fieldsData.find(field => {
    return field.field_label === "Phone";
  });

  if (phoneField) {
    const to = field.field_value;

    // Do something with the phone number
  } else {
    // Return an error because we could not find the field.
    callback(new Error("Could not find Phone field in webhook data"));
  }
}

Now, the next thing you want to do is send the number a message. You originally said you want to redirect to Autopilot, but you are currently dealing with a webhook from Duda and Autopilot has not gotten involved yet. You cannot return Autopilot actions to the request from Duda because Duda will not know what to do with them.

Another thing is that you cannot make an outbound request from Autopilot. Autopilot responds to inbound requests. So, to get Autopilot involved, you should set up your Twilio number to respond with your Autopilot bot, but your first outbound message will have to be made using the Twilio Messaging API.

You have the phone number you want to send the message to, I recommend you add your Twilio phone number into the Runtime Environment Variables, and you will need an outbound message body. Then you can send the outbound message, like this:

exports.handler = async function(context, event, callback) {
  const fieldsData = event.data.fieldsData;
  const phoneField = fieldsData.find(field => {
    return field.field_label === "Phone";
  });

  if (phoneField) {
    const to = field.field_value;

    const from = context.TWILIO_PHONE_NUMBER;
    const body = "Thanks for filling in the form. I have some more questions for you.";
    const client = context.getTwilioClient();

    try {
      await client.messages.create({ to, from, body });
      // Everything succeeded, respond OK to the Duda webhook
      callback(null, "OK");
    } catch (error) {
      // Something went wrong trying to send the message
      callback(error);
    }
  } else {
    // Return an error because we could not find the field.
    callback(new Error("Could not find Phone field in webhook data"));
  }
}

I think that should do the trick. I've not used Duda before, so I might be wrong, but hopefully that puts you on the track to solving this.

philnash
  • 70,667
  • 10
  • 60
  • 88
  • Hey Phil - You were exactly the guy I was hoping would show up! I got an error log that I added to my original post (too long for a comment!). Reads to me like it's saying fieldsData is not defined - but it's defined on line 2, correct? – crossbeats Jul 22 '21 at 13:40
  • That’s saying that `event.data` doesn’t exist. It might be best if you log out why the `event` object looks like so that we can work out how to work with it. – philnash Jul 22 '21 at 13:49
  • Here's the JSON object I'm getting back: `{utm_campaign=null, fieldsData=[{field_label=Phone, field_value=7348123008, field_type=tel, field_key=, field_id=dmform-00}, {field_label=Title, field_value=Test Form, field_type=form_title, field_key=, field_id=null}], recipients=[sales@trueradiusmarketing.com]}` event.data.Fields data is definitely the correct object. I'm still getting the same error, even though I'm now getting a response. – crossbeats Jul 30 '21 at 22:37
  • Looks to me like you don’t need the `data` and you can just work with `event.fieldsData` on the first line of the function. – philnash Jul 30 '21 at 22:57
  • TypeError: Cannot read property 'find' of undefined Line 3, Column 33 - so looks like fieldsData still isn't defined – crossbeats Jul 30 '21 at 23:11
  • What did you log out that gave you the object in your previous comment? – philnash Jul 30 '21 at 23:12
  • `console.log("Log Event: ",event); ` `Log Event: { data: { utm_campaign: null, fieldsData: [ [Object], [Object] ], recipients: [ 'sales@trueradiusmarketing.com' ] }, source: null, resource_data: { site_name: 'e5712b84' }, event_timestamp: 1628265846061, event_type: 'CONTACT_FORM_SENT_V2' }` I've tried JSON.stringify, JSON.parse, and decodeURIComponent - all I get back for fieldsData is [object Object] – crossbeats Aug 06 '21 at 16:10