Skip to contentSkip to navigationSkip to topbar
Rate this page:
On this page

Function Execution


The Twilio Function runtime environment is lightweight by design to provide developers with all the flexibility they need. Read on to learn about how your code is executed, what variables and tools this environment provides, and ways you could create a valid response.

During Function invocation, the following steps occur:

  1. Environment Bootstrap - The Twilio Function environment is bootstrapped, and any resources your Function code may rely on are quickly initialized.
  2. Handler Execution - The Twilio Environment will then execute the exports.handler method that your code defines, and provide the context , event , and callback parameters, in addition to a selection of useful global utility methods.
  3. Response Emitted - When your Twilio Function code has completed, your code must call the callback() method in order to emit your response. After executing the callback() method, your Twilio Function execution will be terminated. This includes any asynchronous processes that may still be executing.

Handler Method

handler-method page anchor

The handler method is the interface between Twilio Functions and your application logic. You can think of the handler method as the entry point to your application. This is somewhat analogous to a main() function in Java or __init__ in Python.

Twilio Functions will execute your handler method when it is ready to hand off control of execution to your application logic. If your Function Code does not contain a handler method, Twilio Functions will be unable to execute your logic and will emit an HTTP 500 error.

Handler Arguments

handler-arguments page anchor
ArgumentTypeDescription
contextobjectProvides information about the current execution environment
eventobjectContains the request parameters passed into your Twilio Function
callbackfunctionFunction used to complete execution and emit responses

Handler Method Boilerplate

handler-method-boilerplate page anchor

Twilio Function Handler Method Boilerplate


_10
exports.handler = (context, event, callback) => {
_10
// Your application logic
_10
_10
// To emit a response and stop execution, call the callback() method
_10
return callback();
_10
}


Twilio Functions provides the context object as an interface between the current execution environment and the handler method. The context object provides access to helper methods, as well as your Environment Variables.

The context object provides helper methods that pre-initialize common utilities and clients that you might find useful when building your application. These helper methods extract all their required configuration from Environment Variables.

MethodTypeDescription
getTwilioClient()Twilio REST HelperIf you have enabled the inclusion of your account credentials in your Function, this will return an initialized Twilio REST Helper Library(link takes you to an external page). If you have not included account credentials in your Function, calling this method will result in an error. If your code doesn't catch this error, it will result in an HTTP 500 response.

Use built-in Twilio REST Helper to send an SMS Message

use-built-in-twilio-rest-helper-to-send-an-sms-message page anchor

Example of using built-in Twilio REST Helper


_21
exports.handler = (context, event, callback) => {
_21
// Access the pre-initialized Twilio REST client
_21
const twilioClient = context.getTwilioClient();
_21
_21
// Determine message details from the incoming event, with fallback values
_21
const from = event.From || '+15095550100';
_21
const to = event.To || '+15105550101';
_21
const body = event.Body || 'Ahoy, World!';
_21
_21
twilioClient.messages
_21
.create({ to, from, body })
_21
.then((result) => {
_21
console.log('Created message using callback');
_21
console.log(result.sid);
_21
return callback();
_21
})
_21
.catch((error) => {
_21
console.error(error);
_21
return callback(error);
_21
});
_21
};

We encourage developers to use Environment Variables to separate their code from configuration. Using Environment Variables ensures that your code is portable, and that simple configuration changes can be made instantly.

For a more in-depth explanation and examples, refer to the Environment Variables documentation.

Retrieve Domain from Default Environment Variables

retrieve-domain-from-default-environment-variables page anchor

Example of how to access the Default Environment Variables


_10
exports.handler = (context, event, callback) => {
_10
// Check to see if the Domain name is null
_10
const domain = context.DOMAIN_NAME || 'No Domain available';
_10
// Respond with the Domain hosting this Function
_10
return callback(null, domain);
_10
};

Retrieve Environment Variables

retrieve-environment-variables page anchor

Example of how to access Environment Variables


_16
exports.handler = (context, event, callback) => {
_16
// Get the primary and secondary phone numbers, if set
_16
const primary = context.PRIMARY_PHONE_NUMBER || 'There is no primary number';
_16
const secondary = context.SECONDARY_PHONE_NUMBER || 'There is no secondary number!';
_16
_16
// Build our response object
_16
const response = {
_16
phone_numbers: {
_16
primary,
_16
backup: secondary,
_16
},
_16
};
_16
_16
// Return the response object as JSON
_16
return callback(null, response);
_16
};


The event object contains the request parameters and headers being passed into your Function. Both POST and GET parameters will be collapsed into the same object. For POST requests, you can pass either form encoded parameters or JSON documents; both will be collapsed into the event object.

The specific values that you'll be able to access on event are dependent on what context your Function is being used in and what parameters it is receiving. We'll cover some common use cases and general scenarios below, so you can get the most out of event.

