Webhooks

Getting push notifications to your application
The ATS supports a form of webhooks to provide notifications of events to interested subscribers. Client applications can create topics to specify the events of interest and create subscriptions to specify the endpoint to send the notifications to.

Using Webhooks

Firstly create a topic to define the type and scope of the events of interest.

POST https://example.tal.net/api/v1/notification_topics
{
  "type": "POSTING_UPDATE",
  "name": "Main job board postings update",
  "description": "Updates to postings on main internal job board",
  "expression": "posting.posting_loc_meth.post_loc_vac.job_board.id == 123"
}

The name and description should be whatever is meaningful for your application, type should be one of the types of notification that we support, expression is a ‘datapath’ expression for limiting the set of events that are of interest.

The topic can now be subscribed to.

POST https://example.tal.net/api/v1/notification_topics/123/subscriptions
{
"start_dt": "2021-04-12T09:22:30.579Z",
"end_dt": "2022-04-12T09:22:30.579Z",
"destination_url": "https://myapp.example.com/webhooks"
}

The start_dt and end_dt cover the intended duration of the subscription and destination_url is where notifications will be posted.

When the subscription starts notifications will be posted to the endpoint in a standard format:

{
  "message_id": "51dd550c-6dda-4dd2-81f4-3309bb04d094",
  "timestamp": "2021-01-15T16:50:12Z",
  "details": {
    "id": 2,
    "url": "https://example.tal.net/vx/api/v1/postings/2",
    "job_board": {
      "id": 2,
      "url": "https://example.tal.net/vx/api/v1/job_boards/2"
    },
    "vacancy": {
      "id": 3,
      "url": "https://example.tal.net/vx/api/v1/vacancies/3"
    }
  },
  "user": {
   "id": "36",
   "url": "https://example.tal.net/vx/api/v1/recruiters/36"
  },
  "subscription": {
    "id": 10,
    "url": "https://example.tal.net/vx/api/v1/notification_topics/4/subscriptions/10",
    "uuid": "c34db4e8-ffc0-40dc-9150-cce795cbf3c2",
    "topic": {
      "url": "https://example.tal.net/vx/api/v1/notification_topics/4",
      "uuid": "218fc25b-9dd8-4793-be92-14a5d391da31",
      "id": 4
    }
  }
}

Notification payloads contain 3 main elements:

  • user has attributes about the user who initiated the event that caused the notification to be fired
  • subscription has attributes about the subscription and topic
  • details has specific details about the event, this varies according to the type (see below)

Types

The set of supported types of notification is being continually expanded as the tooling is added to the ATS. The types of event for the notification available, such as an application has changed status [STATE_CHANGE_APPLICATION] or a vacancy has been posted [POSTING_CREATE], are shown in the current set.

Job board postings

| Type              | Description |
|-------------------|-------------|
| POSTING_CREATE    | A posting has been created, a job has been posted |
| POSTING_UPDATE    | Properties of the posting have been updated, e.g. closing date |
| POSTING_DELETE    | A posting has been deleted |
The details object in these payloads has URLs for the vacancy that was posted and the job board it was posted to:
  "details": {
    "id": 2,
    "url": "https://example.tal.net/vx/api/v1/postings/2",
    "job_board": {
      "id": 2,
      "url": "https://example.tal.net/vx/api/v1/job_boards/2"
    },
    "vacancy": {
      "id": 3,
      "url": "https://example.tal.net/vx/api/v1/vacancies/3"
    }
  }

Status updates

| Type           | Description |
|----------------|-------------|
| STATE_CHANGE_APPLICATION | An application has changed status |
| STATE_CHANGE_OPPORTUNITY | An opportunity, e.g. a vacancy or an event, has changed status |
The details object in these payloads has URLs for the subject that has changed state and its history entries
  "details":
    "id": 222,
    "url": 'http://example.tal.net/vx/api/v1/applications/222'
    "state_changes":
      "url": 'http://example.tal.net/vx/api/v1/applications/222/history'
    }
  }

Expressions

Expressions are how to specify exactly which events of the specified type are of interest. They can be arbitralily complex but require a bit of syntax knowledge and internal IDs to construct correctly, contact your support representive to get help contructing expressions to fit your requirements.

Examples

Any new postings to job board with ID: 123.

type: POSTING_CREATE
expression: posting.posting_loc_meth.post_loc_vac.job_board.id == 123
Any postings on job board ID: 123 that have been updated within 30 days of their closing date.
type: POSTING_UPDATE
expression: posting.posting_loc_meth.post_loc_vac.job_board.id == 123
            AND (posting.closing_date <= (DATE("today") - DTDURATION(0,0,0,30)))
Any status changes for applications to vacancy ID: 321
type: STATE_CHANGE_APPLICATION
expression: application.opportunity_id == 321
Status changes of applications to vacancy 321 that have moved to state 111 where the applicant’s firstname is ‘Dave’
type: STATE_CHANGE_APPLICATION
expression: application.opportunity_id == 321
            AND application.main_process_state.state.id == 111
            AND application.user.firstname == "Dave"

Authentication

Notification payloads are signed by including a signature in an x-oleeo-notify-signature HTTP header. This allows verification that the notification was sent by Oleeo, not by a 3rd party.

A signing key is generated for each subscription and is required to check the signature. It will be returned in the response to the call to create the subscription and also can be retrieved by fetching the subscription object:

GET https://example.tal.net/api/v1/notification_topics/123/subscriptions/321
{
  "topic": {
    "id": 123,
    "url": "http://example.tal.net/vx/api/v1/notification_topics/123",
    "uuid": "ebc4863a-b82c-41c4-a91c-81d2acc17a90",
    "created_dt": "2020-04-09T15:32:08Z"
    "type": "POSTING_UPDATE",
    "name": "Main job board postings update",
    "description": "Updates to postings on main internal job board",
    "expression": "posting.posting_loc_meth.post_loc_vac.job_board.id == 123"
  },
  "id": 12,
  "url": "http://example.tal.net/vx/api/v1/notification_topics/123/subscriptions/12",
  "destination_url": "https://myapp.example.com/webhooks",
  "start_dt": "2021-05-07T10:50:11Z",
  "end_dt": "2021-06-07T10:50:11Z",
  "uuid": "d034529a-c03f-4885-9a47-d10a4d0a05cb",
  "signing_key": "269e6cf13b612f027bf6c0b5b8e01ba707c66ccd"
}

Verifying signatures

  • Extract the timestamp and signature. The x-oleeo-notify-signature header contains a timestamp and a signature, comma separated.
X-Oleeo-Notify-Signature: 1618308159,14354f8dc6d6b203bad46833aa1ea9ea91f9114c0c602baa6c28635c828e78a9
  • Prepare a signed_payload string by concatenating the timestamp and json payload with a . character

  • Compute the expected signature with the SHA256 function using the subscription signing_key as the key and the signed_payload as the message

  • Compare the signature from the header to the expected signature. For an equality match, compute the difference between the current timestamp and the received timestamp, then decide if the difference is within your tolerance.