Skip to main content

Webhooks configuration

Our recommendation

We strongly recommend using webhooks to stay updated on important events. By subscribing to our webhook events, you can receive real-time notifications directly to your application, enabling you to act swiftly and efficiently.

Setting Up Webhooks

To start using webhooks, follow these steps:

  1. Register Your Webhook: Use the Create Webhook endpoint to create your webhooks.

    Request Parameters:

    ParameterTypeDescription
    url requiredstringThe URL endpoint where webhook notifications will be sent
    events requiredstringAn array of event to subscribe to. Refer to the list of Webhook Events for available event types
    facilitiesarrayAn array of facility IDs to limit notifications to specific facilities
    secretsarrayAn array of secret tokens for securing webhook payloads, a maximum of two secrets are allowed, If you do not provide a secret, a random secret will be generated for you
  2. Verify Webhook Signatures: For security, verify the signature of incoming webhook payloads to ensure they are sent from our system. The header looks like this

    Nursa-Signature:
    t=1492774577,
    v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd,
    v1=6ffbb59b2300aae63f272406069a9788598b792a944a07aba816edb039989a39

    Steps to validate the webhook event signature

    1. Get body payload from the incoming event request:

    2. Get the Nursa-Signature header from the incoming event request

    3. Split the header using the , character as the separator to get a list of attributes. Then split each attribute using the = character as the separator to get a prefix and value pair. The value for the prefix t corresponds to the timestamp in seconds, and v1 corresponds to the signature (or signatures if you have more than one secret).

    4. Concatenate the timestamp from the header, the character . and the JSON payload from the body.

    5. Sign the payload with the webhook secret using HMAC with SHA256 hash function, and encode the result with hex.

    6. Compare the signatures

      a. Compare the header's signature (or signatures) to the generated hash. If at least one of them matches, then the signature is correct (that's to guarantee no-downtime rotation).

      b. Calculate the difference between the current and received timestamps, then decide if the difference is within your tolerance.

    Code example on how to validate the request

    import hmac
    import hashlib
    from time import time

    def main():
    # Get request body in JSON format
    body = "{\"data\":{\"shiftId\":\"c1099745-10d6-43ec-8c9d-6653d35ffbce\",\"facilityId\":\"f817ca7b-b2bb-4905-a74d-bc2ab403ffa3\",\"clinicianId\":\"1f559150-35a2-452f-98ec-7b9fe27dafbd\",\"at\":\"2023-06-19T20:51:38.372Z\",\"requestedBy\":{\"userId\":\"fb881bf1-f074-4f2c-aa09-422c7a360d2f\",\"email\":\"request@email.com\",\"source\":\"clinician\"}},\"eventType\":\"shift.request.created\"}"
    # Get this from request header
    signature = "t=1687208610,v1=29421185bad346abe4cbc1ee2048901addd3f9c0a3cff0d4d0022e91dbbdf8d5,v1=6004febfa2e2c5cf3f39e18ff3508ec49c99cad974d9678b6bf1b1a251bb6ca2"
    # Must be stored in a safe location
    secret = "df5c86cfe88295651cd8adb4e867084bfb08e3f522f4f2b967452871fa1a052a";
    validate(body, signature, secret)

    def validate(body, signature, secret):
    attributes = signature.split(",")
    timestamp = resolve_timestamp(attributes)
    # 1687208610
    payload_to_hash = timestamp + "." + body
    hashed = hash_payload(payload_to_hash, secret)
    # 29421185bad346abe4cbc1ee2048901addd3f9c0a3cff0d4d0022e91dbbdf8d5

    is_valid_signature = len([attr for attr in attributes if attr == "v1=" + hashed]) == 1
    is_valid_time = validate_time(timestamp)
    print("Is signature valid? " + str(is_valid_signature) + ". Is valid time? " + str(is_valid_time));
    return is_valid_signature and is_valid_time

    def resolve_timestamp(attributes):
    [key] = [attr for attr in attributes if attr.startswith("t=")]
    return key.split("=")[1]

    def hash_payload(payload, secret):
    return hmac.new(bytes(secret, "utf-8"), payload.encode("utf-8"), hashlib.sha256).hexdigest()

    def validate_time(timestamp):
    now = int(time())
    # You can define how much time you want to consider to prevent replay attacks
    five_minutes_in_seconds = 5 * 60
    return now < int(timestamp) + five_minutes_in_seconds

    main()
  3. Handle Events: Implement logic in your application to process the received events and take appropriate actions.

Why this helps?

Webhooks provide a mechanism for your system to receive notifications when specific events occur in our system. By utilizing webhooks, you can:

  • Receive instant updates: Get notified immediately when an event happens.
  • Reduce API polling: Minimize the need to frequently check our API for changes.
  • Enhance efficiency: Automate workflows and processes in response to real-time events.

Webhook Events

EventDescription
shift.request.createdTriggered when a shift request is created.
shift.request.cancelledTriggered when a shift request is cancelled.
shift.report.createdTriggered when a shift report is created.
shift.scheduled.cancelledTriggered when a scheduled shift is cancelled.
shift.scheduledTriggered when a shift is scheduled.
shift.report.accepted-automaticallyTriggered when a shift report is automatically accepted.
shift.report.acceptedTriggered when a shift report is accepted.
shift.report.rejectedTriggered when a shift report is rejected.
shift.cancelledTriggered when a shift is cancelled.
allTriggers notifications for all events.
facility.user-connection.acceptedTriggered when a facility user connection is accepted.
facility.user-connection.rejectedTriggered when a facility user connection is rejected.
facility.creation.acceptedTriggered when a facility creation request is accepted.
facility.creation.rejectedTriggered when a facility creation request is rejected.

Please refer to the Webhooks Events page to check the payload of each event.