If you have configured your Function to act as the webhook for an action, such as an incoming SMS or phone call, event will contain a very specific set of values related to the phone number in question. These will be values such as event.From, which resolves to the E.164 formatted phone number as a string, event.Body, which returns the text message of an incoming SMS, and many more. For example, an incoming message will result in event having this shape:


_25
{
_25
"ToCountry": "US",
_25
"ToState": "CA",
_25
"SmsMessageSid": "SMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
_25
"NumMedia": "0",
_25
"ToCity": "BOULEVARD",
_25
"FromZip": "",
_25
"SmsSid": "SMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
_25
"FromState": "WA",
_25
"SmsStatus": "received",
_25
"FromCity": "",
_25
"Body": "Ahoy!",
_25
"FromCountry": "US",
_25
"To": "+15555555555",
_25
"ToZip": "91934",
_25
"NumSegments": "1",
_25
"MessageSid": "SMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
_25
"AccountSid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
_25
"From": "+14444444444",
_25
"ApiVersion": "2010-04-01",
_25
"request": {
_25
"headers": { ... },
_25
"cookies": { ... }
_25
},
_25
}

Refer to the dedicated Messaging and Voice Webhook documentation to learn the full list of properties which you can leverage in your Functions.

(information)

Info

Webhook properties are always in PascalCase(link takes you to an external page); check to make sure that you have capitalized the first letter of commonly used variables, such as From.

Access webhook values from event

access-webhook-values-from-event page anchor

Example of how to access webhook values by name from the event object in a Function


_10
exports.handler = (context, event, callback) => {
_10
// Prepare a new messaging response object; no need to import Twilio
_10
const twiml = new Twilio.twiml.MessagingResponse();
_10
// Access incoming text information like the from number and contents off of `event`
_10
// Access environment variables and other runtime data from `context`
_10
twiml.message({ to: context.MY_NUMBER }, `${event.From}: ${event.Body}`);
_10
// Remember to return the TwiML as the second argument to `callback`
_10
return callback(null, twiml);
_10
};

Parameters from HTTP requests

parameters-from-http-requests page anchor

If your Function is being executed in response to an incoming HTTP request, then the contents of event will directly correspond to the request's query parameters and request body (if any).

For example, given a Function with the URL of http-7272.twil.io/response and this request:


_10
curl -X GET 'https://http-7272.twil.io/response?age=42&firstName=Rick'

The resulting event object will be:


_10
{
_10
"firstName": "Rick",
_10
"age": "42",
_10
"request": {
_10
"headers": { ... },
_10
"cookies": { ... }
_10
}
_10
}

Similarly, given a POST request with query parameters, a JSON body, or both such as:


_10
curl -L -X POST 'https://http-7272.twil.io/response?age=42&firstName=Rick' \
_10
-H 'Content-Type: application/json' \
_10
--data-raw '{
_10
"color": "orange"
_10
}'

the Function of the receiving end will then have access to an event object with these contents:


_10
{
_10
"firstName": "Rick",
_10
"age": "42",
_10
"color": "orange",
_10
"request": {
_10
"headers": { ... },
_10
"cookies": { ... }
_10
}
_10
}

(warning)

Warning

In the case of a POST request, query parameters and any JSON in the body of the request will be merged into the same object. If a property such as age is defined in both parts of the request, the value defined in the JSON body takes precedence and will overwrite the initial value from the query parameters in event.

(information)

Info

You might have noticed that event also contains a request object with headers and cookies that aren't explicitly part of the request(s). To learn more about this aspect of event and how you can leverage request headers and cookies, refer to the accessing headers and cookies documentation.

Parameters from the Run Function Widget

parameters-from-the-run-function-widget page anchor

Similar to a direct HTTP request, a Run Function widget is invoking a Function, that Function's event will be populated by any arguments specified in the configuration of that particular Run Function widget.

Refer to the Use the Run Function widget in Studio example to see what this looks like in practice when combining Functions and Studio Flows.


When you have finished processing your request, you need to invoke the callback function to emit a response and signal that your Function has completed its execution. The callback method will automatically determine the data type of your response and serialize the output appropriately.

You must invoke the callback method when your Function is done processing. Failure to invoke callback will cause your Function to continue running up to the 10-second execution time limit. When your Function reaches the execution time limit, it will be terminated, and a 504 Gateway timeout error will be returned to the client.

Callback and Asynchronous Limitations

callback-and-asynchronous-limitations page anchor

It is important to note that when the callback function is invoked, it will terminate all execution of your Function. This includes any asynchronous processes you may have kicked off during the execution of your handler method.

For this reason, if you are using libraries that are natively asynchronous and/or operate using Promises(link takes you to an external page), you must properly handle this asynchronous behavior. Structure your code to call callback within the correct callback methods, .then chains, or after await in async functions.

