Sending an SMS with the Nexmo API is as easy as initiating a request to the URL: https://rest.nexmo.com/sms/json. But have you ever wondered what happens behind the scenes? When you request things from the Internet, what does your computer do? What does the server do?
These are the questions we're aiming to answer below, so follow along if you'd like to see for yourself.
Before we start
Before we begin you’ll need a few things:
The cURL command-line tool to send and receive data.
Vonage API Account
To complete this tutorial, you will need a Vonage 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 Vonage API Dashboard.
Making the https request with cURL
Sending an https
request to the Nexmo SMS API is straightforward. Just replace the following variables in the example below, and the message should be on its way.
KEY | DESCRIPTION |
---|---|
NEXMO_KEY |
Your Nexmo API key, shown in your account overview. |
NEXMO_SECRET |
Your Nexmo API secret, shown in your account overview. |
TO_NUMBER |
The number you are sending the SMS to in E.164 format. For example 447401234567. |
SENDER_ID |
The number or text shown on a handset when it displays your message. You can set a custom Alphanumeric SENDER_ID to represent your brand better if this feature is supported in your country. |
You can invoke curl with command-line options to accompany the URL(s). These options pass on information to curl about how you want it to behave.
The Nexmo Documentation uses -d
to send strings of data in a POST request to a server, and we are adding -v
/--verbose
to switch on verbose mode.
The latter enables us to see the added information given to us from the curl internals, alongside all headers it sends and receives. Also adding --trace-time
so that cURL prefixes all verbose outputs with a high-resolution timer for when the line is printed.
Now, let's take a look at the output:
The Breakdown
If you're anything like me, and maybe have a "friend" who used to own the commandLineMyNemesis
GitHub handle for a while, you might need a second look at that output. Let's break it down into steps and see what each of them does.
DNS Lookup
The HTTPS protocol we used speaks TCP (Transmission Control Protocol). With TCP, cURL must first figure out the IP address of the requested host: Trying 173.193.199.22...
, then connect to it: Connected to rest.nexmo.com (173.193.199.22) port 443 (#0)
. By doing so, it performs a TCP protocol handshake.
The '(#0)
' part indicates which internal number cURL has given this connection.
TCP_NODELAY
is set
by default, which enables segment buffering so that data can be sent out as quickly as possible. It is typically used to increase network utilisation.
TLS Connection
HTTPS stands for "Secure HTTP", which means that the TCP transport layer is enhanced to offer authentication, encryption and data integrity, using TLS (Transport Layer Security).
The TLS connection begins with a "handshake", a negotiation between the client (cURL running on your PC) and the server that sorts out the details of how they’ll proceed. The handshake determines what cipher suite will be used, verifies the server, and ensures that a secure connection is established before starting the actual data transfer.
We are informed that Nexmo picked “TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256”
out of the cipher suites we offered. This means that the ECDHE
protocol was chosen, it will use the RSA
public key algorithm to verify certificate signatures and exchange keys, the AES
algorithm in GCM
to encrypt data, and the SHA256
to verify the contents of messages.
Server Certificates
Being certain that you are communicating with the correct host is just as important as having a secure connection. During the TLS handshake, cURL obtains the remote server certificate and verifies its signature by checking it against its own CA certificate store. This is done to ensure that we communicate with the right TLS server - so, the Nexmo server is indeed the Nexmo server.
POST Request
An HTTP request sent by a client starts with a request line: POST /sms/json HTTP/1.1
, followed by headers and then optionally a body, separated from the headers by an empty line.
The request headers carry information about the server we are talking to, our software version, the content types we can understand and about the request body content.
Response Headers
The request we sent is getting a corresponding HTTP response from the server. It contains a set of headers and a response body, separated by an empty line.
The first line shows a status code, in this case, 200 OK
, which lets us know that the request has succeeded.
The headers contain metadata from the Nexmo server, telling us it uses nginx as a web server platform, that it's sending back content in a JSON format, and that the content is chunked, so we shouldn't expect a Content-Length
header (like cURL sent in the request header).
The Connection: keep-alive
part lets us know that TCP's keepalive
feature is being used. cURL does this by default, so that "ping frames" are being sent back and forth when the connection would otherwise be totally idle. It helps idle connections to detect breakage even in lack of traffic and helps intermediate systems understand that the connection is still alive.
There are a few security related headers in there as well, X-Frame-Options: deny
doesn't allow a browser to render this URL in a <frame>, <iframe> or <object>. Nexmo uses this to avoid clickjacking attacks, by ensuring that their content is not embedded into other sites. X-XSS-Protection: 1; mode=block;
enables XSS filtering, so that the browser will prevent rendering of the page if an attack is detected.
The last line is empty, that is the marker used for the HTTP protocol to signal the end of the headers.
Response Body
The response body contains information about the text we've sent, starting with the number of messages: "message-count": "1"
, followed by a "messages":
array of objects with details regarding each individual message. The elements of this array are as follows: the number the message was sent to, the ID of the message, the status of the message, the remaining balance in the Nexmo account, the cost of the message and the ID of the recipient's network.
Connection #0 to host rest.nexmo.com left intact
lets us know that the connection is not being closed as a consequence of the transfer. Although, as soon as cURL returns to the command line, it will be closed.
Conclusion
Even though it took less than 2 seconds to send an SMS, there is a lot going on beyond what meets the eye at first. Hopefully, I managed to shed some light on the inner workings, and by now you have a better understanding of what really happens during an HTTPS request to the Nexmo SMS API. If you still have questions that remained unanswered, feel free to reach out to me on twitter.
What's next?
If you'd like to dive even deeper in the technologies mentioned, make sure to check out these resources about The First Few Milliseconds of an HTTPS Connection, HTTP Headers, HTTP Over TLS, The TLS Protocol, Everything cURL and the Nexmo SMS API.
Julia is a Developer Advocate for Vonage focusing on low-code technologies and integrations. Maker and breaker of things, explorer of yet another builder tool. Forever challenging the barriers to entry of tech, she is passionate about learning and teaching, creating resources for the community.