In this post on Mux serverless webhook updates we see how you can use serverless functions in your Mux video workflow. Mux is a video service which takes care of encoding your video content and serving it in the best format for each user’s device. Mux is primarily designed for developers. As an example, to upload video, you use the REST API, either using something like curl, from the Terminal or you own custom app. Some tasks which Mux performs, like video encoding, for example, are not immediate. You might want to know once Mux have finished encoding your video so you can integrate content into your project immediately. Pinging the Mux endpoint until it reports the video is ready is not ideal. Instead Mux makes webhooks available.
With the webhooks, Mux will send a new request to your own URL as soon as they have an update. That request is just a REST POST with a JSON body. Your webhook URL will be one you manage, rather than one provided by Mux. If you are using the Terminal to upload videos or a static site, you can set up a serverless function to listen for the Mux webhook. In fact, that’s exactly what we will look at in this post. We will use Rust Cloudflare Workers to listen for Mux requests. Whenever the worker receives a request, it will invoke the Telegram API. A Telegram bot will then send the update to your own private chat.
Using Telegram lets you and your team get updates even while away from the desk (via the mobile app). To add polish, we see how to verify webhook events using your Mux signing key. All within the worker.
If that sounds like something you could find useful why don’t we crack on? To get going you will need a Cloudflare account as well as a Mux account. We will start with a quick look at what Cloudflare workers are then, we move on to Telegram bot configuration. Finally we code up the Rust.
Rust Cloudflare workers are a great way to handle webhook events. They will listen 24/7 and save
you having to maintain infrastructure. We will create the Cloudflare worker step by step. To build
the workers we will use the
wrangler CLI. If it is your first time
wrangler, just follow the few configuration steps in the
article on getting started with Rust Cloudflare workers. That article will also let you know how to set your system up for developing Rust.
To get going let’s spin up a new skeleton worker:
Next we will update the
Cargo.toml project file and add the crates
(Rust packages) we need for our worker.
We will use the
reqwest package to access the Telegram REST API.
hmac will help us verify the Mux webhook signature. Finally,
nom is a parser combinator. You use parser combinators, to parse strings.
They take a different approach to Regex, but solve similar problems. They are more composable and can
be much more efficient. Change the package data to suit your own needs. Lines
9 are optional though you may wish to update
and include them to follow best practices.
As a quick test, from within the project folder, in the Terminal, spin up the worker locally in dev mode:
It will take a moment or two to download crates and build the skeleton worker the first time we
run this. If all is well you will have a message saying the wasm package is ready and the worker
is listening on
Now we have a skeleton Worker up and running, let's get some Telegram credentials.
You will need to let Mux know the Cloudflare Worker endpoint. To authenticate messages, we will also need a signing key from the Mux dashboard. We’ll sort these out now. If you are not already logged in, log in now to the Mux Dashboard .
Next, from the menu at the bottom left, select Settings then Webhooks.
In the main window you will see all of your webhooks. By default the dashboard displays the Development environment webhooks. If this is your first webhook you’ll see a message saying “You haven’t created any webhooks yet”.
Click the Create new webhook button. In the window that pops up, keep Development
environment selected then enter the URL to notify. This will be
mux-serverless-webhook-updates.YOUR_SUBDOMAIN/mux-endpoint. To get your subdomain, use
Finally, once you return to the webhooks view, click the Show Signing Secret button and make a note of this. We will use it later.
The process for getting Telegram API credentials is quite simple, just follow step by step and you will have API keys in a couple of minutes.
- Bots are created by Telegram’s Bot Father — isn't that cute! Open up a new chat with @BotFather .
You interact with bots in Telegram by typing commands which begin with a
/in the chat window. Create a new bot using the command
/newbot. Bot Father will ask you for a name and then a username. The name can be anything but the username needs to end
botand should only contain alphanumeric characters and underscores. I will use “Astro Landing Page Form Site” as the name and
mux_webhook_botas the username. Bot Father will respond with the new API key for your bot make a note of this.
- Next we need to create a new group chat and add the bot to it (you can also add anyone whom you want to receive bot messages). From the Telegram menu select New Group. Enter a name for the group when prompted then in the Add Members window type the username of your bot.
We’re almost done. Next we need to get the ID for this new group chat so we can send
messages to it from the Netlify Serverless Function. From the group chat, send a message to
the bot by typing the following command as a message “
/my_id @my_bot” replace
my_botwith the name of your bot.
In the terminal use curl to see the bot’s updates. Remember to replace
123456789:AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqwith the API key you got earlier:
If you don’t have curl on your machine, just paste the link into your browser instead. If you are working on a shared machine, be sure to clear the link from the browser history as it contains an API key.
You will get a response back something like this:
Ok this is just some JSON. It contains two ids, although we just need one. The first is the
message ID. We don’t need this one. The second, within the chat object, starts with a
-”, this is the chat ID we need, including the “
We have all the API data we need to proceed. Let's carry on by setting up or function.
We split the code up, creating a Telegram Client module as well as a Mux webhook Event Module.
We will use these two modules when we update the code in the existing
src/lib.rs file. Let’s add code for that first module now. Create
src/telegram_client.rs and add the following content:
send_message function will use
reqwest to send a REST
POST request to the Telegram API with a JSON
body containing the body.
We are making good progress. Next up we will create the Mux webhook event module we mentioned
earlier. The Worker will be listening for updates from the Mux webhook on a route we will set
up in the next section. Once we receive a request on that endpoint, we verify the signature
and then parse the JSON body. Let’s add the module code then take a closer look at what
it does. Create a
src/mux_webhook_event.rs file and add the following
The structs in line
36 help us convert the JSON body of the
Mux webhook request to structures which we can manipulate in our Rust code. The
serde package has a
Deserialize trait which does a lot of the heavy
lifting for us. Some fields are JSON arrays, we can parse these into Rust
serde. As an example the
playack_ids field is an array (see line
23). The webhook sends an
initial status update to say an asset has been created, even though it is not yet ready. When
we receive this
created status update, some fields like video duration
will not yet be available. By making these fields Rust
Options, will tell
serde not to panic if one of them is missing. This
way we can use the same structs for
ready requests. We see this in action in line
We do not use all of the data which the webhook typically sends in our code. If you need additional data for your use case, just update the structs. Here is an example JSON body which you might find useful if you need to map additional data for your own project:
Example JSON Response — click to expand code.
We will use the
hmac_sha_256_verify function in lines
43 to verify the Webhook update. HMAC
(Hash-based Message Authentication Code) is a cryptographic algorithm for verifying messages. When
Mux creates the JSON body, the server generates a digest of the body, using the signing secret
for our webhook. It then includes this digest in the header it sends to our endpoint. When we receive
the body, we can also use the signing secret to generate a digest of the body. If our own calculated
digest matches the one placed in the header by the Mux server, we have some assurance the message
is genuine and has not been tampered with. This is because if an adversary tampered with the body
while it was in transit, the digest would not match the signature in the header. Also, to send
a spoofed message, the adversary would need to know the signing key.
So in a nutshell
hmac_sha_256_verify is just performing this data
integrity and authenticity verification function.
Paste in this missing code at the bottom of
72 you can see we call
hmac_sha_256_verify to verify our Mux event. When our endpoint receives a webhook event REST request, it will strip
the signature header then call
verify_event using that signature
and the raw JSON message body. The signature header will look something like:
The first part is a timestamp, while the
v1 part is the digest.
nom to parse this, separating out the timestamp and digest.
Then, we need to combine the timestamp with with JSON raw body and use that combined string for
our digest calculation. We form the string in line
the two components with a full stop (period). For more on Mux webhook verification, see Mux Verify webhook signatures docs
Cloudflare Workers have a mechanism for storing secrets, which saves us accidentally committing them in our repos. The secrets are uploaded to the Cloudflare dashboard from the Terminal. Once there, they are accessible in dev mode as well in the published worker.
Let’s add the two Telegram bot secrets now. First you will need to link you project to you Cloudflare account if you have not yet done that:
This will print a link to the console which you can paste into your browser. It takes you to the Cloudflare dashboard. Check permission and accept if you comfortable to do so.
Now we can upload the secrets we generated for our Telegram bot earlier:
wrangler prompts you, paste the token into the terminal. Then
repeat for the bot chat id:
Then, the MUX_WEBHOOK_SIGNING_SECRET:
Next we will wire everything up!
The final thing to do before testing is to connect everything. I have removed the boilerplate routes we don’t use here. Feel free to keep them for reference and debugging. First let’s add the modules we need to set everything up:
Much like we used
serde to parse JSON into Rust structs in the
Mux module, we will use it to convert our parsed data into a JSON report which we will use
serde to create a JSON report with our status update. Still using
serde, we will serialise the report into a pretty-formatted string which we will send to the
Telegram chat. The code in lines
22-26 helps define the structure
of the report.
serde will use this to generate our output.
Now replace the existing endpoints (in the same file) with this code:
44 you can see we are listening for a
POST request on
https://mux-serverless-webhook-updates.example.workers.dev/mux-endpoint. Following on, in line
45 you see how we can pull a secret from
the Cloudflare Worker environment. Lines
50 is where we parse the headers looking
Mux-Signature header needed for verification.
55 we parse the incoming Mux webhook event body from JSON
data variable. In line
61 we convert this to our report struct and then use
serde to pretty format that into stringified JSON for us. Finally in line
67, it is important to send the
200 OK response back to Mux. If
the Mux server does not receive this reply, it will keep trying to send the webhook update —
this could fill up your chat window quite quickly 😅 Let me know if anything there needs a little
more explanation. Next up we will run a test.
For a full production app you would want to run some unit tests using a package like
httptest to mock server responses. Here we will just send a
using curl, to the dev server and check we get a message in our Telegram chat. Paste this curl
command into your Terminal:
You will get a message pop up in your Telegram window if all is well.
verified will be returned as
false since the
Mux-Signature in this test request was not created using your own signing secret. We will test verification
in the next step though. The final step is to deploy the worker. You can do this using
As a final test, try uploading a short video to Mux to see if you get the updates in your Telegram chat. If you do not, get anything you can use the Mux dashboard API Activity view to help troubleshoot. Just click API Activity from the menu at the bottom left:
In the main window you will see logs which will confirm that Mux actually sent the webhook update out.
In this post we have seen how you can use Rust Cloudflare workers to improve your Mux workflow. In more detail, we have seen:
- a way to use Serde to process incoming JSON requests,
- how to verify authenticity and data integrity of webhook events using HMAC,
- how you can use a Telegram bot from your Rust Cloudflare Worker using Reqwest.
I hope you found this article useful and am keen to hear where you will go next as well as potential improvements, both to the Rust code and explanations above.
- We have seen a way to use Rust Cloudflare Workers to listen for Mux webhook events. These are the events you can configure Mux to send once your freshly uploaded video is ready to stream. We can listen for the POST REST request which Mux webhooks sends once the video is ready. Using our preshared signature (which Mux generates), we can also verify the data integrity of the webhook request.
- Pinging can be an inefficient approach, you can end up sending multiple pings while the video is nowhere near ready. Using webhooks you can be confident you will get the alert as soon as the video is ready. While waiting for the update you can just carry on with your life!
- Like many services, you can access Telegram bots using a REST API. This lets you send alerts and status update to your private group chat from your Worker. Reqwest is a great choice of package for interfacing with REST APIs. It is versatile and can send form encoded data, JSON bodies, handle query parameters and a whole lot more!
Have you found the post useful? Would you prefer to see posts on another topic instead? Get in touch with ideas for new posts. Also if you like my writing style, get in touch if I can write some posts for your company site on a consultancy basis. Read on to find ways to get in touch, further below. If you want to support posts similar to this one and can spare a few dollars, euros or pounds, please consider supporting me through Buy me a Coffee.
Finally, feel free to share the post on your social media accounts for all your followers who will find it useful. As well as leaving a comment below, you can get in touch via @askRodney on Twitter and also askRodney on Telegram . Also, see further ways to get in touch with Rodney Lab. I post regularly on Astro as well as SvelteKit. Also subscribe to the newsletter to keep up-to-date with our latest projects.