Webhooks are an easy way to get notifications on events happening asynchronously within Lob's architecture. Some common use cases for integrating webhooks are:
When an event occurs within our architecture and you have a webhook subscribed to that event type in that Environment (Test vs. Live), we will attempt to make a
POST request with the entire event object to the URL provided. See here for a full list of all available event types that you can subscribe to.
NOTE: In Live mode, you can only have as many non-deleted webhooks as allotted in your current Print & Mail Edition. There is no limit in Test mode.
To receive webhooks from Lob, you just need to create another endpoint on your web server that will accept a
POST request with a content type of
application/json. Keep in mind that it will need to be accessible by us so if there's anything that could prevent Lob from accessing it should be disabled for this endpoint. However, we do have recommendations on how to secure your endpoint.
To confirm delivery of the webhook, Lob expects a
2xx status code returned in a timely manner. We will consider any other status code (or lack of status code) to be erroneous and attempt to retry the delivery. If your webhook endpoint has any additional complex logic to perform, we recommend immediately returning a
2xx to let us know that you don't want to receive this event again, and then performing that logic afterwards. This should aid in preventing unwanted retry attempts caused by unexpected network timeouts.
Any other information sent back to Lob in the response will be captured and stored (regardless of status code) for you to view on your Dashboard, though we won't perform any processing on it. Therefore, we recommend responding with any information that you may find useful for debugging purposes. While you can return anything (including HTML), we've found it most helpful to return a concise JSON object with anything that could be relevant.
Events are created in both your Test and Live Environment, and Webhooks can also be created in both. Please note that Webhooks created in the Test Environment will be triggered off events from your Test API Key, while Webhooks created in the Live Environment will be triggered off events from your Live API Key.
Because tracking events only ever exist in Live, these event types can not be subscribed to in the Test Environment. To debug, you can "fake" the sending of these events to your server by using our Debugger.
When first starting out, we recommend using our Debugger. This tool allows you to trigger a generated event body to your specified URL on command. This should mainly be used to determine JSON structure when integrating. Since the event bodies sent are fake, all IDs and URLs within them are not accessible and do not map to real resources in your account.
Once you've started local development of the web server that will be handling these requests, we recommend using a tool that provides local tunneling, such as ngrok. This allows you to expose your locally running server to the Internet so we can access it without you needing to deploy your application.
When webhook attempts executed by Lob do not succeed (e.g. do not receive a
2xx status code, hit a SSL/TLS error, DNS issue, etc), we will continue to try to deliver the same event according to a schedule with an increasing back off. This policy is meant to give you time to rectify the issue without losing any events.
We will attempt the webhook at the following intervals until we either receive a
2xx status code or all 8 attempts have been executed:
|Attempt #||Time since last attempt||Time since first attempt||Example|
|2||1 min||1 min||
|3||5 min||6 min||
|4||30 min||36 min||
|5||1 hr||1 hr 36 min||
|6||6 hr||7 hr 36 min||
|7||12 hr||19 hr 36 min||
|8||24 hr||43 hr 36 min||
This means that if a webhook attempt continuously fails, Lob will stop attempting webhook requests 43 hr & 36 min (approximately 1.82 days) after the initial creation of the event.
It's important to note that for every API request you send to Lob, you may get multiple requests back to your server, depending on what event types you have subscribed to. For best results, please make sure your servers will be able to handle the load you expect to get back.
We understand that security is an important concern when granting external access. You need to make sure that Lob is able to access your endpoint, but you don't want anybody being able to access it or your data, so there are certain features that you can enable on your end to ensure this is possible.
We enforce HTTPS for all webhook URLs. Securing your endpoint with TLS ensures all data being sent to and from your server is encrypted. Make sure that you're using a fully-chained certificate, or else the request will never make it to your server and the attempt will fail. To make sure they are fully-chained, you should use the Debugger and see if the request successfully goes through.
Lob webhooks include a signature to allow you to verify their authenticity. Verifying this signature within your webhook endpoints allows you to ensure that the webhooks originate from Lob and not from a third party.
Lob-Signature is generated by computing HMAC-SHA256 on a signature input and a secret. The signature input is generated by concatenating
Lob-Signature-Timestamp (as a string), the
. character, and the webhook request's JSON payload (as a string). The secret is unique for each webhook and can be found in the details page for the respective webhook in the dashboard.
A static, fixed secret is used for webhooks in the Test Environment and for requests sent out using the webhook debugger. In these cases, the secret used in generating the signature is the string
The addition of the
Lob-Signature-Timestamp in the headers and as the input to HMAC-SHA256 allows you to prevent users from performing replay attacks. In a replay attack, an attacker intercepts webhooks and retransmits them. By verifying that the signature is valid and the timestamp is within some tolerance (we recommend 5 minutes), you can ensure that the request is not an older request being duplicated by an attacker.
In order to verify the
Lob-Signature-Timeout headers, follow the steps below.
Step 1: Prepare the signature input
Lob-Signature-Timestamp (as a string), the
. character, and the request body (as a string).
Step 2: Generate the expected signature
Compute the HMAC with SHA-256 using the webhook secret from the dashboard as the key and the signature input as the message. Convert to a string in base-16, hexidecimal format.
Step 3: Compare Signatures
Compare the expected signature with the
Lob-Signature header. If the strings are equal, then the webhook is valid.
Step 4: [Optional] Check the timestamp
If you are concerned about replay-attacks, check that
Lob-Signature-Timestamp is not older than your tolerance.
You can also use Basic Authentication to guard your endpoint from public access. This can be used in addition to or instead of webhook signature verification. For the best level of security, we highly recommend verifying webhook signatures, rather than relying solely on HTTP Basic Authentication.
When creating your webhook, insert the username and password to the URL using the following format:
https://username:email@example.com/webhooks. This will be converted on our end to the appropriate
Authorization header when we make the request.
A common feature that is enabled by default for some frameworks is cross-site request forgery. This is an valuable security measure to ensure that authenticated users aren't performing actions that aren't intended. However, having it enabled on your webhook endpoint could prevent our events from being processed. Instead of disabling it completely, you should just exempt this endpoint from CSRF validation.
We will always send events based on the API Version on your account at the time of event creation. If your account is set to an older API version but a request is sent with a hard coded header, the Event generated will still be based on the API Version on your account at that time. Event objects in the past will not be updated if you upgrade your API Version - only subsequent events will follow the new Version's structure.