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
- Create a webhook endpoint as an HTTP endpoint on your server.
- Handle requests from Worklayer by parsing each event and returning
2xxresponse status codes. - Secure your webhook by verifying signatures.
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:
JavaScriptCopied1const express = require('express');2const bodyParser = require('body-parser');3const app = express();45app.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.
jsonCopied1{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 Resource8 }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
5xxstatus code. 408 Request Timeout.429 Too Many Requests.
Worklayer does not retry in these cases:
- Your endpoint responds with any other
4xxstatus code, such as400,401,403, or404. 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.
| Attempt | Typical delay before the attempt | Maximum delay |
|---|---|---|
| 1 (initial) | none | none |
| 2 (retry 1) | about 0.5 seconds | 0.7 seconds |
| 3 (retry 2) | about 0.6 seconds | 1.4 seconds |
| 4 (retry 3) | about 1 second | 2.2 seconds |
| 5 (retry 4) | about 2 seconds | 4.3 seconds |
| 6 (retry 5) | about 4 seconds | 8.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.
Because the retry window is short, keep your endpoint as thin as possible. A reliable pattern is:
- Verify the request signature.
- Write the raw event to a durable queue, such as Amazon SQS, Google Cloud Pub/Sub, RabbitMQ, or Kafka.
- Return
2xximmediately. - 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.
JavaScriptCopied1const express = require('express');2const bodyParser = require('body-parser');3const app = express();45app.post('/taxfyle_webhooks', bodyParser.json(), (request, response) => {6 const event = request.body;78 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 }1617 // Return a response to acknowledge receipt18 response.json({ok: true})19});2021app.listen(8000, () => console.log('Running on port 8000'));