Webhook Client

Webhook Client

A webhook client consists of a HTTPS endpoint to receive the webhooks (and your relevant downstream processing), a client to obtain key sets (JWKS), a cache of the JWKS, and a scheduled job to poll for a new JWKS.

At a high level processing a webhook consists of (more details are provided in the following sections):

  1. Validating the signature in the X-JWS-Signature HTTP header
  2. Returning a 400 Invalid Request if the signature or ce-time is invalid
  3. Parsing the HTTP request with the Cloud Events SDK
  4. Processing the webhook
  5. Returning a 200 OK if processed successfully, otherwise returning an appropriate HTTP error code

Server Setup

Create an HTTPS endpoint which we will call to deliver webhooks. This endpoint can optionally be secured by basic auth, but must be HTTPS. Webhooks are cryptographically signed; the details to implement verification of this signature are given in the next section.

Received webhooks should be acknowledged with a 200 OK response; you should respond only once you are certain you have persisted or processed the webhook as once it is successfully acknowledged it cannot be resent. Responding with any other HTTP status code will cause the webhook to be enqueued for periodic retry. If at the end of the retry period for the webhook we still have not received a 200 OK acknowledgement the webhook will remain available for on-demand retry via the Events API

Idempotency

Webhooks are delivered at-least-once, therefore if you require once-and-only-once delivery you should use the ce-id header, which is unique per webhook, to implement and idempotent client and handle possible duplicates. A simple implementation of this would keep a set of ce-id's that you have successfully processed, check if this set contains the incoming ce-id and respond with 200 Ok without processing the message if the set does contain it.

🚧

It's important to compare ce-id only for events you have successfully processed, otherwise you will potentially discard retry attempts after failures!

Ordering

Webhooks are sent with best-effort ordering per topic. The topic is the portion prior to the '-' in the ce-type. There is no guarantee to the ordering across topics.

Versioning

Entity versioning can be determined using the ce-time header unless the specific entity provides a more precise version field defined in its schema. If a version field is provided, that should be used over ce-time

Replay Automation

You can follow along with actual code for this section in the Replay Event recipe.

List Events can be used in an ad hoc fashion to query about passed events, both failed and successful. However, this section covers how to build an automation to replay all failed events for a subscription. For this example, we will use a replay period of 24 hours.

  1. Call the List events endpoint with the following parameters:
    1. status.eq=FAILURE
    2. from=time.Now() - 24 hours //Adjust if replaying on a different schedule
    3. limit=50
    4. offset=0
  2. If response.pagination.total > 50
    1. Repeat Step 1 ceiling(response.pagination.total/50) times adjusting offset as needed, e.g. if the total is 102, then List events needs to be called a total of 3 times with a limit of 50
      1. Call 1: limit=50, offset=0
      2. Call 2: limit=50, offset=50
      3. Call 3: limit=50, offset=100
    2. Merge all results into a single array of events. It's important to maintain ordering as we return them in chronological order.

❗️

It's important to get the complete list of events before starting to request their replay as successfully replaying an event affects the pagination results.

For each event returned from List events, in chronological order (as returned from List events), call the Replay An Event endpoint. A successful retry is indicated by a 200 Ok response with a status of SUCCESS in the body. As event ordering is important, you should not move on to replaying a subsequent event until the prior one has been replayed successfully.

Ad Hoc Replay

These APIs can also be used outside of automation. List events can be used simply to get counts for your subscription. The additional filters (statuses other than FAILURE and the to time) can be used in this case. The status enum has the following meanings:

StatusDefinition
FAILUREWe were unable to send you the event and our automated retries have been exhausted. To get this event you must use the Replay API
PENDINGWe are in the process of sending this event to you but haven't successfully delivered it yet. This could be either because it has just arrived or because the initial delivery attempt failed and it is in the automated retry process
SUCCESSWe delivered the event and you responded with a 200 Ok