Webhooks allows third-party users to act on various events triggered by risr/advance. The third-party is responsible for creating a public http server which can accept the payload and for registering the required URLs.
In risr/advance an API user with a “Allow user to manage web hooks” permission can request to be notifed when certain actions happen. The request is called a registration where the user specifies on which action a given URL should be called. For example user can request so that a user profile will be send to a registered url when the profile is updated.
To simplify the process there is no authentication on the targets URL. Instead the payload is signed with a secret provided at registration so that the source is trusted.
Below there is an example of a registration for profile_updated hook.
>>> payload = {
'topic': 'profile_updated,
'url': 'https://myhostname/profile_updated',
'secret': 'signature_secret'
}
>>> registration = requests.post('https://api.kaizenep.com/v2/webhooks/registrations', json=payload, headers=headers)
>>> response.json()
{"id": "new_registration_id", "rev": "revision number"}
When the above runs successfuly risr/advance will issue a POST request with a signed profile json to the url https://myhostname/profile_updated
The webserver accepting the POST request can be implemented in any way and is fully in hand of the third party integrator. However there is an example server that can receive and parse the response.
Note
The example below uses Python and aiohttp (https://docs.aiohttp.org/en/stable/) and it is just to demonstrate how the payload is decoded. It is not a production ready solution.
import json
import jose.jws
from aiohttp import web
async def handle_profile_updated(request):
# await the request payload
data = await request.text()
# Verify it has been signed by the secret provided at registration
payload_str = jose.jws.verify(data, 'signature_secret', algorithms=['HS256'])
payload = json.loads(payload_str.decode('utf-8'))
# The actual handling of the payload
print("The received payload is:")
print(json.dumps(js, indent=2))
return web.json_response({'ok': True})
app = web.Application()
app.add_routes([web.post('/profile_updated', handle_profile_updated)]),
if __name__ == '__main__':
web.run_app(app, port=6785)
When the application is deployed and accesible at https://myhostname it is ready for receiving webhooks.
A convenient way to check the target application works well is to trigger a testing hook:
>>> data = {
'topic': 'profile_uploaded
}
>>> response = requests.post('https://api.kaizenep.com/v2/webhooks/test', json=data, headers=headers)
This code will trigger a profile_updated hook with an example payload. The application from above will print:
{
"auditLog": [],
"id": "profile_org_id",
"webhook_request_id": "f47bf223-f5dd-4f58-aa05-28aaa234aa75",
"email": "john@doe.com",
"rev": "1-1324",
"firstName": "John",
"lastName": "Doe",
"userFields": []
}
user_logged_in
user_registered
profile_updated
booking_updated
booking_state_changed
The user logged in hook is triggered after a successful log in before user is redirected back to the application. The hook is synchronous hence the user is blocked until all the hooks return a value. It is recommended to have as fast response time as possible. The reason for synchronous call is that the user sees changes immediatlely or the permissions are correctly set up before the application loads.
If a longer running action is required we recommend using a queue mechanism and handle the task asynchronously within the integration.
The payload contains kaizen user id and all the data that can be collected from SSO headers.
When you accesses risr/advance for the first time the account is locally set up and user registered hook is called so that the profile can be updated from an external source so that the user has profile data and permission set up before they access the system. The hook is synchronous hence the user is blocked until all the hooks return a value.
The payload contains kaizen user id and all the data that can be collected from SSO headers.
Whenever a user profile is updated or edited this hook is called with the full new updated profile. This hook is asynchronous however we would still recommend to aim for a fast response.
Booking updated hook is triggered any time a booking is saved even if there are no changes to it. The payload contains the newly updated booking document.
Booking state changed is triggered when a transition is executed. It can be any transition even if the workflow state does not change. However some actions could be processed. The payload contains the new booking document plus information about the transition and processed actions.