Manage webhooks

Estimated reading time: 18 minutes

DTR includes webhooks for common events, such as pushing a new tag or deleting an image. This lets you build complex CI and CD pipelines from your own DTR cluster.

The webhook events you can subscribe to are:

Repository specific events

  • Tag push
  • Tag delete
  • Manifest push
  • Manifest delete
  • Security scan completed
  • Security scan failed

Namespace specific events

  • Repo events (created/updated/deleted)

Global events

  • Security scanner update complete

In order to subscribe to an event you need to be at least an admin of the particular repository (for repository events) or namespace (for namespace events). A global administrator can subscribe to any event. For example, a user must be an admin of repository “foo/bar” to subscribe to its tag push events.

Subscribing to events

In order to subscribe to events you must send an API query to /api/v0/webhooks with the following payload:

{
  "type": "",
  "key": "",
  "endpoint": "https://example.com"
}

The keys in the payload are:

  • type: The event type. These are listed below.
  • key: The namespace or repo to subscribe to (eg “foo/bar” to subscribe to pushes to repo “bar” within namespace “foo”)
  • endpoint: The URL to send the POST payload to.

Normal users must supply a “key” to scope a particular webhook event to a repository or namespace. System administrators can choose to omit this, meaning a webhook payload will be sent for every repository or namespace.

Event types

Repository specific events

  • Tag push (type TAG_PUSH)
  • Tag delete (type TAG_DELETE)
  • Manifest push (type MANIFEST_PUSH)
  • Manifest delete (type MANIFEST_DELETE)
  • Security scan completed (type SCAN_COMPLETED)
  • Security scan failed (type SCAN_FAILED)

Namespace specific events

  • Repo created/updated/deleted (type REPO_EVENT)

Global events

  • Security scanner update complete (type SCANNER_UPDATE_COMPLETED)

Receiving a payload

Whenever a suitable action occurs DTR will send a POST request to the given endpoint with a JSON encoded payload. The payload will always have the following wrapper:

{
  "type": "...",
  "createdAt": "2012-04-23T18:25:43.511Z",
  "contents": {...}
}

type refers to the event type being sent, and contents refers to the payload of the event itself. Each event is different, therefore the structure of the JSON object in contents will change depending on the event type. These are listed in a section below.

Testing payload subscriptions

Before subscribing to a payload you can view and test your endpoints using fake data. To send a test payload, fire a POST request to /api/v0/webhooks/test with the following payload:

{
  "type": "...",
  "endpoint": "https://www.example.com/"
}

Change type to the event type that you want to receive. DTR will then send an example payload to the endpoint specified. Note that the example payload sent is always the same.

Content structure

