Back to Integrations Guides

Introduction

Webhooks are sent over the network – and networks aren’t always reliable. Your endpoint might be briefly unavailable, a response might time out, or a retry might arrive after the original already succeeded. This guide covers what to do about all of that.


Reply quickly

Send back a success code (any 2xx) within a few seconds. If we get anything else – or no answer at all – we treat it as a failure and may retry a few times before giving up.

If your handler has real work to do, like calling a slow service of your own, don’t make us wait for it. Acknowledge the webhook right away with a 2xx, then finish the work in the background. Otherwise, a slow handler can time out and accidentally trigger duplicate retries.


Handling duplicates

Every message includes an X-Webhook-Delivery-Id header – a unique ID for that delivery:

X-Webhook-Delivery-Id: 3459a611-318a-46ce-aedc-c3eaa30c32d9

Here’s the useful part: that ID stays the same across retries. If we resend a message because the first attempt didn’t get through, every retry carries the very same ID. So if you keep a record of the IDs you’ve already handled and simply ignore repeats, you’ll never process the same delivery twice.

A minimal version of that looks like:

1. On receipt: read X-Webhook-Delivery-Id.
2. INSERT delivery_id INTO processed_deliveries ON DUPLICATE KEY DO NOTHING.
   If the row already existed, return 200 OK and stop.
3. Otherwise, process the payload, then commit.

The ID is handy in one more way: if you ever contact our support team about a particular delivery, quoting it lets us find that exact message in our logs.


Replaying past events

Sometimes you’ll want your endpoint to receive data that already happened – not just new events. The “Sync all existing data” button on the integration screen does exactly that, backfilling your endpoint with historical issues, instances, and completed scans. It’s useful when:

  • You’re setting up a brand-new endpoint and want it pre-loaded with what’s already there before it goes live.
  • You rebuilt or replaced your endpoint and need to catch up on anything it missed while it was down.

Replayed messages look almost exactly like normal ones, with two giveaways so you can tell them apart:

  1. The request carries an extra header: X-Webhook-Replay: true.
  2. The envelope includes a top-level flag: "is_replay": true.

Either signal on its own is enough. On a normal real-time message, neither is sent – they’re simply absent rather than set to false. How you respond is up to you, and there are a few common approaches:

  • Already de-duplicating? You’re done. If you’re keeping track of delivery IDs, replays look after themselves – the content (issue ID, instance ID, and so on) is the same, so your end state lands in the right place either way. This is the easiest path.
  • Skip them for live-only notifications. If your endpoint just pushes real-time alerts (say, a Slack ping), reply 200 OK right away when you see X-Webhook-Replay: true, so a backfill doesn’t flood people with old news.
  • Route them differently. Send replays to a separate background job – for example, a slower bulk-import worker – and keep real-time events on their usual path.


Still stuck?

File a support ticket with our five-star support team to get more help.

File a ticket

  • This field is for validation purposes and should be left unchanged.
  • Please provide any information that will be helpful in helping you get your issue fixed. What have you tried already? What results did you expect? What did you get instead?

Related Guides