Skip to content

Consume Webhooks

Listen to webhook notifications to react to events happening in your workspace

Worklayer uses webhooks to notify your application of events happening in your workspace. You can react to events such as a Job being picked up by a Tax Pro, a document being added to a job, new messages being sent, or the job being completed. Check the Event Resources page for a full list of available events and payloads.

Worklayer uses HTTPS to deliver webhook notifications to your app as a JSON Payload. You can use these notifications in your backend to execute any actions you may deem appropriate.

Steps to receive webhooks

  1. Create a webhook endpoint as an HTTP endpoint on your server.
  2. Handle requests from Worklayer by parsing each event and returning 2xx response status codes.
  3. Secure your webhook by verifying signatures.
Note

At this time, webhook creation is done on demand on a per-request basis.

The only requirement for a webhook to be created for you is the HTTPS endpoint URL where you want to receive notifications.

Step 1: Create an endpoint to receive notifications

Set up an HTTPS endpoint on your server that can accept unauthenticated webhook requests with a POST method in JSON format. Worklayer sends each request with a Content-Type of application/json and a User-Agent of worklayer/1.0. For example, this route in a Node express.js app maps a webhook endpoint:

JavaScript
Copied
1const express = require('express');
2const bodyParser = require('body-parser');
3const app = express();
4
5app.post('/taxfyle_webhooks', bodyParser.json(), (request, response) => {
6 const event = request.body;
7});

Here, the /taxfyle_webhooks route is configured to accept POST requests and expect data in a JSON payload.

Step 2: Handle requests from Worklayer

Your endpoint should be configured to read event resources for the type of event notifications you want to handle.

Review Event Structure

Webhook events have an object structure with the common top-level fields of id, create_time, event_type, version, and data. Your endpoint should check the event type and parse the payload of each event you care about.

json
Copied
1{
2 "id": "21e42d52-4145-465e-94bd-322c13bbe5fa",
3 "create_time": "2022-08-23T13:54:27.612477Z",
4 "event_type": "job.status",
5 "version": "1.0",
6 "data": {
7 "job": {} // The Job Resource
8 }
9}

Check the Event Resources page for all the available event types and their structure.

Return a 2xx response

Your endpoint should quickly return a successful status code (2xx) prior to any heavy computation that can cause a timeout. Worklayer treats any 2xx status code as a successful delivery and ignores the response body. See Delivery and retries below for what happens when your endpoint does not return 2xx.

Step 3: Secure your webhook by verifying signatures

During webhook setup, you'll receive a secret that can be used to verify incoming webhook requests in your endpoint. Worklayer generates a signature for each payload and includes information in the request headers that you can use to verify that the payloads were generated by Worklayer and not by another server acting as Worklayer.

Reference the Check Signatures page for complete details.

Delivery and retries

Worklayer sends each event to your endpoint with one POST request. If that request fails, Worklayer retries it according to the policy below. Each event is delivered independently, so one failing event does not block the delivery of other events.

When Worklayer retries a delivery

Worklayer retries a delivery only when your endpoint responds with one of the following status codes:

  • Any 5xx status code.
  • 408 Request Timeout.
  • 429 Too Many Requests.

Worklayer does not retry in these cases:

  • Your endpoint responds with any other 4xx status code, such as 400, 401, 403, or 404. Worklayer treats these as permanent failures.
  • Worklayer cannot connect to your endpoint, for example, because of a DNS or TLS error.
  • Your endpoint does not respond within 100 seconds.

The retry schedule

Retries use exponential backoff with jitter. The delay before each retry roughly doubles, and each delay is randomized so that retries from many events do not hit your endpoint at the same time.

AttemptTypical delay before the attemptMaximum delay
1 (initial)nonenone
2 (retry 1)about 0.5 seconds0.7 seconds
3 (retry 2)about 0.6 seconds1.4 seconds
4 (retry 3)about 1 second2.2 seconds
5 (retry 4)about 2 seconds4.3 seconds
6 (retry 5)about 4 seconds8.6 seconds

In total, Worklayer makes at most 6 attempts per event (the initial attempt plus 5 retries). All attempts happen within a window of roughly 6 to 12 seconds after the first attempt, not counting the time your endpoint takes to respond. If the last attempt also fails, Worklayer logs the failure and discards the event.

No replay

Worklayer does not store events for replay, and there is no API to request that an event be sent again. If your endpoint is unavailable for longer than the retry window, the events sent during that time are lost.

Tip

Because the retry window is short, keep your endpoint as thin as possible. A reliable pattern is:

  1. Verify the request signature.
  2. Write the raw event to a durable queue, such as Amazon SQS, Google Cloud Pub/Sub, RabbitMQ, or Kafka.
  3. Return 2xx immediately.
  4. Process events from the queue in a separate worker, where you can retry your own logic as often as you need.

This way, a bug or an outage in your processing code does not cause you to miss events.

Duplicate deliveries

A retry can deliver an event that your endpoint already processed. For example, if your endpoint processes the event and then fails before it returns 2xx, Worklayer retries and your endpoint receives the same event again. Use the id field of the event to detect and skip duplicates.

Full Example

The following is a full example of reacting to a job.status event in Node.

JavaScript
Copied
1const express = require('express');
2const bodyParser = require('body-parser');
3const app = express();
4
5app.post('/taxfyle_webhooks', bodyParser.json(), (request, response) => {
6 const event = request.body;
7
8 switch (event.event_type) {
9 case 'job.status':
10 const eventData = event.data;
11 // handleJobStatusChanged(eventData);
12 break;
13 default:
14 console.log(`Unhandled event type ${event.event_type}`);
15 }
16
17 // Return a response to acknowledge receipt
18 response.json({ok: true})
19});
20
21app.listen(8000, () => console.log('Running on port 8000'));
Last updated on October 2, 2026