Function Execution
The Twilio Function runtime environment is lightweight, giving you the flexibility to build and deploy code quickly. This topic explains how your code runs, which variables and utilities the environment provides, and how to return a valid response.
During a Function invocation, the following steps occur:
- Environment bootstrap: The runtime environment starts and initializes any resources that your Function code requires.
- Handler execution: The runtime executes the
exports.handlermethod that your code defines and supplies thecontext,event, andcallbackparameters, along with several useful global utilities. - Response emitted: When your code finishes, call
callback()to emit the response. Aftercallback()returns, the runtime terminates execution, including any asynchronous operations that are still running.
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, similar to a main() function in Java or an __init__ method in Python.
Twilio Functions executes your handler method when it is ready to hand off control to your code. If your Function code does not contain a handler method, Twilio Functions returns an HTTP 500 error.
| Argument | Type | Description |
|---|---|---|
context | object | Information about the current execution environment |
event | object | The request parameters passed into the Function |
callback | function | Function that completes execution and emits the response |
Twilio Function handler method boilerplate
1exports.handler = (context, event, callback) => {2// Your application logic34// Emit a response and stop execution.5return callback();6};
Twilio Functions provides the context object as an interface between the current execution environment and the handler method. The context object gives you access to helper methods and to your environment variables.
The helper methods on context return pre-initialized utilities and clients. They retrieve configuration from your environment variables.
| Method | Type | Description |
|---|---|---|
getTwilioClient() | Twilio REST Helper | Returns an initialized Twilio REST SDK client if account credentials are included in the Function. If credentials are not available, the method throws an error, which results in an HTTP 500 response unless your code handles the exception. |
Example of using the built-in Twilio REST Helper
1exports.handler = (context, event, callback) => {2// Access the pre-initialized Twilio REST client3const twilioClient = context.getTwilioClient();45// Determine message details from the incoming event, with fallback values6const from = event.From || "+15095550100";7const to = event.To || "+15105550101";8const body = event.Body || "Ahoy, World!";910twilioClient.messages11.create({ to, from, body })12.then((result) => {13console.log("Created message using callback");14console.log(result.sid);15return callback();16})17.catch((error) => {18console.error(error);19return callback(error);20});21};
Use environment variables to separate code from configuration. This approach keeps your code portable and lets you change configuration without redeploying.
For more details and examples, see the Environment variables documentation.
Example of how to access the default environment variables
1exports.handler = (context, event, callback) => {2// Check to see if the domain name is null3const domain = context.DOMAIN_NAME || "No domain available";4// Respond with the domain hosting this Function5return callback(null, domain);6};
Example of how to access environment variables
1exports.handler = (context, event, callback) => {2// Get the primary and secondary phone numbers, if set3const primary =4context.PRIMARY_PHONE_NUMBER || "There is no primary number";5const secondary =6context.SECONDARY_PHONE_NUMBER || "There is no secondary number";78// Build the response object9const response = {10phone_numbers: {11primary,12backup: secondary,13},14};1516// Return the response object as JSON17return callback(null, response);18};
The event object contains the request parameters and headers passed into your Function. POST and GET parameters are merged into the same object. For POST requests, you can send either form-encoded parameters or JSON documents; both formats populate the event object.
The specific values available on event depend on the context in which your Function is invoked and the parameters it receives. The following sections describe common use cases.
If the Function acts as the webhook for an incoming SMS or voice call, event contains a predefined set of parameters related to the phone number. Examples include event.From, which resolves to the E.164-formatted phone number, and event.Body, which returns the text of an incoming SMS.
An incoming message produces an event object similar to the following:
1{2"ToCountry": "US",3"ToState": "CA",4"SmsMessageSid": "SMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",5"NumMedia": "0",6"ToCity": "BOULEVARD",7"FromZip": "",8"SmsSid": "SMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",9"FromState": "WA",10"SmsStatus": "received",11"FromCity": "",12"Body": "Ahoy!",13"FromCountry": "US",14"To": "+15555555555",15"ToZip": "91934",16"NumSegments": "1",17"MessageSid": "SMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",18"AccountSid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",19"From": "+14444444444",20"ApiVersion": "2010-04-01",21"request": {22"headers": { ... },23"cookies": { ... }24}25}
Refer to the dedicated Messaging and Voice webhook documentation for the full list of available properties.
Webhook parameter naming
Webhook properties are always in PascalCase. Make sure you capitalize the first letter of commonly used variables, such as From.
Example of how to access webhook values by name from the event object in a Function
1exports.handler = (context, event, callback) => {2// Prepare a new messaging response object; no need to import Twilio3const twiml = new Twilio.twiml.MessagingResponse();4// Access incoming text information such as the sender and message body5twiml.message({ to: context.MY_NUMBER }, `${event.From}: ${event.Body}`);6// Return the TwiML as the second argument to `callback`7return callback(null, twiml);8};
If the Function is executed in response to an HTTP request, the contents of event correspond to the request's query parameters and body (if any).
Given a Function with the URL http-7272.twil.io/response and the following request:
curl -X GET 'https://http-7272.twil.io/response?age=42&firstName=Rick'
event is:
1{2"firstName": "Rick",3"age": "42",4"request": {5"headers": { ... },6"cookies": { ... }7}8}
For a POST request that includes query parameters and a JSON body:
1curl -L -X POST 'https://http-7272.twil.io/response?age=42&firstName=Rick' \2-H 'Content-Type: application/json' \3--data-raw '{4"color": "orange"5}'
event becomes:
1{2"firstName": "Rick",3"age": "42",4"color": "orange",5"request": {6"headers": { ... },7"cookies": { ... }8}9}
POST request parameter precedence
For a POST request, query parameters and any JSON in the request body are merged into the same object. If a property such as age appears in both places, the value from the JSON body takes precedence and overwrites the value from the query
string in event.
Accessing headers and cookies in the event object
The event object also contains a nested request object with headers and cookies. To learn how to use these values, see the accessing headers and cookies
documentation.
Example that returns an error with HTTP 500 Internal Server Error
1exports.handler = (context, event, callback) => {2// Passing a single string or an Error object returns HTTP 500 Internal Server Error.3return callback('Something went very, very wrong.');4};
Example that returns an empty HTTP 200 OK
1exports.handler = (context, event, callback) => {2// If you pass neither an error nor a response, Functions returns HTTP 200 OK.3return callback();4};
Example that returns plain text with HTTP 200 OK
1exports.handler = (context, event, callback) => {2// Passing a string returns HTTP 200 OK.3return callback(null, 'This is fine');4};
Example that returns JSON with HTTP 200 OK
1exports.handler = (context, event, callback) => {2// Build an object in any way you prefer.3const response = { result: 'winner winner!' };4// Returning a JavaScript object causes the runtime to serialize it to JSON5// and set Content-Type: application/json automatically.6return callback(null, response);7};
In addition to the standard response types, Functions supports generating and returning TwiML.
The callback function accepts TwiML objects—such as MessagingResponse and VoiceResponse—as its second argument.
When you pass TwiML in this way, the runtime serializes it to XML and sets the correct Content-Type header for you. You don't need to stringify the TwiML or manually specify headers.
1exports.handler = (context, event, callback) => {2// Create a new MessagingResponse object.3const twiml = new Twilio.twiml.MessagingResponse();4// Use any of the Node.js SDK methods, such as message(), to compose the reply.5twiml.message('Hello, World!');6// Return the TwiML as the second argument to callback().7// The runtime renders the response as XML.8return callback(null, twiml);9};
1exports.handler = (context, event, callback) => {2// Create a new VoiceResponse object.3const twiml = new Twilio.twiml.VoiceResponse();45// Webhook information is available as properties of the event object.6const city = event.FromCity;7const number = event.From;89// Optionally change the voice, add template variables, play audio, and more.10twiml.say({ voice: 'alice' }, `Never gonna give you up, ${city || number}`);11twiml.play('https://demo.twilio.com/docs/classic.mp3');1213// Return the TwiML as the second argument to callback().14// The runtime renders the response as XML.15return callback(null, twiml);16};
In addition to the helpers provided through the context, event, and callback parameters, you can use several globally scoped classes without importing additional Dependencies.
The global Twilio class is always available. Use it to create TwiML or Access Tokens in your Function responses. For example:
1// Initialize TwiML without importing Twilio2const response = new Twilio.twiml.MessagingResponse();34// Work with other utilities, such as Access Tokens5const AccessToken = Twilio.jwt.AccessToken;6const SyncGrant = AccessToken.SyncGrant;
You can access the Runtime Client through the global Runtime object. The client provides helper methods for working with private Assets, other Functions, and the Sync client. For example:
1const text = Runtime.getAssets()["/my-file.txt"].open();2console.log("Your file contents: " + text);
Sometimes your Function needs finer control over the response it returns. In those cases, use the Twilio Response object, which is available in the Function's global scope by default—you don't need to import Twilio.
With the Twilio Response object, you can set the status code, headers, and body of the response. Start by creating a new Twilio Response object, as shown in the following example:
1// Twilio is globally available in Functions; no import required2const response = new Twilio.Response();
| Method | Return type | Description |
|---|---|---|
setStatusCode(int) | self | Sets the HTTP status code for the response. |
setBody(mixed) | self | Sets the response body. Accepts a string or an object. If you set the body to any format other than plain text, make sure to specify the matching Content-Type header by calling appendHeader(). |
appendHeader(string, string) | self | Adds a single header to the response. The first argument is the header name and the second argument is the header value. |
setHeaders(object) | self | Replaces all existing headers with the headers provided in the object. Each key is a header name and each value is the corresponding header value. |
Example of setting a status code by using Twilio Response
1exports.handler = (context, event, callback) => {2// Twilio is globally available in Functions3const response = new Twilio.Response();45// Set the status code to 204 No Content6response.setStatusCode(204);78return callback(null, response);9};
Example of building a plain-text response with Twilio Response
1exports.handler = (context, event, callback) => {2// Twilio is globally available in Functions3const response = new Twilio.Response();45response6// Set the status code to 200 OK7.setStatusCode(200)8// Set the response body9.setBody('This is fine');1011return callback(null, response);12};
Example of building a JSON response with Twilio Response
1exports.handler = (context, event, callback) => {2// Twilio is globally available in Functions3const response = new Twilio.Response();45response6// Set the status code to 200 OK7.setStatusCode(200)8// Specify the content type9.appendHeader('Content-Type', 'application/json')10// Set the response body11.setBody({12everything: 'is alright',13});1415return callback(null, response);16};
Example of setting a header by using Twilio Response
1exports.handler = (context, event, callback) => {2// Twilio is globally available in Functions3const response = new Twilio.Response();45response6// Set the status code to 301 Moved Permanently7.setStatusCode(301)8// Set the Location header for the redirect9.appendHeader('Location', 'https://twilio.com');1011return callback(null, response);12};
Example of setting multiple headers with Twilio Response
1exports.handler = (context, event, callback) => {2// Twilio is globally available in Functions3const response = new Twilio.Response();45// Map of headers to set in a single call6const headers = {7'Access-Control-Allow-Origin': 'example.com',8'Access-Control-Allow-Methods': 'GET, PUT, POST, DELETE, OPTIONS',9'Access-Control-Allow-Headers': 'Content-Type',10};1112response.setHeaders(headers);1314return callback(null, response);15};
You now understand the core components of writing a Function. For more details and hands-on material, review the Function examples.
Next, learn how Function and Asset visibility affects access to, and use of, your projects.