Note that comments (// here) are added for documentation only; they are not present in POST payloads.

Repository event content structure

Tag push

{
  "namespace": "",    // (string) repository's namespace name
  "repository": "",   // (string) repository name
  "tag": "",          // (string) the name of the tag just pushed
  "digest": "",       // (string) sha256 digest of the manifest the tag points to (eg. "sha256:0afb...")
  "imageName": "",    // (string) the fully-qualified image name including DTR host used to pull the image (eg. 10.10.10.1/foo/bar:tag)
  "os": "",           // (string) the OS for the tag's manifest
  "architecture": "", // (string) the architecture for the tag's manifest
  "author": "",       // (string) the username of the person who pushed the tag
  "pushedAt": "",     // (string) JSON encoded timestamp of when the push occurred
}

Tag delete

{
  "namespace": "",    // (string) repository's namespace name
  "repository": "",   // (string) repository name
  "tag": "",          // (string) the name of the tag just deleted
  "digest": "",       // (string) sha256 digest of the manifest the tag points to (eg. "sha256:0afb...")
  "imageName": "",    // (string) the fully-qualified image name including DTR host used to pull the image (eg. 10.10.10.1/foo/bar:tag)
  "os": "",           // (string) the OS for the tag's manifest
  "architecture": "", // (string) the architecture for the tag's manifest
  "author": "",       // (string) the username of the person who deleted the tag
  "deletedAt": "",     // (string) JSON encoded timestamp of when the delete occurred
}

Manifest push

{
  "namespace": "",    // (string) repository's namespace name
  "repository": "",   // (string) repository name
  "digest": "",       // (string) sha256 digest of the manifest (eg. "sha256:0afb...")
  "imageName": "",    // (string) the fully-qualified image name including DTR host used to pull the image (eg. 10.10.10.1/foo/bar@sha256:0afb...)
  "os": "",           // (string) the OS for the manifest
  "architecture": "", // (string) the architecture for the manifest
  "author": "",       // (string) the username of the person who pushed the manifest
  "pushedAt": "",     // (string) JSON encoded timestamp of when the push occurred
}

Manifest delete

{
  "namespace": "",    // (string) repository's namespace name
  "repository": "",   // (string) repository name
  "digest": "",       // (string) sha256 digest of the manifest (eg. "sha256:0afb...")
  "imageName": "",    // (string) the fully-qualified image name including DTR host used to pull the image (eg. 10.10.10.1/foo/bar@sha256:0afb...)
  "os": "",           // (string) the OS for the manifest
  "architecture": "", // (string) the architecture for the manifest
  "author": "",       // (string) the username of the person who deleted the manifest
  "deletedAt": "",    // (string) JSON encoded timestamp of when the delete occurred
}

Security scan completed

{
  "namespace": "",    // (string) repository's namespace name
  "repository": "",   // (string) repository name
  "tag": "",          // (string) the name of the tag scanned
  "imageName": "",    // (string) the fully-qualified image name including DTR host used to pull the image (eg. 10.10.10.1/foo/bar:tag)
  "scanSummary": {
    "namespace": "",          // (string) repository's namespace name
    "repository": "",         // (string) repository name
    "tag": "",                // (string) the name of the tag just pushed
    "critical": 0,            // (int) number of critical issues, where CVSS >= 7.0
    "major": 0,               // (int) number of major issues, where CVSS >= 4.0 && CVSS < 7
    "minor": 0,               // (int) number of minor issues, where CVSS > 0 && CVSS <
    "last_scan_status": 0,    // (int) enum; see scan status section
    "check_completed_at": "", // (string) JSON encoded timestamp of when the scan completed
  }
}

Security scan failed

{
  "namespace": "",    // (string) repository's namespace name
  "repository": "",   // (string) repository name
  "tag": "",          // (string) the name of the tag scanned
  "imageName": "",    // (string) the fully-qualified image name including DTR host used to pull the image (eg. 10.10.10.1/foo/bar@sha256:0afb...)
  "error": "",        // (string) the error that occurred whilst scanning
}

Namespace specific event structure

Repository event (created/updated/deleted)

{
  "namespace": "",    // (string) repository's namespace name
  "repository": "",   // (string) repository name
  "event": "",        // (string) enum: "REPO_CREATED", "REPO_DELETED" or "REPO_UPDATED"
  "author": "",       // (string) the name of the user which authored the event
  "data": {}          // (object) when updating or creating a repo this follows the same format as an API response from /api/v0/repositories/{namespace}/{repository}
}

Global event structure

Security scanner update complete

{
  "scanner_version": "",
  "scanner_updated_at": "", // (string) JSON encoded timestamp of when the scanner updated
  "db_version": 0,          // (int) newly updated database version
  "db_updated_at": "",      // (string) JSON encoded timestamp of when the database updated
  "success": <true|false>   // (bool) whether the update was successful
  "replicas": {             // (object) a map keyed by replica ID containing update information for each replica
    "replica_id": {
      "db_updated_at": "",  // (string) JSON encoded time of when the replica updated
      "version": "",        // (string) version updated to
      "replica_id": ""      // (string) replica ID
    },
    ...
  }
}

Security scan status enums

  • 0: Failed. An error occurred checking an image’s layer
  • 1: Unscanned. The image has not yet been scanned
  • 2: Scanning: Scanning in progress
  • 3: Pending: The image will be scanned when a worker is available
  • 4: Scanned: The image has been scanned but vulnerabilities have not yet been checked
  • 5: Checking: The image is being checked for vulnerabilities
  • 6: Completed: The image has been fully security scanned

Viewing and managing existing subscriptions

Viewing all subscriptions

To view existing subscriptions make a GET request to /api/v0/webhooks. As a normal user (ie. not a system administrator), this will show all of your current subscriptions across every namespace and repository. As a system administrator this will show every webhook within DTR.

The API response will be in the following format:

[
  {
    "id": "",        // (string): UUID of the webhook subscription
    "type": "",      // (string): webhook event type
    "key": "",       // (string): the individual resource this subscription is scoped to
    "endpoint": "",  // (string): the endpoint in which the payload will be sent to via a POST request
    "authorID": "",  // (string): the ID of the user which created this subscription
    "createdAt": "", // (string): JSON encoded datetime when this subscription was created
  },
  ...
]

For more information view the API documentation.

Viewing subscriptions for a particular resource

You can also view subscriptions for a given resource that you are an administrator of. For example, if you have admin rights to the repository “foo/bar” you can view all subscriptions (even other people’s) from a particular API endpoint. These endpoints are:

  • /api/v0/repositories/{namespace}/{repository}/webhooks: GET to view all webhooks for a repository resource’s events
  • /api/v0/repositories/{namespace}/webhooks: GET to view all webhooks for a namespace resource’s events

Deleting a subscription

To delete a webhook subscription send a DELETE request to /api/v0/webhooks/{id}, replacing {id} with the webhook subscription ID which you would like to delete.

Note that in order to delete a subscription you must be either a system administrator or an admistrator for the resource which the payload subscribes to. For example, as a normal user you can only delete subscriptions for repositories which you are an admin of.

chat icon Feedback? Suggestions? Can't find something in the docs?
Edit this page Request docs changes Get support