Skip to content

Event Notifications

Event Notifications

Data delivery can be automated using subscriptions.

Subscriptions currently support real-time notifications via webhooks or emails.

Users can specify multiple subscriptions for a project for multiple events. Once a new real-time subscription is specified, events relating to that project will be submitted to the target URL in JSON format via HTTP POST requests in case of a webhook notification, or via email otherwise.

After creating a subscription, users can view the subscription notification history and additional information such as response status and payload in the Gencove web UI.

Currently, legacy webhook format and an updated format are supported. New event types will only support new format.

Once a webhook is received, the receiver is responsible for querying the Gencove API for more details on each object that is referenced. For example, upon receiving a analysis_complete_v2 webhook for a project, the receiver should query the Gencove API for additional sample details and fresh download URLs for deliverables related to those samples.

Available event types and webhook format

The content of the webhook contains a list of event objects where each event has the following keys:

  • event_id, a unique identifier of the event
  • event_type, describing the type of event
  • payload, event-specific webhook contents
  • timestamp

Notes on delivery semantics:

  • the top-level array may contain multiple events - always iterate it rather than reading only the first element
  • delivery is at-least-once and ordering is not guaranteed. For analysis_complete_v2 and sample_status_update, deduplicate on each sample's last_status.id (the same status can be re-announced under a new event_id) and order by last_status.created; for other events deduplicate on event_id
  • payload objects may gain additional keys over time - integrations should ignore unknown keys

The following events are available:

  • analysis_complete_v2
    • this event describes the completion of analysis on samples belonging to a project. The webhook payload will contain the respective project_id and a list of samples.
  • sample_status_update
    • this event fires on every sample status change, including kit ordering and lab lifecycle transitions (see the sample status lifecycle). The payload shares the analysis_complete_v2 schema, so both event types can be handled by one parser - iterate the samples list rather than assuming a fixed number of entries. One event can carry many samples and their statuses can differ (for example, a finished run delivers its succeeded and failed … samples in one event); the same sample can also appear more than once. Each entry's last_status describes the transition being announced for that sample. last_status.status may take values beyond those in the lifecycle tables; treat unrecognized values as informational rather than errors. Kit and lab statuses come from periodic synchronization with the lab, so several events can arrive close together; last_status.created is when Gencove recorded the status. Final analysis statuses (succeeded, failed …) arrive as sample_status_update events too, so also subscribing to analysis_complete_v2 is redundant if you consume this event, with one exception: samples copied into a project from another project are announced only by analysis_complete_v2.
  • batch_final_report_complete_v2
    • this event describes the completion of creation of "Backwards-compatible array deliverables"
  • samples_restored
    • this event describes the restoration of archived samples, for more information about archiving see here. The webhook payload will contain the respective project_id and restore_group_id that can be used to obtain more information in sample-restore-group/ endpoint in the API
[
  {
    "event_id": "0b2d7502-86b0-863e-11e2-990d0e134e8a",
    "event_type": "analysis_complete_v2",
    "timestamp": "2021-04-09T12:01:26.346341Z",
    "payload": {
      "project": {
        "id": "1d6daca6-475a-4961-9841-57aac36cbd0f"
      },
      "samples": [
        {
          "id": "45273390-64bd-4a07-a1be-8514d3ba7750",
          "client_id": "HumanS01-001",
          "last_status": {
            "id": "7c94085d-c2bf-4d7b-91aa-9708b9011782",
            "status": "succeeded",
            "created": "2021-04-09T12:01:26.311204+00:00"
          }
        }
      ]
    }
  }
]
[
  {
    "event_id": "9f41c1b6-2c5d-4e37-8a10-6c3b5b1f0d24",
    "event_type": "sample_status_update",
    "timestamp": "2021-04-09T12:01:26.346341Z",
    "payload": {
      "project": {
        "id": "1d6daca6-475a-4961-9841-57aac36cbd0f"
      },
      "samples": [
        {
          "id": "45273390-64bd-4a07-a1be-8514d3ba7750",
          "client_id": "HumanS01-001",
          "last_status": {
            "id": "e8b7a3d2-51f4-4c69-b0aa-2d9c47e6f815",
            "status": "kit shipped",
            "created": "2021-04-09T12:01:26.311204+00:00"
          }
        }
      ]
    }
  }
]
[
  {
    "event_id": "bdc558af-4815-7736-8bab-9be8c5f63fff",
    "event_type": "batch_final_report_complete_v2",
    "timestamp": "2021-04-09T12:01:26.346341Z",
    "payload": {
      "project": {
        "id": "1d6daca6-475a-4961-9841-57aac36cbd0f"
      },
      "batch": {
        "id": "77799c11-aa57-4a06-aa17-978d203f1eb5",
        "name": "Batch 001",
        "last_status": {
          "status": "succeeded"
        }
      }
    }
  }
]
[
  {
    "event_id": "d60f19f7-9fed-4ef6-8dee-13d376e2c6af",
    "event_type": "samples_restored",
    "timestamp": "2024-06-25T14:21:02.072313Z",
    "payload": {
      "project": {
        "id": "1d6daca6-475a-4961-9841-57aac36cbd0f"
      },
      "restore_group": {
        "id": "11d66a31-f277-4af4-8b34-15c352ca3d47",
        "created": "2024-06-25T14:20:16.165992+00:00",
        "last_status": {
          "status": "restored"
        }
      }
    }
  }
]

