Getting started with webhooks

This guide will help you get started with receiving webhooks from the Oyster platform.

Webhooks are a way of receiving information from the Oyster platform by getting it "pushed" to you, as opposed to continually making requests ("polling") to the Oyster platform API for updates. For example, one way to use webhooks would be to receive a notification every time an expense is created or approved.

Requirements

To get started with webhooks, you'll need the following:

  • A Developer Application. We have guides to set one up for Partners or Customers, but you can also use one you've already created on Oyster.
  • An Access Token authorized for the same company (account) that owns the Developer Application (see below).
  • A public-facing endpoint (URL) for us to POST webhooks to.

1. Create an Access Token

To register an endpoint to receive webhooks, you will need to make an API request to Oyster. That API request needs to be made with an Access Token authorized for the same company (account) that the Developer Application belongs to. You can find instructions to do this in the Customer guide to creating and authorizing a Developer Application or Partner guide to creating a Developer Application.

2. Set up a webhook endpoint

You'll need to set up a webhook endpoint to receive webhooks to.

To do this, make the following API request, replacing the Bearer token with your access token (from step 1) and replacing the url and sharedSecret with appropriate values:

curl --request POST \
     --url https://api.oysterhr.com/v0.1/webhooks \
     --header 'accept: application/json' \
     --header 'authorization: Bearer <TOKEN GOES HERE>' \
     --header 'content-type: application/json' \
     --data '
{
  "url": "<YOUR WEBHOOK ENDPOINT GOES HERE>",
  "sharedSecret": "<YOUR SHARED SECRET GOES HERE>"
}
'
  • url: This is the endpoint you would like us to POST webhooks to.
  • sharedSecret: We will include the secret you provide here as an Authorization header (bearer token) in all webhooks we send to you, to prove they've come from the Oyster platform.

This API request will then return the ID of your new webhook endpoint. Make a note of the ID as you'll need it to update or delete the endpoint in the future.

3. Receive a webhook and validate it

Once a webhook endpoint has been registered, the Oyster platform will begin to dispatch webhooks to it as the system responds to events. You'll want to validate that the webhook came from Oyster and you can do this by grabbing the Authorization header from the request and comparing the value to the shared secret that you entered when originally registering the webhook endpoint.

For example, if you use a shared secret of 12345 the Authorization header would be Bearer 12345.

If the two match, the webhook came from Oyster and you can be confident about processing it. In the example above, the two match and the webhook should be processed accordingly.

Responding to webhooks

You must respond to the webhook with a 200 status code within the timeout of 5s.

If we do not receive a 200 response within the timeout, we will consider the webhook dispatch to have failed and we will try again later.

If delivery fails, Oyster will automatically retry webhook delivery up to 9 total attempts over approximately 48 hours, using an increasing backoff schedule of 30 seconds, 5 minutes, 30 minutes, 1 hour, 3 hours, 6 hours, 12 hours, and 1 day (with a small random jitter added to spread out retries). Because webhooks may be delivered more than once, your endpoint should be idempotent.

4. Processing a webhook

Oyster's webhooks follow a defined pattern, set out below:

{
  "eventName": "some_event_name",
  "eventTimestamp": "2026-04-21T09:35:13Z"
  "id": "wh_01J19XRFZ2Q4QBDC6CA461AGT7",
  "companyId": "ABC1234",
  "data" {
    <data relating to the event>
  }
}
  • eventName: This is the name of the event generated by the system and will usually be in the format [namespace].event_name. For example, when an expense is approved on Oyster, the event name would be expenses.expense_approved. This will allow you to filter for only the events you care about.
  • eventTimestamp: The time the event occurred on Oyster, formatted as an ISO-8601 timestamp (UTC). You can use this for ordering events and for debugging delayed deliveries.
  • id: The globally unique ID for this webhook notification. If you have multiple developer applications receiving webhooks for the same logical 'event' (i.e. an expense being approved) then they will each receive a different notification with a different ID. The id will always be prefixed with wh_.
  • companyId: The ID of the company for whom the event occurred. For customers, this will be your company ID; for partners, you can use this ID to match against the relevant customer in your system.
  • data: A JSON object containing data specific to the event. For example, with an expense.expense_approved event, this would contain the ID of the expense that was approved.


Did this page help you?