Complete Execution with Asynchronous HTTP Request

complete-execution-with-asynchronous-http-request page anchor

Example of how to appropriately use callback() with an asynchronous HTTP request


_26
exports.handler = (context, event, callback) => {
_26
// Fetch the already initialized Twilio REST client
_26
const client = context.getTwilioClient();
_26
_26
// Determine message details from the incoming event, with fallback values
_26
const from = event.From || '+15095550100';
_26
const to = event.To || '+15105550101';
_26
const body = event.Body || 'Ahoy, World!';
_26
_26
client.messages
_26
.create({ to, from, body })
_26
.then((result) => {
_26
console.log('Created message using callback');
_26
console.log(result.sid);
_26
// Callback is placed inside the successful response of the request
_26
return callback();
_26
})
_26
.catch((error) => {
_26
console.error(error);
_26
// Callback is also used in the catch handler to end execution on errors
_26
return callback(error);
_26
});
_26
_26
// If you were to place the callback() function here, instead, then the process would
_26
// terminate before your API request to create a message could complete.
_26
};

ArgumentTypeDescription
errorstring|nullError indicating what problem was encountered during execution. Defining this value (as anything but null or undefined) will result in the client receiving a HTTP 500 response with the provided payload.
responsestring|object|nullSuccessful response generated by the Function. Providing this argument will result in the client receiving a HTTP 200 response containing the provided value.

How do I return an error?

how-do-i-return-an-error page anchor

If you have encountered an exception in your code or otherwise want to indicate an error state, invoke the callback method with the error object or intended message as a single parameter:


_10
return callback(error);

How do I return a successful response?

how-do-i-return-a-successful-response page anchor

To signal success and return a value, pass a falsy value such as null or undefined as the first parameter to callback, and your intended response as the second parameter:


_10
return callback(null, response);

(information)

Info

Please note that all samples demonstrate using the return keyword before calling callback. This is to prevent subsequent code from unintentionally running before handler is terminated, or from calling callback multiple times, and is considered a best practice when working with Functions.

Return an Error Response

return-an-error-response page anchor

Example of how to return an error message with HTTP 500 Error


_10
exports.handler = (context, event, callback) => {
_10
// Providing a single string or an Error object will result in a 500 Error
_10
return callback('Something went very, very wrong.');
_10
};

Return a Simple Successful Response

return-a-simple-successful-response page anchor

Example of how to return an empty HTTP 200 OK


_10
exports.handler = (context, event, callback) => {
_10
// Providing neither error nor response will result in a 200 OK
_10
return callback();
_10
};

Return a Successful Plaintext Response

return-a-successful-plaintext-response page anchor

Example of how to return plaintext with HTTP 200 OK


_10
exports.handler = (context, event, callback) => {
_10
// Providing a string will result in a 200 OK
_10
return callback(null, 'This is fine');
_10
};

Return a Successful JSON Response

return-a-successful-json-response page anchor

Example of how to return JSON in HTTP 200 OK


_10
exports.handler = (context, event, callback) => {
_10
// Construct an object in any way
_10
const response = { result: 'winner winner!' };
_10
// A JavaScript object as a response will be serialized to JSON and returned
_10
// with the Content-Type header set to "application/json" automatically
_10
return callback(null, response);
_10
};

How do I return TwiML?

how-do-i-return-twiml page anchor

In addition to the standard response types, Functions has built-in support to allow you to quickly generate and return TwiML for your application's needs.

This is such a common use case that callback directly accepts valid TwiML objects, such as MessagingResponse and VoiceResponse, as the second argument. If you return TwiML in this way, the environment will automatically convert your response to XML without any extra work required on your part. (Such as stringifying the TwiML and specifying a response content type)

Return a static Messaging response to incoming text messages

return-a-static-messaging-response-to-incoming-text-messages page anchor

_10
exports.handler = (context, event, callback) => {
_10
// Create a new messaging response object
_10
const twiml = new Twilio.twiml.MessagingResponse();
_10
// Use any of the Node.js SDK methods, such as `message`, to compose a response
_10
twiml.message('Hello, World!');
_10
// Return the TwiML as the second argument to `callback`
_10
// This will render the response as XML in reply to the webhook request
_10
return callback(null, twiml);
_10
};

Return a Voice response that includes Say and Play verbs

return-a-voice-response-that-includes-say-and-play-verbs page anchor

_15
exports.handler = (context, event, callback) => {
_15
// Create a new voice response object
_15
const twiml = new Twilio.twiml.VoiceResponse();
_15
// Webhook information is accessible as properties of the `event` object
_15
const city = event.FromCity;
_15
const number = event.From;
_15
_15
// You can optionally edit the voice used, template variables into your
_15
// response, play recorded audio, and more
_15
twiml.say({ voice: 'alice' }, `Never gonna give you up, ${city || number}`);
_15
twiml.play('https://demo.twilio.com/docs/classic.mp3');
_15
// Return the TwiML as the second argument to `callback`
_15
// This will render the response as XML in reply to the webhook request
_15
return callback(null, twiml);
_15
};


