Thanks for summing up, concisely, why webhooks really aren't magic at all, in the fourth paragraph:
"All [webhooks] are is a promise by an application or API: “when this thing happens, I’ll send this HTTP request with this data.”"
It's nice to see that all the hype really just boils down to generalized pingbacks[1]. Now, having a standard is great -- I'm not entirely sure we have a standard yet, though. It's more like a fancy name for pingbacks that aren't just for blog posts.
I'm also not entirely sure if I'd prefer webhooks for eg. processing emails. Emails are naturally "push" -- they get pushed via SMTP. I know that people are scared of email/SMTP -- but it seems quite a lot easier to make sure you don't loose any "events" with SMTP than with HTTP(S).
What if your site is down for a few minutes, just as some service out there tries to "ping" you with a webhook? Email handles that.
I think what most people seem to mix up is that handling "real" email may be hard -- but looking for a well formed subject that exactly matches some regex, then parsing that, isn't that hard. Everything else you can either bounce (a little dangerous) or just drop (not quite as dangerous).
Mailing-lists work. What you need isn't much more complicated. Maybe allow for a mime-part with a json or xml, or some other well-formed body. Use gpg or smime to encrypt data, if you need something more than a short hash/token.
Part of the problem has traditionally been that email servers haven't been as easy to "hack" as web servers have. That was a failing on the part of the developers of those servers.
Thankfully now you have things like Qpsmtpd, James, Lamson and Haraka which can do those things for you. But not many people install those servers. I'd love to see that change (for obvious reasons).
The interesting thing about SMTP is that a mail transfer agent is typically built using queues for both outbound and inbound transmission. Those queues help ensure durability of a message. You could implement webhooks with a transmission queue, retrying for a bit, maybe giving up depending on the nature of webhook. The awesome part about SMTP is that there is so much existing infrastructure in place, although some agents aren't as reliable as others at delivery.
I'm new to webhooks - I understand them conceptually, but is there a standard for authenticating the incoming notification? Take the Stripe example - how do you know that the HTTP POST is actually coming from Stripe? Do you use a shared-secret, or some other mechanism to verify the HTTP request is authentic?
1) Receive a webhook and record the ID in your database. If it's a duplicate, stop.
2) Ask Stripe for the event matching the ID they gave you. If they reject it, stop.
3) Process the event.
It requires a roundtrip, but it's the only sane way to validate that the event you got is real and that you haven't seen it before without trying to validate a signature (lots of other APIs make you do that, though)
For Iron.io, all our requests are authenticated using an OAuth token. So only people that know your OAuth token (and thus could use our API anyways) can use your webhook endpoints.
But there are other ways, too. The most common I've seen is to provide an API endpoint to verify events with (Stripe does this). If you use HTTPS to receive the webhook, and verify it with a request over HTTPS to the API you expect it to be coming from, you're ensuring the request is authentic.
For some webhook styles, it doesn't actually matter. Some people use webhooks to just say "Something happened", without actually saying what. In this style, the API is still responsible for the data and authentication, the webhook just says "Hey, wake up, the API has something new for you."
There isn't a standard way of authenticating the incoming notification yet. I like how Mailgun is doing it, to verify the webhook is originating from Mailgun you need to:
* Concatenate timestamp and token values.
* Encode the resulting string with the HMAC algorithm (using your API Key as a key and SHA256 digest mode).
* Compare the resulting hexdigest to the signature.
* Optionally, you can check if the timestamp is not too far from the current time.
So, you essentially get 3 extra parameters from your webhook, `timestamp`, `token` and `signature`. Obviously, the API key is the shared secret here between your app and Mailgun.
MediaCrush updates itself through GitHub hooks [1]. When we get the POST, it git pulls and restarts the site automatically. Best thing we ever did. Not worrying about deployment makes our lives a lot easier.
This is pretty sweet, but it seems like it might be more useful for the baked-in reliability to be on the remote end.
That is, the side sending the POSTs should notice that it didn't get a 200 reply and retry some number of times with backoff. Also, the POSTs need to be idempotent (include a sequence number or nonce or something) so that if the "200 OK" gets lost and the sending side retries, you can discard the duplicates on the receiving side.
That's of course a lot harder since you have to convince everybody whose service you want to use that this is worth the time/effort :)
Stripe's webhooks are really nice. Everything that happens with your account, be it charges, disputes, transfers, or people changing subscription levels, all generate events that you can receive and do something with. In my book and the app that sells it[1] I use them to trigger emails to myself when important things happen. There's also an iPhone app named Paypad[2] that registers a webhook on your account that sends you push notifications when things happen.
Ok, maybe it's just the terminology that's confusing, but how do webhooks differ from callback requests? Is it that the semantics are standardized, or is there something that I'm missing? The Author is quite excited about them.
As far as I'm concerned, webhooks and callback requests are the same. If we were going to get pedantic, I suppose we could say that for a request to be a callback, it would have to be a response to an earlier request (think asynchronous processing) whereas a webhook is an evented request (it wasn't prompted by a previous request).
But being pedantic is lame. Let's just be excited about both!
Great post, Paddy. One thing I'd love to see in the HUD is a GitHub OAuth + repo webhook config. That is, you log in with GitHub credentials, you see a list of repos and can select which workers will get POSTed to after specific GitHub repo events[1].
Examples:
- The "adelevie/MyJekyllBlog" repo will POST to the worker "BuildAndDeploy" after event "push."
- The "adelevie/MyRailsApp" repo will POST to the worker "TestMyRailsApp" after events "push" and "pull_request."
I love this idea. I've been wanting to do something similar to this, making webhooks even easier to hook into the Iron.io platform. I don't know if it will make it into HUD, but I'm definitely going to be trying to setup some push-button webhook configurations for popular services that support configuring webhooks from an API.
Great an' all, but what happens when a request fails? There's no (specified) retry mechanism — and POSTs aren't meant to be idempotent. I guess many applications don't need strong reliability and so this is cool, but I can't help but feel HTTP's design is really being stretched with ideas like this. I totally get that it's really easy to get stuff going if everything just speaks HTTP, but is it really for the best?
I can't speak for other providers, but our practice is to let users set the number of retries they'd like and the space between retries.
We also are close to rolling out error queues, so when a push notification fails, the message is automatically placed into a queue, to be processed at the user's convenience.
I agree, the need for safe retries (as this is a process without user feedback) calls for idempotency, but that's at odds with the need for a webhook to be possible to be triggered multiple times.
One way around this is to use "tickle" webhooks--webhooks that tell the destination that data has changed, but require the destination to pull in that information themselves. Then the webhook call is still idempotent in practice (at worst, you're refreshing data more than you need to, which is still less than polling), but multiple webhook calls can be made.
> There's no (specified) retry mechanism — and POSTs aren't meant to be idempotent.
The semantics of the data exchanged by POST can be such that the request is effectively idempotent even though that's not an HTTP-level expectation (it's not wrong to have a layered-over-HTTP protocol in which methods are safer than HTTP requires, it would be wrong for them to be less safe than HTTP requires -- e.g., non-idempotent GET.)
If you are sending updated notifications over POST with the actual data then needing to be retrieved by a request the other directions, the first POST is effectively idempotent.
If you are sending the content in the POST without a key to prevent duplication, then there is a problem with retries.
> This is basically pub/sub messaging, but over the internet?
Its basically hubless pub/sub messaging over HTTP ("...over the internet", sure, but there is lots of much older versions of that); there's also the with-a-hub version, PubSubHubbub.
[+] [-] e12e|12 years ago|reply
"All [webhooks] are is a promise by an application or API: “when this thing happens, I’ll send this HTTP request with this data.”"
It's nice to see that all the hype really just boils down to generalized pingbacks[1]. Now, having a standard is great -- I'm not entirely sure we have a standard yet, though. It's more like a fancy name for pingbacks that aren't just for blog posts.
I'm also not entirely sure if I'd prefer webhooks for eg. processing emails. Emails are naturally "push" -- they get pushed via SMTP. I know that people are scared of email/SMTP -- but it seems quite a lot easier to make sure you don't loose any "events" with SMTP than with HTTP(S).
What if your site is down for a few minutes, just as some service out there tries to "ping" you with a webhook? Email handles that.
I think what most people seem to mix up is that handling "real" email may be hard -- but looking for a well formed subject that exactly matches some regex, then parsing that, isn't that hard. Everything else you can either bounce (a little dangerous) or just drop (not quite as dangerous).
Mailing-lists work. What you need isn't much more complicated. Maybe allow for a mime-part with a json or xml, or some other well-formed body. Use gpg or smime to encrypt data, if you need something more than a short hash/token.
[1] http://en.wikipedia.org/wiki/Pingback
[+] [-] baudehlo|12 years ago|reply
Thankfully now you have things like Qpsmtpd, James, Lamson and Haraka which can do those things for you. But not many people install those servers. I'd love to see that change (for obvious reasons).
[+] [-] daigoba66|12 years ago|reply
[+] [-] roarroar|12 years ago|reply
[+] [-] uptown|12 years ago|reply
[+] [-] zrail|12 years ago|reply
1) Receive a webhook and record the ID in your database. If it's a duplicate, stop.
2) Ask Stripe for the event matching the ID they gave you. If they reject it, stop.
3) Process the event.
It requires a roundtrip, but it's the only sane way to validate that the event you got is real and that you haven't seen it before without trying to validate a signature (lots of other APIs make you do that, though)
[+] [-] paddyforan|12 years ago|reply
For Iron.io, all our requests are authenticated using an OAuth token. So only people that know your OAuth token (and thus could use our API anyways) can use your webhook endpoints.
But there are other ways, too. The most common I've seen is to provide an API endpoint to verify events with (Stripe does this). If you use HTTPS to receive the webhook, and verify it with a request over HTTPS to the API you expect it to be coming from, you're ensuring the request is authentic.
For some webhook styles, it doesn't actually matter. Some people use webhooks to just say "Something happened", without actually saying what. In this style, the API is still responsible for the data and authentication, the webhook just says "Hey, wake up, the API has something new for you."
[+] [-] siong1987|12 years ago|reply
[+] [-] unknown|12 years ago|reply
[deleted]
[+] [-] Sir_Cmpwn|12 years ago|reply
[1] https://github.com/MediaCrush/MediaCrush/blob/master/mediacr...
[+] [-] richardlblair|12 years ago|reply
[+] [-] philsnow|12 years ago|reply
This is pretty sweet, but it seems like it might be more useful for the baked-in reliability to be on the remote end.
That is, the side sending the POSTs should notice that it didn't get a 200 reply and retry some number of times with backoff. Also, the POSTs need to be idempotent (include a sequence number or nonce or something) so that if the "200 OK" gets lost and the sending side retries, you can discard the duplicates on the receiving side.
That's of course a lot harder since you have to convince everybody whose service you want to use that this is worth the time/effort :)
[+] [-] paddyforan|12 years ago|reply
[+] [-] zrail|12 years ago|reply
[1]: https://www.petekeen.net/mastering-modern-payments
[2]: https://www.pay-pad.com
[+] [-] baudehlo|12 years ago|reply
http://baudehlo.wordpress.com/2013/09/06/stripe-webhooks-don...
[+] [-] huxley|12 years ago|reply
https://github.com/zapier/django-rest-hooks
[+] [-] duaneb|12 years ago|reply
[+] [-] paddyforan|12 years ago|reply
As far as I'm concerned, webhooks and callback requests are the same. If we were going to get pedantic, I suppose we could say that for a request to be a callback, it would have to be a response to an earlier request (think asynchronous processing) whereas a webhook is an evented request (it wasn't prompted by a previous request).
But being pedantic is lame. Let's just be excited about both!
Relevant: https://twitter.com/paddyforan/statuses/254375310554968064
[+] [-] adelevie|12 years ago|reply
Examples:
- The "adelevie/MyJekyllBlog" repo will POST to the worker "BuildAndDeploy" after event "push."
- The "adelevie/MyRailsApp" repo will POST to the worker "TestMyRailsApp" after events "push" and "pull_request."
[1] http://developer.github.com/v3/repos/hooks/
[+] [-] paddyforan|12 years ago|reply
[+] [-] samograd|12 years ago|reply
http://www.wired.com/wired/archive/5.03/ff_push.html [1997]
It seems I'm not the only one to remember the promises of this prophecy:
http://www.boston.com/business/technology/articles/2004/01/0...
[+] [-] dwb|12 years ago|reply
[+] [-] paddyforan|12 years ago|reply
We also are close to rolling out error queues, so when a push notification fails, the message is automatically placed into a queue, to be processed at the user's convenience.
I agree, the need for safe retries (as this is a process without user feedback) calls for idempotency, but that's at odds with the need for a webhook to be possible to be triggered multiple times.
One way around this is to use "tickle" webhooks--webhooks that tell the destination that data has changed, but require the destination to pull in that information themselves. Then the webhook call is still idempotent in practice (at worst, you're refreshing data more than you need to, which is still less than polling), but multiple webhook calls can be made.
[+] [-] dragonwriter|12 years ago|reply
The semantics of the data exchanged by POST can be such that the request is effectively idempotent even though that's not an HTTP-level expectation (it's not wrong to have a layered-over-HTTP protocol in which methods are safer than HTTP requires, it would be wrong for them to be less safe than HTTP requires -- e.g., non-idempotent GET.)
If you are sending updated notifications over POST with the actual data then needing to be retrieved by a request the other directions, the first POST is effectively idempotent.
If you are sending the content in the POST without a key to prevent duplication, then there is a problem with retries.
[+] [-] baudehlo|12 years ago|reply
[+] [-] mikeknoop|12 years ago|reply
[+] [-] adventured|12 years ago|reply
[+] [-] aytekin|12 years ago|reply
It is win-win for everyone. It is easier to implement and apps don't have to poll you constantly.
[+] [-] zrail|12 years ago|reply
[+] [-] mwetzler|12 years ago|reply
[+] [-] paddyforan|12 years ago|reply
[+] [-] jkarneges|12 years ago|reply
[+] [-] paddyforan|12 years ago|reply
[+] [-] tootie|12 years ago|reply
[+] [-] dragonwriter|12 years ago|reply
Its basically hubless pub/sub messaging over HTTP ("...over the internet", sure, but there is lots of much older versions of that); there's also the with-a-hub version, PubSubHubbub.
[+] [-] carimura|12 years ago|reply