Top
Best
New

Posted by weli 5 hours ago

The Valley of Webhooks(weli.dev)
99 points | 40 comments
toomim 1 hour ago|
This is a nice writeup of the problems in using Webhooks for State Synchronization. I also noticed that the proposed solution is a pseudo IETF-style draft protocol called SCROLL... that happens to be remarkably similar to an actual IETF draft I am bringing to IETF 127 this November called "Braid-HTTP Subscriptions."

Both drafts request a subscription with a GET plus a header:

    Scroll Request:
      GET /scroll/feed/customers
      Prefer: stream
    
    Braid Request:
      GET /customers
      Subscribe:
In both systems, the GET leaves its response open to stream events. SCROLL responds with application/x-ndjson. Braid subscriptions are a 209 Multiresponse, with content-type application/http-history. This lets them support more than just JSON. You can send updates to the state of CSV, or PNGs, XML, HTML, plain text, or any media type.

The author noted that it's hard to get adoption. Well, the reason that Webhooks are so common is that they are bog-standard HTTP. For this to get adopted, we need to put it into bog-standard HTTP. So we need to go to the IETF, and and extend HTTP in a general way to support state synchronization. It should just work for any existing HTTP media type (not just JSON), and any resource/URL (not just special /scroll/* URLs), and any way of marking timestamps (not just the ordered strings proposed in SCROLL).

Then we can bake this stuff into HTTP, and thus into all our bog-standard libraries, utilities, and code, and you won't have to reimplement the same sync-logic-over-webhooks again, and again, and again.

Reach out if you're interested!

bobbiechen 51 minutes ago||
Is it accurate to say this is something like long polling except you continue to hold the connection open for subsequent updates? Does this mean a server potentially needs to hold open a very large number of connections (one per client) even if there are no updates?

And why formalize on HTTP rather than on a similar protocol over websockets?

weli 1 hour ago||
I reached out through email :)

Just one correction. My spec doesn't force /scroll/ URL's, just proposes it as a convention.

alt227 3 hours ago||
I had the exact same thing with the Quickbooks api recently. You cannot trust the responses or webhooks at all.

On create a user or invoice for example sometimes it will return an error, yet it actually created the entity. This means you have to check manually after creating everything to know if its created properly.

Then you have the issue that sometimes quickbooks takes a while to update, and locks the company file while it does some background magic. This means you cannot immediately do the existence check, and also sometimes the check errors or times out which essentially means you need to keep checking forever until you can properly reconcile your db against theirs. But with hundreds/thousands of transactions per minute this state is never reached. You perpetually live in a state of trying to catch up but never managing it.

When I brought it up with Quickbooks dev support their response was literally "Its your job to make sure things are created properly in our system".

How did we get to this place where we started putting up with systems that cannot ever be trusted?

hyperhello 2 hours ago|
That is the way enterprise software works as a system. It demands to be the central focus of everything. Workers want to route around these turbo productivity theater nonsense that could be replaced by a few K script that gates access to a text file and checks validity of appends. That can’t be allowed, so you need what is essentially whole poorly documented OSs to enable an economy of brokers to it, or the whole con would collapse.
foresterre 4 minutes ago||
I had this almost exact discussion today. Adyen (the payment provider) provides merchants with webhooks so they can update a local modal of payment and payment modification data (checkout).

But there is no way (for a merchant) to get the latest 'true' state as held by Adyen. So you better hope your data is exactly in sync with the notifications you got from the webhook (which it never exactly is, because there are so so many points of failures, and unlike what this author says, the docs aren't thát well presented to hold the same model as the PSP does. It is often close enough though, but you are constantly gardening your implementation, because the model also changes on their end with little information in the changelogs).

The "latest state" data exists though! If you open the customer portal it is presented to you without problem.

shreygupta 49 minutes ago||
Gerard mentions it super quickly, but another massive issue with webhooks generally is local development. Yes, you can use a tunnel, but that requires all engineers on a team to add their own tunnel urls. This causes even more issues when you use the platform as a source of truth, like for auth or payments. With WorkOS specifically, your whole team develops with one shared development sandbox. You run into issues when your local dev auth (in postgres) is not synced with the shared dev sandbox that WorkOS has since not all team members have their dev environments running at once. So yeah, then you use events API. But WorkOS only preserves the events API data for 90 days (and u have make 3 calls since its a max of 30 days per call). So then you load all the data with the state API first, then you start running the events API. It's a mess.

Tried to talk about this on X until the CEO of WorkOS wanted to bring it in private, then proceeded not to help at all. https://x.com/grinich/status/1913035839866835297?s=20

tasn 3 hours ago||
Webhooks are simple and ubiquitous, and that's both a weakness and a strength. It's also why they are used for a lot of things, even things they are not great for (state sync).

These weaknesses are why we[1] added FIFO endpoints, Polling Endpoints, and what we call "Svix Stream" as ways to do ordered state synchronization (each with its own tradeoffs). This lets people consume the events in the way that best fits their use-case. We are working on more things to make the state sync even easier. I'd love to hear about more challenges people are facing with webhooks, as we want to make these things better.

OP: I'd love to hear more about your thoughts there, and will send you an email in a moment.

P.S, if you're unfamiliar, please check out Standard Webhooks[2]. It's a spec we created to help with signature verification that has been adopted by OpenAI, Anthropic, Google, and many others. We are chipping at one webhook challenge at a time. :)

1: I'm the founder of Svix (mentioned in the post), we do webhooks infrastructure as a service.

2: https://www.standardwebhooks.com/

zffr 4 hours ago||
With webhooks, consumers get to asynchronously respond to updates from a provider. If no data has changed, a provider will not send any updates.

With SCROLL, consumers are responsible for choosing when to ask a provider for updates. Without a mechanism for knowing when data has changed, consumers will be forced to be pessimistic and poll providers for new data on some cadence.

I see two issues with the proposal: (1) SCROLL will lead to an increase in unnecessary network traffic for both the consumer and provider, and (2) because a consumer cannot know when data has changed, the lag between a consumer's local model and the provider's data model will be larger when with Webhooks.

lxgr 4 hours ago||
Assuming you're not using the proposed streaming option, I suppose you could always send a webhook for that fact alone? In other words, an empty notification, with semantics of "something has probably changed, better poll the SCROLL if you aren't already".
Multicomp 2 hours ago||
Doesn't doing that just reinvent eTags on hypertext resources from the RESTful wars and XML Web Services days 20 years ago?

1. Long Poll the cursor to pull down the latest events

2. Trigger a long-poll even if in exponential backoff because they shot you a webhook saying 'eTag changed!'

inigyou 4 hours ago||
If your API is just wrapping Kafka, it can long-poll
zrail 4 hours ago||
Webhooks are a painful problem. To clarify, Stripe's events API definitely ships a cursor and polling it has been the method preferred by large consumers for a long time.
weli 2 hours ago|
Stripe events API is one of the examples of how to do things properly. And SCROLL is just trying to create a common spec so that everyone offers a stripe-like event polling api.
thingification 1 hour ago||
I wonder if this is a CS problem somebody solved in 1954. Does somebody have the link to that paper?

(I'm not serious about 1954 in particular, I am about hoping somebody here knows the CS literature better than me)

Terr_ 4 hours ago||
The end here reminds me of "The Log: Real-time data's unifying abstraction" [0], which has unfortunately had a bit of link-rot since 2013.

One complication in this approach involves access-windows: What if my system is only supposed to be seeing stuff that happened during two separate weeks in the year, because those are the spans when it was subscribed or authorized?

So the data-host would need to maintain a concept of "connection history" for other services, and also use that to filter/modify its real event stream, inserting artificial "initial state" roll-ups of events that happened in dark periods.

[0] https://news.ycombinator.com/item?id=6916557

WorldMaker 1 hour ago|
The proposed feed solution looks a lot like the CouchDB replication protocol, as another object in a convergent evolution space to consider.
More comments...