cURL, HTTPS and the Nexmo SMS API – Behind the Scenes

Published November 06, 2018 by Julia Biro

Sending an SMS with the Nexmo API is as easy as initiating a request to the URL: 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:

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.

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, then connect to it: Connected to ( 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 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.


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.

Leave a Reply

Your email address will not be published.