Deploying an AWS Lambda Function for Vonage Voice Callbacks With PHP
Published on May 18, 2021

Deploying a complete and web-accessible application to AWS Lambda presents a unique set of requirements and hurdles. Among these are execution and permissions settings. In this post, I'll build upon a few previous posts, bringing them together as a practical example.

This post uses a sample callback application from "AWS Transcribe with Nexmo Voice Using PHP". It also leverages "AWS Lambda with PHP Using Bref and Serverless Framework". I also apply the permissions model shown in "How Permissions Work In AWS Lambda" for AWS S3 and Amazon Transcribe. Together these pieces allow you to create your own AWS Lambda function, creating a transcription microservice to be used in your applications.

Note: You won't need to go through the three posts mentioned above to follow along with this one. I thoroughly cover everything you need to know below.

Prerequisites

In this example the following are needed:

DT API Account

To complete this tutorial, you will need a DT API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the DT API Dashboard.

This tutorial also uses a virtual phone number. To purchase one, go to Numbers > Buy Numbers and search for one that meets your needs.

AWS Setup

You'll need an AWS account, as well as IAM credentials associated with a user who has sufficient privileges. That permission ensures Serverless can create the Lambda function and assign permissions as needed.

Create an S3 Bucket

Create an S3 Bucket to store the voice recording MP3 files retrieved from Vonage. Amazon Transcribe can then easily access the files for transcription later.

After creating it, make sure to check the box beside the bucket name. A panel opens from the right, so you can click the button "Copy Bucket ARN" and save it for later usage.

Creating an IAM User

Select the IAM Management Console from the Services panel:

Select IAM Management ConsoleSelect IAM Management Console

From the IAM Management Console, add a new IAM user by clicking the blue Add User button:

AWS new IAM userAdd a new IAM user

Below is a JSON snippet to assign the permissions needed for the new user.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "*",
            "Resource": "*"
        }
    ]
}

Serverless Framework

The Bref tool leverages the Serverless Framework foundation, which is a "complete solution for building and operating serverless applications." Thus, our first step is to get this framework installed on the development system you're using. I recommend installing it globally, to allow usage from anywhere via CLI.

npm install -g serverless

AWS Credentials

With Serverless installed, ensure you've also set up the AWS credentials above as an admin, for Serverless to interact with the various AWS services. You can read more about this at serverless.com and bref.sh so that we won't go into the details here.

Application Preparation

Next, we prepare the application using Composer to retrieve dependencies. A small edit is required in the code to work correctly with the Lambda URLs.

Composer

Preparing the application takes a couple of steps before doing the Composer install. We need to require Bref to perform the Serverless functionalities. Type the following in your terminal after navigating to the project directory containing the code.

composer install composer require bref/bref

The first command installs the dependencies of the application. Then, the second command adds Bref along with dependencies needed for it. Alternatively, you could edit the composer.json file to require Bref and only run the install command.

Bref Init

Typically, for a new application, you would command Bref to init, and create serverless.yml and index.php. However, in this case, you should simply create a file named serverless.yml in the root directory as follows:

service: app

provider:
    name: aws
    region: us-east-1
    runtime: provided
    iamRoleStatements:
        - Effect: Allow
          Action:
              - s3:PutObject
              - s3:GetObject
              - s3:DeleteObject
          Resource: 'arn:aws:s3:::{{bucket-name}}/*'
        - Effect: Allow
          Action: transcribe:*
          Resource: '*'

plugins:
    - ./vendor/bref/bref

functions:
    api:
        handler: index.php
        description: ''
        timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
        layers:
            - ${bref:layer.php-73-fpm}
        events:
            -   http: 'ANY /'
            -   http: 'ANY /{proxy+}'

# Exclude files from deployment
package:
    exclude:
        - 'node_modules/**'
        - 'tests/**'

Note: You should update the AWS region and replace {{bucket-name}} to match your needs.

Also, notice that iamRoleStatements is setting permissions for the Lambda to use AWS S3 as well as Amazon Transcribe. See the post "How Permissions Work in AWS Lambda", mentioned above, for more details.

Environment Variables

As a part of the preparation, rename the .env.default file to become .env, and update as needed to suit your AWS and Vonage account information. Though you can safely ignore AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, because those are automatically added to the environment by Lambda.