In addition to the values and helpers available through the context, event, and callback parameters, you have access to some globally-scoped helper classes that you can access without needing to import any new Dependencies.

The Twilio class is accessible at any time. This is commonly used to initialize TwiML or Access Tokens for your Function responses. For example:


_10
// Initialize TwiML without needing to import Twilio
_10
const response = new Twilio.twiml.MessagingResponse();
_10
_10
// Similarly for other utilities, such as Access Tokens
_10
const AccessToken = Twilio.jwt.AccessToken;
_10
const SyncGrant = AccessToken.SyncGrant;

The Runtime Client is accessible via Runtime, and exposes helper methods for accessing private Assets, other Functions, and the Sync client. For example:


_10
const text = Runtime.getAssets()['/my-file.txt'].open();
_10
console.log('Your file contents: ' + text);


In some instances, your Function may need greater control over the response it is going to emit. For those instances, you can use the Twilio Response object that is available in the global scope of your Function by default. No need to import Twilio yourself!

By using the Twilio Response object, you will be able to specify the status code, headers, and body of your response. You can begin constructing a custom response by creating a new Twilio Response object, like so:


_10
// No need to import Twilio; it is globally available in Functions
_10
const response = new Twilio.Response();

MethodReturn TypeDescription
setStatusCode(int)selfSets the status code in the HTTP response
setBody(mixed)selfSets the body of the HTTP response. Takes either an object or string. When setting the body to anything other than text, make sure to set the corresponding Content-Type header with appendHeader()
appendHeader(string, string)selfAdds a header to the HTTP response. The first argument specifies the header name and the second argument the header value
setHeaders(object)selfSets all of the headers for the HTTP response. Takes an object mapping the names of the headers to their respective values

Set a Status Code in a Response

set-a-status-code-in-a-response page anchor

Example of setting a Status Code using Twilio Response


_10
exports.handler = (context, event, callback) => {
_10
// No need to import Twilio; it is globally available in Functions
_10
const response = new Twilio.Response();
_10
_10
// Set the status code to 204 Not Content
_10
response.setStatusCode(204);
_10
_10
return callback(null, response);
_10
};

Build a Plaintext Response

build-a-plaintext-response page anchor

Example of building a plaintext response with Twilio Response


_12
exports.handler = (context, event, callback) => {
_12
// No need to import Twilio; it is globally available in Functions
_12
const response = new Twilio.Response();
_12
_12
response
_12
// Set the status code to 200 OK
_12
.setStatusCode(200);
_12
// Set the response body
_12
.setBody('This is fine');
_12
_12
return callback(null, response);
_12
};

Building a JSON Response

building-a-json-response page anchor

Example of building a JSON response with Twilio Response


_16
exports.handler = (context, event, callback) => {
_16
// No need to import Twilio; it is globally available in Functions
_16
const response = new Twilio.Response();
_16
_16
response
_16
// Set the status code to 200 OK
_16
.setStatusCode(200)
_16
// Set the Content-Type Header
_16
.appendHeader('Content-Type', 'application/json')
_16
// Set the response body
_16
.setBody({
_16
everything: 'is alright',
_16
});
_16
_16
return callback(null, response);
_16
};

Set an HTTP Header in a Response

set-an-http-header-in-a-response page anchor

Example of setting an header using Twilio Response


_12
exports.handler = (context, event, callback) => {
_12
// No need to import Twilio; it is globally available in Functions
_12
const response = new Twilio.Response();
_12
_12
response
_12
// Set the status code to 301 Redirect
_12
.setStatusCode(301);
_12
// Set the Location header for redirect
_12
.appendHeader('Location', 'https://twilio.com');
_12
_12
return callback(null, response);
_12
};

Set Multiple HTTP Headers in a Response

set-multiple-http-headers-in-a-response page anchor

Example of setting multiple headers using Twilio Response


_16
exports.handler = (context, event, callback) => {
_16
// No need to import Twilio; it is globally available in Functions
_16
const response = new Twilio.Response();
_16
_16
// Build a mapping of headers as a way to set many with one command
_16
const headers = {
_16
'Access-Control-Allow-Origin': 'example.com',
_16
'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE,OPTIONS',
_16
'Access-Control-Allow-Headers': 'Content-Type',
_16
};
_16
_16
// Set headers in response
_16
response.setHeaders(headers);
_16
_16
return callback(null, response);
_16
};


By now, you should have a pretty good idea of what goes into writing a Function. (Although there are plenty of specifics and examples yet to learn)

The next important step in your journey is to understand the concept of visibility, and how it affects access to and use of your Functions (and Assets)!


Rate this page: