maesn
Product insight

One event model, even without native webhooks

Some systems push events. Many push nothing at all. Maesn gives you one webhook to subscribe to, one payload shape to handle and one signature to verify, and does the polling itself wherever a system stays silent.

Two kinds of systemone event
System pushes eventsnative webhook
System stays silentno native webhook
maesn emits the event
The same event body
{
  "eventType": "CREATED",
  "resource": "INVOICE",
  "resourceId": "bca91f06…"
}
Trusted by winning software teams
HubSpotTipaltiPaywiseRallyQredNordhealthFindityFintoClockinProvetHeroHolviLanes & PlanesHubSpotTipaltiPaywiseRallyQredNordhealthFindityFintoClockinProvetHeroHolviLanes & Planes
The concept

What are unified webhooks

A webhook is the difference between asking and being told. Instead of calling an API on a schedule to see whether anything changed, you register a URL once and the system calls you when something does. For integrations that keep data in sync, that is the difference between minutes of staleness and a few seconds, and between constant traffic and traffic only when there is news.

The catch is that webhooks are the least standardized part of any API. Support is uneven, the payloads disagree, and the vocabulary for a created object differs from system to system. Unified webhooks collapse that into one subscription model and one event body, delivered through the same normalized data model as the rest of the Unified API. You write one handler, and it keeps working as your customers bring new systems.

The problem

Events are the least standardized part

Every system answers the same four questions differently, starting with whether it will tell you anything at all. Build against them directly and each integration needs its own listener.

Does it push at all
native eventsnothingpartial
What arrives
full payloada ping onlyan array
Event vocabulary
creatednewobject.add
How you verify it
signatureshared secretnothing
How Maesn handles it

Subscribe once, handle one event

One endpoint creates a subscription for one customer. From then on the events arrive at your callback URL in the same shape, whichever system they came from.

callbackUrl

Where events go

The endpoint on your side that receives every event for this subscription, as a POST request.

eventType

What to hear about

Subscribe to objects being created, updated or deleted, using one vocabulary on every system.

resource

Which objects

The resource you want to watch, an invoice or a customer for example, named the same everywhere.

One webhook type

A single unified webhook covers every system, so you write one handler instead of one per integration.

Synthetic webhooks

For systems that push nothing natively, Maesn polls on your behalf and emits the same event, so the gap never reaches your code.

Subscriptions per customer

Each subscription belongs to one customer, so their events arrive through their own subscription and stay separable.

Signed events

Every event carries an HMAC-SHA256 signature over the raw body, so you can prove it came from Maesn before you trust it.

subscribe.http
POST /webhooks
 
x-api-key: YOUR_API_KEY
x-account-key: CUSTOMER_ACCOUNT_KEY
 
{
"callbackUrl": "https://your-app.com/events",
"eventType": "CREATED",
"resource": "INVOICE"
}

Signed on every event

Every event carries an X-MAESN-SIGNATURE header. Recompute it over the raw request body with the secret you received when you created the webhook, and compare. Verify before you parse the JSON.

expected = hmacSha256(webhookSecret, rawBody)
isValid  = expected === headerSignature
Synthetic webhooks

Events from systems that push nothing

This is the part that does not exist without a unified layer. When a system has no native webhooks, or only covers a fraction of its objects, the usual answer is that you build a poller: a schedule, a cursor per customer and per resource, change detection, and a queue to smooth out the load. It works, and it becomes permanent infrastructure you own forever.

Maesn runs that poller instead, and turns the result into a normal event. You subscribe the same way you would to a native webhook, and you receive the same body with the same eventType, resource and resourceId. Nothing in your handler distinguishes the two, which is the point: whether a system pushes events stops being an input to your architecture. The polling that makes it work is paced by asynchronous processing, so it stays inside each system's limits without you scheduling around them.

A system with no events
1No native webhook to subscribe to
2So you poll on a schedule yourself
3Every tenant, every resource, forever
4And you still learn late
maesn polls it for you
A synthetic webhook

You subscribe once and receive events. The polling, the scheduling and the change detection stay on Maesn's side, and the event body is the one you already handle.

same eventType · resource · resourceId
Asynchronous responses

Told when the write actually finishes

Not every system answers a write immediately. Some accept the object, queue it and produce the outcome later, which normally leaves you polling for your own result.

Your app
Post the object
Where you would otherwise be polling
The system
Queues it, no result yet
maesn
Tracks the outcome
Your app
Event: success or failure

Maesn can close that loop with a webhook: when the system produces the outcome, you get an event telling you whether the write succeeded or failed. It exists because customers asked for it, which is the honest reason most of this layer exists. Every request, response and event along the way is recorded, so when something does go wrong you can see what was sent and what came back through logging and monitoring.

Why it matters

One listener, every system

Building it yourself
  • Learn each system's event model
  • Poll the systems that send nothing
  • Turn pings into real payloads
  • Verify each scheme differently
With Maesn
  • One event model to handle
  • Silent systems polled for you
  • Normalized payloads either way
  • One signature check everywhere

Webhook support is the thing most likely to be missing from the system a customer wants next, and the thing most likely to force a rewrite when it is. Because the event model is Maesn's rather than each vendor's, that question stops mattering during a sales call: you support the system, and how its data reaches you is an implementation detail on our side. The handler you wrote for the first integration is the handler for the last one.

Unified Webhooks FAQ

Common questions

Create a subscription with a POST to the /webhooks endpoint, passing a callbackUrl, the eventType you care about and the resource you want to watch. The request carries your API key and the account key of the customer the subscription belongs to. Deleting a subscription is a DELETE to /webhooks/{webhookId}.

Build once on the Unified API.

See how unified webhooks works for your integration, or dive into the technical reference.