Available legacy event types and webhook format

Please note that users are highly encouraged to use the updated format. We are planning to sunset legacy format at a later date. Please follow our blog or our mailing list for more information about this in the future.

The content of the legacy webhook contains the following keys:

  • event, describing the type of event
  • payload, event-specific webhook contents
  • object_id, a unique identifier for the originating object of the webhook
  • timestamp

Together, object_id and event should be considered unique and duplicates should be handled by the receiver.

The following legacy events are available:

  • analysis_complete

    • this event describes the completion of analysis on samples belonging to a project. The webhook payload will contain the respective project_id and a list of sample_ids.
  • batch_final_report

    • this event described the completion of creation of "Backwards-compatible array deliverables"
{
    "event": "analysis_complete",
    "object_id": "99573a16-98a8-48fc-8caf-e3b4dcdf34e6",
    "timestamp": "2018-11-18T14:09:59.741183",
    "payload": {
        "project_id": "1d6daca6-475a-4961-9841-57aac36cbd0f",
        "sample_ids": [
            "45273390-64bd-4a07-a1be-8514d3ba7750"
        ]
    }
}
{
    "event": "batch_final_report",
    "object_id": "99573a16-98a8-48fc-8caf-e3b4dcdf34e6",
    "timestamp": "2018-11-18T14:09:59.741183",
    "payload": {
        "project_id": "1d6daca6-475a-4961-9841-57aac36cbd0f",
    }
}

Webhook signatures

Gencove can optionally sign webhook events it sends to endpoints. This is done by including a signature in each event’s Gencove-Signature header, allowing you to verify that the events were sent by Gencove.

Before verifying signatures, webhooks need to be enabled and the secret needs to be retrieved for each project via the Gencove API (API reference). Note that each subscription has a separate unique secret.

After this setup, Gencove automatically starts signing each webhook notification it sends to the endpoint of the related project.

Verifying webhook signatures

The Gencove-Signature header contains a timestamp and a signature:

  • the timestamp is an integer representing UNIX time and is prefixed by t=
  • the signature is prefixed by a scheme, which starts with v and is followed by an integer. Currently, the only valid signature scheme is v1.

Example signature: Gencove-Signature: t=1492774577,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd

Gencove generates signatures using a hash-based message authentication code (HMAC) with SHA-512. To prevent downgrade attacks, you should ignore all schemes that are not v1.

There are multiple ways to verify a signature, there is a command available in the Gencove CLI, it can be done directly from the python console or from any other tool that can generate a HMAC with SHA-512.

Step 1: Extract the timestamp and signatures from the header

Split the header, using the , character as the separator, to get a list of elements. Then split each element, using the = character as the separator, to get a prefix and value pair.

The value for the prefix t corresponds to the timestamp, and v1 corresponds to the signature.

Step 2: Prepare signature_message

This is achieved by concatenating:

  1. The timestamp (as a string)
  2. The character .
  3. The actual JSON payload (i.e., the request’s body)

Step 3: Determine the expected signature

Compute an HMAC with the SHA512 hash function. Use the endpoint’s signing secret as the key and the signature_message string as the message.

Step 4: Compare signatures

Compare the signature in the header to the expected signature. If a signature matches, compute the difference between the current timestamp and the received timestamp, then decide if the difference is within your tolerance.

export SECRET='super-secret'
export HEADER='t=1492774577,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd'
export PAYLOAD='{"k":"v"}'
gencove webhooks verify $SECRET $HEADER $PAYLOAD
import hmac, hashlib

def calculate_signature(secret, timestamp, payload):
    signature_message = "{}.{}".format(timestamp, payload).encode("utf-8")
    return hmac.new(
        secret.encode("utf-8"),
        signature_message,
        hashlib.sha512
    ).hexdigest()

Testing

To support developers using the event notification system, a straightforward way is provided to test notification delivery without waiting for a real event to occur in the system.

In My projects, the user can select the project for which notifications should be tested, click Manage subscriptions, and from the list of existing subscriptions, select View to open subscription details. On this page, the user can use the Test button to send a test notification.

The same page also shows a history of notifications dispatched by the system, with test notifications clearly marked.

If an integration has not yet been built, we recommend using a free service such as webhook.site to view the expected payload.