Build a stock quote SMS bot with Twilio and TypeScript
Time to read: 6 minutes
We've seen how to send an SMS with TypeScript and how to receive and reply to SMS messages with TypeScript. Now let's create something we could use! If you're into investing, you can never have too many ways to check in on the stock market, so let's build an application you can send a stock symbol to and get back a stock quote.
In this post we will build a Node.js application with TypeScript, using Express, the Twilio Node package, and the Finnhub API to reply to incoming SMS messages with stock quotes.
What you will need
To build the application in this post you will need:
- A Twilio account (if you don't have one yet, sign up for a free Twilio account here and receive $10 credit when you upgrade)
- A Twilio phone number that can send and receive SMS messages
- Node.js installed
- ngrok so that you can respond to webhooks in your local development environment
- A Finnhub API key (you can register for a free Finnhub API key here)
With that prepared, let's get building.
A running start
In the blog post on receiving and responding to SMS messages in TypeScript we built a good base for this application which we will work from. If you haven't followed that post, you can get up to speed quickly. First, download or clone this repo of Twilio TypeScript examples and change into the receive-sms
directory:
Install the dependencies:
Compile the TypeScript:
Start the server:
You now have your application running locally on port 3000, to connect it to a Twilio number you will need to create a publicly available URL that can tunnel through to your local machine. I like to do this with ngrok. Open a second terminal and run ngrok with the command:
Once the tunnel has connected, ngrok will display a URL with a random subdomain that now points at your application. It should look like https://RANDOM_STRING.ngrok.io. Open your Twilio console and navigate to your incoming numbers, and choose the number you want to use for this app, orbuy a new one. Edit the number and add your ngrok URL, plus the /messages
path, as the webhook for when a message comes in.
If you have the Twilio CLI installed you can do this on the command line with the command:
With all that set up, send an SMS message to your Twilio number. You will get a response echoing back what you said.
This is all handled in the routes/messages.js
file; incoming messages are routed to the /messages
endpoint, the body of the message is extracted from the request body and a response is built up using messaging TwiML. The response is then returned as XML.
We did some other work to set the type of the incoming request and response. Check out the rest of the blog post to learn more about that.
Let's get on with turning our incoming SMS messages into stock quotes.
Making API requests in TypeScript
In this application we are going to turn our incoming message body into a request to the Finnhub API for a quote.
Loading config into your app
To use the API we will need to load the Finnhub API key into the application. We recommend doing this via environment variables so that you don't inadvertently commit API credentials to your project. In this application we will manage that with the dotenv
package.
Install dotenv
to your development dependencies:
Open package.json
and change the "start" script to:
This will require and run dotenv
when you start the application.
Find your Finnhub API key on the dashboard.
Create a file called .env
and add your Finnhub API key to it like so:
Open config.ts
and add a line that reads the Finnhub API key and exports it again:
With that done, we can move on to making requests to the API.
Making API requests in TypeScript
There are many ways to make HTTP requests in Node.js. We will use the got
package to make our requests to the Finnhub API. got
is fully written in TypeScript, so it provides us with types. Install got
to the project:
Create a new directory called src
and a file within that directory called quotes.ts
. This is where we will write a function to make requests to the Finnhub API. Start by importing got
and your Finnhub API key from config.
Now, let's define the function we'll use to make requests to the API. It will take the symbol we want to look up as a string and, since it will make an asynchronous HTTP request, return a Promise that resolves to an object of type Quote
.
There's a problem here though, we don't have a Quote
type. If we take a look at the Finnhub documentation we can see a sample response from the API:
The properties refer to the different prices the API returns; the current price, the day's high, the day's low, the opening price and the price at the previous close. The final property, t
, is a timestamp for the prices. Using this, we can define our Quote
type inside quotes.ts
:
Let's make the request to the API using got
. We make a GET
request to the API URL https://finnhub.io/api/v1/quote
and pass the symbol we are looking up as a URL parameter. We can pass the API key as a URL parameter or in the headers as the X-Finnhub-Token
header. With got
we can set the expectation up front that the response will be JSON and the package will parse the response for us, so we can then return the body of the response.
If you write out the code above, you will find that TypeScript is not happy about compiling. response.body
is of type unknown
. We know it is a JSON response that has been parsed into an object, but TypeScript doesn't know the shape of that object. In this case, we can assert, since we read the documentation, that it is of the type Quote
that we defined.
We assert that the body is of type Quote
using the syntax as Quote
, like so:
Now TypeScript is happy and we can use this function in the rest of our application.
Building an SMS response
Open routes/messages.ts
, we're now going to alter the response from echoing the body of the message to making a call to the Finnhub API and sending back data about the stock prices.
At the top of the file import the getQuote
function we just defined:
Remove the code from within the route definition and start building our new response. First we make the route handler an async
function. Then in the handler itself we get the body of the incoming message and uppercase it. This is the symbol we will look up with the API. We also create a new TwiML messaging response.
Next we want to make the request to the API. This could fail, so we wrap it in a try/catch block. When we get the response we send the data back however we like. I'm going to compare the current price to the previous close and show an emoji based on whether it is higher or lower. We set the message to send back by calling message
on the TwiML response
object.
If there is an error, we'll return an error to the sender instead. Finally, whether the API request was a success or not, we set the content type of the response to "application/xml" and send the TwiML response as a string.
Last thing to do is compile the code and start the server.
If you still have ngrok running from earlier, then you are good to go. If you need to start ngrok again you will likely need to update your number configuration in the Twilio console to use a new ngrok subdomain.
Send a text to your number with a stock symbol you want to look up. If all goes well, you will get a response with the current price.
If it doesn't work, check the application log and there should be an error message telling you what went wrong.
Now you can make API requests in TypeScript
In this post you have seen how to take an incoming SMS message, turn the body into an API request and format and return the results as a reply. We used the Finnhub API and stock quotes as the example here and you could do a lot more with this data. You could use more of the data returned from the quote API, or pick a different endpoint, like foreign exchange rates or even cryptocurrencies. You could also pick any other HTTP API, there are a few good examples of fun APIs in this blog post.
The code for this post, as well as the others in this series of posts about building Twilio apps with TypeScript, is available on GitHub.
Let me know what you are building with Twilio and keeping type-safe with TypeScript. Drop me a line at philnash@twilio.com or send me a tweet at @philnash.
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.