You will also not be able to populate the VONAGE_APPLICATION_PRIVATE_KEY_PATH and VONAGE_APPLICATION_ID values until AFTER you deploy to Lambda, causing the need to deploy to Lambda twice. The first time to provide you with the URLs needed to create the Vonage Application. Then, the second deployment contains an updated .env file with the Vonage values. That's all covered later.

Event URLs

Because of the difference in how Lambda handles the URI, you will also need to edit the index.php file in the application. Specifically, you will need to alter the eventUrl on lines 33 and 47. The end result will look like the following, respectively:

// Line 33
'https://'.$uri->getHost().'/dev/webhooks/fetch'
// Line 47
'https://'.$uri->getHost().'/dev/webhooks/transcribe'

The update is caused by the $request not showing with https, and Lambda also includes the environment in the API Gateway URLs.

Deploying

Will all the steps above completed, you are now ready to deploy the application to Lambda using Serverless. In your terminal, issue the following command:

serverless deploy

After deployment, you receive the URL needed to access the application via the API Gateway. Make a note of the URL for the next step.

IMPORTANT: The example application, as-is, does not carry any authentication or verification. Anyone with access to the URL provided after deployment can access it. Doing so could cause unexpected charges to your accounts. Therefore, please secure the app if you intend to leave it active.

Vonage Setup

Unfortunately, in the case of deploying AWS Lambda applications, you did not know the URL until after deployment. However, you still need to create the Application at Vonage to gain the VONAGE_APPLICATION_PRIVATE_KEY_PATH and VONAGE_APPLICATION_ID for the application to function.

Using the Vonage CLI, installed as a prerequisite, enter the following command:

vonage app:create /webhooks/answer /webhooks/event

As an example, the command might look like this:

vonage app:create MyTranscripeApp https://asdrferwef.execute-api.us-east-1.amazonaws.com/dev/webhooks/answer https://asdrferwef.execute-api.us-east-1.amazonaws.com/dev/webhooks/event

The response from the command provides the Application ID and the Private Key, to be used in the following steps.

Update Private Key

Rename the file private.key.default to private.key and save the Private Key into the file.

Update .env

Update the .env file with the values for VONAGE_APPLICATION_PRIVATE_KEY_PATH and VONAGE_APPLICATION_ID. It will look something like this:

VONAGE_APPLICATION_PRIVATE_KEY_PATH=./private.key VONAGE_APPLICATION_ID=2735sd6ed1asd-29cf4-4858f-bd90sd-7135a8cf122bas

Number Association

The last step to prepare Vonage is to associate the rented Vonage number with the newly created application. Use the following command for this:

vonage link:app

Make sure to update the variables above with your Vonage number and the app_id given with the Application creation. Ensure you prepend the country code, to prevent failure. Here is an example:

vonage link:app 2735sd6ed1asd-29cf4-4858f-bd90sd-7135a8cf122bas --number=+15558675309

More Details

Creating the Vonage application, and associating the number, instructs Vonage to make callbacks when events happen, and you want those callbacks to point to the newly created app.

The Event URL is for when an event changes the status of a call, while the Answer URL is requested for any inbound calls to retrieve an NCCO object (Nexmo Call Control Object).

Now we are finished with the Vonage setup. Time to redeploy to Lambda with the following command:

serverless deploy

After a couple of minutes, the updated application will be redeployed to Lambda. Though the contents of the application will have changed, the URL remains constant.

Testing

Now it is time to make a test call to your Vonage number. After calling, the automated voice should say, "Please leave a message after the tone, then press #". unless you changed that message in index.php. Then, after you leave a short voice message and hit #, the automated voice should say, "Thank you for your message. Goodbye."

To confirm everything worked as expected, you should be able to see the MP3 file in the S3 bucket you specified. There should also be a transcription job running at Amazon Transcribe. All of that is accessible through the AWS Console.

Congrats! You've built your first Lambda!

Next Steps

There are many possible next steps, depending on your needs. One possible solution may be to create an AWS Cloudwatch event to be alerted when a Transcribe job is "Complete". The event could call another Lambda function to email the transcription, or add the transcription to a database. Bottom line is, you now have a text version of the voice message left by a caller. If you have any questions, or run into troubles, you can reach out to @VonageDev on Twitter or inquire in the Vonage Developer Community Slack team.

Adam CulpVonage Alumni

Adam is a developer and consultant who enjoys ultra-running, blogging/vlogging, and helping others tame technology to accomplish amazing things with an insatiable desire to mentor and help.

Ready to start building?

Experience seamless connectivity, real-time messaging, and crystal-clear voice and video calls-all at your fingertips.