Handling SMS responses with Twilio function and Airtable database lookup

I need help setting up an automated SMS response system. I already have the daily SMS sending part working fine.

Basically I want to create a Twilio function that checks my Airtable database every day to process incoming SMS replies. The workflow should be:

  1. Function searches Airtable table for today’s date entries
  2. Gets the incoming SMS text content
  3. Checks if the reply matches what we expect and sends success message from database
  4. Sends different message from database if reply doesn’t match

Here’s my current function code:

const airtableLib = require("airtable");
const twilioLib = require("twilio");

exports.handler = function (context, event, callback) {
 const db = new airtableLib({
   apiKey: context.AIRTABLE_API_KEY,
 }).base(context.AIRTABLE_BASE_ID);
 const response = new twilioLib.twiml.MessagingResponse();
 const today = new Date();
 const userReply = event.Body.toLowerCase();

 return db("daily_questions")
   .select(entry.get("date") === today)
   .all()
   .then((entries) => {
     entries.forEach((entry) => {
       if (entry.get("expected_answer") === userReply) {
         response.message(entry.get("success_msg"));
         callback(null, response);
       }
     });
     response.message(entry.get("failure_msg"));
     callback(null, response);
   })
   .catch((err) => {
     callback(err);
   });
};

The function isn’t working as expected. Any ideas what might be wrong with my approach?

Your code has several issues. The biggest one - you’re calling callback multiple times, which breaks everything.

Here’s what’s happening: when you find a match, you call callback(null, response) inside the forEach loop. But then the code keeps running and calls callback again with the failure message. Twilio functions can only respond once.

Your select filter syntax is also wrong. It needs to be a filterByFormula string, not a function.

I ran into the same Twilio webhook issues last year. Here’s the fix:

const todayStr = today.toISOString().split('T')[0]; // gets YYYY-MM-DD format

return db("daily_questions")
  .select({
    filterByFormula: `DATESTR({date}) = '${todayStr}'`
  })
  .all()
  .then((entries) => {
    let matchFound = false;
    
    entries.forEach((entry) => {
      if (entry.get("expected_answer") === userReply) {
        response.message(entry.get("success_msg"));
        matchFound = true;
      }
    });
    
    if (!matchFound && entries.length > 0) {
      response.message(entries[0].get("failure_msg"));
    }
    
    callback(null, response);
  })

The key is handling the callback only once at the end, not inside loops.

your date comparison logic is broken - entry.get("date") === today won’t work bc Airtable stores dates as strings. format both dates to the same format (like YYYY-MM-DD) before comparing them.