Skip to content
Akedly
Tutorials

Receive a webhook

Stop polling. Let Akedly tell your server when something happens.

Coming soon

Receive a webhook

Building the endpoint, verifying a signature, and watching a delivery land.


What you need

  • A URL your server answers on — a tunnel to localhost is fine while developing
  • A pipeline, either OTP or utility
  • Ten minutes

Steps

  1. Write the endpoint.

    Answer 200 first, then do your work:

    Express

    app.post('/webhooks/akedly', (req, res) => {
      res.sendStatus(200)   // acknowledge immediately
      handle(req.body)      // then process
    })
    

    Requests are abandoned after 10 seconds, so a handler that writes to a database and calls two services before answering is recorded as a failure even though your code worked.

  2. Point the pipeline at it.

    Paste the URL into the pipeline's Webhooks section and save. Leaving it empty disables outbound webhooks entirely.

  3. Test it before real traffic exists.

    The dashboard can fire a sample request and show your server's live response.

  4. Route and verify the request.

    The same backendCallbackURL can receive OTP verification-result callbacks (signed on V1.2, unsigned on V1) and signed OTP channel events. The OTP channel event guide explains the routing and headers. For every signed request, verify the raw bytes — if your framework parses the JSON and you re-encode it before checking, key order can shift and every signature fails. A V1 result has no Svix headers, so handle it in its own unsigned branch. Utility webhooks are also signed.


When it breaks

  • Every signature fails — you are almost certainly verifying a re-serialised object. Capture the raw body first.
  • Nothing arrives at all — check the callback type. For OTP channel events, see the OTP channel event delivery rules; the OTP verification-result callback is retried on the verification result schedule, so a missed one comes back within minutes.
  • You built one branch for every OTP callback — split verification results from channel events. A V1 result has no Svix headers, and a V1.2 result occasionally arrives without them; match an unsigned result's transactionID against your own record before acting on it.

Where to go next