The Cloudsmith Developer Hub

Welcome to the Cloudsmith Developer Hub. You'll find comprehensive guides and documentation to help you start working with Cloudsmith as quickly as possible, as well as support if you get stuck. Let's jump right in!

Get Started    
Webhooks are great for driving automation by pushing data to your pipelines, or by integrating with your chat tools to provide slick ChatOps.

Cloudsmith webhooks support events that occur in a repository, such as when packages have been uploaded, are synchronising, have synchronised or have failed. We plan to add more events in the future, and to have them creatable at the namespace (user/org) level.

Pipeline Automation

For pipeline automation, you might utilise webhooks to instruct a CI/CD service, such as CircleCI or Spinnaker, that it is time to deploy when a synchronised package is moved to your production repository. In this way, you can control the flow from development to production by limiting who (or what) has the authority to move packages to the production repository, and thus, to deploy publicly.


For ChatOps, you can utilise webhooks to send a message to a chat tool such as Slack when each type of event occurs. You'll format this in such a way so as to present critical information to your team, such as what the package is, where it is located, who uploaded it, and how to access it, etc. If you're really fancy, you'll have a Slack integration that lets users interact with Cloudsmith via slash commands, for super slick bi-directional DevOps goodness.

Create a Webhook

Creating a webhook is simple and only requires an endpoint to send it to.

Create Webhook Button

Create Webhook Form

For testing webhooks, we recommend either Webhook Tester or RequestCatcher.

Webhook Payload Formats

Cloudsmith supports multiple payload formats for webhooks. Plus a templating format, using the handlebars language, for the ultimate in flexibility. You can find more details on that, later in this guide.

The payload formats supported are:

Payload Format



JSON Object

The payload is encoded as a singular JSON Object at the root-level.

  "data": {"foo": bar"}

JSON Array

The payload is encoded as a JSON Array at the root-level.

  "data": {"foo": bar"}

Form Encoded JSON Object

The payload is encoded as a singular JSON Object at the root-level.


Handlebars Template

The payload is encoded in a format determined by the template that you create.

  • foo: bar

See below for more information on how to construct/use handlebars templates.

Webhook Event Types / Subscriptions

Cloudsmith splits repository-level webhooks into a number of different event types. When you create a webhook, you're subscribing it to either all event types, or a subset of them. When that event occurs, if your webhook is subscribed, you'll get a notification in the payload format your chose previously.

Each type of webhook event occurs for a different reason and may have a varying structure to the payload. However, each of the "Package" events will always have the package that caused the event.

The event types are:




Content Type



Sent when a new webhook is created, or when requested; to test an endpoint.


Package Created


Sent when a package has first been uploaded, but not yet processed.


Package Syncronising


Sent when a package has started to be processed (i.e. synchronising state).


Package Syncronised


Sent when a package has been fully processed (i.e. synchronised), and is available for download.


Package Failed


Sent when a package has failed to process.


Package Deleted


Sent when a package has been deleted.


Package Tags Changed


Sent when the tags for a package have changed.


Package Query Filter

You can also add a package search query to webhooks. This uses the same search syntax supported elsewhere for searching. If present, packages that emit events need to match the search query provided. In this way, you could filter webhooks for only certain types of packages, in addition to specific events.

For example, to send Package Synced events for my-web-app packages that have the release tag, you can define the query as name:my-web-app AND tag:release.

As shown below:

Using the Package Query Filter

Webhook Security

Secret Header / Value

If you need a way of authenticating a webhook at the receiver, and you don't want to use the HMAC-based verification outlined later below, you can use the Secret Header and Secret Value fields. These are values that will be sent with every webhook sent, that allow you to perform some form of authentication on the receiver side. Typically useful if the webhook is otherwise open to the world, but you want to authenticate before enacting on the webhook. Cloudsmith stores the Secret Value encrypted internally.

Validating Webhooks

If you're super paranoid about security, and you should be (of course), you can validate that webhooks originated from Cloudsmith, unaltered. To do this, each message that is sent from Cloudsmith calculates an HMAC Digest of the contents. This HMAC, which stands for Hash-based Message Authentication Code, is generated using a cryptographic method for describing the contents of a message, verifiable by the receiver.

To start, you'll need to either provide or make note of the HMAC Signature Key. This is used to generate the HMAC, and you'll need it on the receiver side to be able to validate messages. After a webhook is created, you'll be able to supply new values for the signature key, but you won't be able to retrieve the old one anymore. The value is stored encrypted in Cloudsmith.

When enabled, Cloudsmith will send the HMAC in the X-Cloudsmith-Signature header of every message. The algorithm used for the calculation is HMAC-SHA1. With the secret, you can then verify this against the payload (contents of the message) using the following method (Python-like pseudo-code):

hmac_received = message_headers["X-Cloudsmith-Signature"]
hmac_calculated = hmac_sha1("my-secret-key", message_body)
hmac_validated = (hmac_received == hmac_calculated)
if not hmac_validated:


  • hmac_sha1 is a function that takes a secret key, and the payload, and returns an HMAC.
  • message_headers is the headers received from Cloudsmith in the HTTP request.
  • message_body is the body/payload of the webhook received from Cloudsmith in the HTTP request.
  • "my-secret-key" is the secret key from the HMAC Signature Key field in the webhook form.
  • bailout is a function that cancels everything, alerts your team, and stops bad things from happening.

Verifying SSL Certificates

You can choose to not verify SSL certificates when webhooks are sent. You'll need this if the destination endpoint is using a self-signed certificate. However, please be aware that it opens you to attacks where the endpoint is replaced by a malicious user. Use with care.

Webhook Templates (Handlebars)

Handlebars is a minimal templating language, normally used in Javascript-based applications, for constructing messages based on variables and limited conditional flow. This means you can drive all kinds of external services, without needing an intermediate "translation" service in-between, such as IFTTT or Zapier. Of course, you can still use those to achieve some powerfully dynamic integrations.

Template Format

When creating templates, you can choose the overall Template Format that you'd like to emit. This primarily changes the Content-Type that is sent with the webhook but also determines the syntax highlighting in the editor, and the validation of the content. You can also override the exact Content Type you'd like to send if you want to be more specific.

Event Templates

For each of the event types, you can write a different template. If you provide a specific template for a specific event, that template will be chosen first. Otherwise, it will use the Default template. In this way, you can process the events in different ways, depending on which fired but send them all to the same endpoint.

Handlebars Syntax

The Handlebars Basic Usage is a good first reference for how to construct a template. An example of some of the constructs you'll use are interpolation (getting data from the webhook payload), functions (manipulating the data), and conditionals (doing different thing depending on the data content):

  • Interpolation: Use {{}}, to get name from the data object.
  • Functions: Use {{concat "-test"}}, to concatenation and "-test" together.
  • Conditionals: Use {{#if (gt data.downloads 0)}foo{{/if}} to output foo if data.downloads is greater-than zero.


The thing to note here is that you'll be acting upon the JSON data from a webhook payload (which you can see later on in the "Webhook Payloads") section. Plus, when you're creating the webhook, it's possible to get a live view of example data (taken from your repository), by clicking the following link:

Get Example Webhook Data

Helper Functions

In addition to the builtin helpers, we have a number of additional helper functions that extend the base handlebars syntax. You can call a helper function using the Handlebars syntax of {{func arg1 arg2}} for emitting values, and {{#if (func arg1 arg2}} in conditionals.

The functions supported are:






Unary (1 arg)

Arithmetic Negation

{{neg 10}} = -10


Unary (1 arg)

Logical Negation

{{neg false}} = true


Unary (1 arg)

Truth Test

{{truth 1}} = true


Unary (1 arg)

Convert to JSON

{{tojson data.some.object}}


Binary (2 args)

Arithmetic Addition

{{add 5 5}} = 10


Binary (2 args)


{{concat "foo" "bar"} = foobar


Binary (2 args)

Arithmetic Floating Division

{{div 5 2}} = 2.5


Binary (2 args)

Arithmetic Integer Division

{{floordiv 5 2}} = 2


Binary (2 args)

Logical/Bitwise And

{{and true true}} = true
{{and true false}} = true


Binary (2 args)

Logical/Bitwise Or

{{or true true}} = true
{{or true false}} = true


Binary (2 args)

Logical/Bitwise Exclusive Or

{{xor true true}} = true
{{xor true false}} = false


Binary (2 args)

Arithmetic Modulo

{{mod 5 2}} = 1


Binary (2 args)

Arithmetic Multiplication

{{mul 5 5}} = 25


Binary (2 args)

Arithmetic Subtraction

{{sub 10 5}} = 5


Binary (2 args)

Relational Less-Than

{{lt 5 10}} = true
{{lt 5 5}} = false


Binary (2 args)

Relational Less-Than or Equal-To

{{lte 5 10}} = true
{{lte 5 5}} = true


Binary (2 args)

Relational Greater-Than

{{gt 10 5}} = true
{{gt 5 5}} = false


Binary (2 args)

Relational Greater-Than or Equal-To

{{gte 10 5}} = true
{{gte 5 5}} = true


Binary (2 args)

Relational Equality

{{eq 10 5}} = false
{{eq 5 5}} = true


Binary (2 args)

Relational Inequality

{{ne 10 5}} = true
{{ne 5 5}} = false


Binary (2 args)

Needle (arg1) contained in Stack (arg2)

{{contains "foo" "foobar"}} = true
`{{contains "baz" "foobar"}} = 'false'


Binary (2 args)

Needle (arg1) is at start of Stack (arg2)

{{startswith "foo" "foobar"}} = true
`{{startswith "bar" "foobar"}} = 'false'


Binary (2 args)

Needle (arg1) is at end of Stack (arg2)

{{endswith "bar" "foobar"}} = true
`{{endswith "foo" "foobar"}} = 'false'


Binary (2 args)

Join Elements (arg2) by Delimiter (arg1)

{{join ";" ["a", "b"]}} = a;b


Binary (2 args)

Split String (arg2) by Delimiter (arg1)

{{split ";" "a;b"}} = ["a", "b"]

Example Template

The following is a short worked example of how you might use templates:

Sheila, a Senior DevOps engineer at WhyObi Ltd, is setting up alerts for ChatOps. She'd like to get a notification for when a specific package has been synchronised (is available for download) and would like to output the download URL for it in a special Slack channel. If the package has a tag labelled "hotfix" tag, she'd also like to call this out in bold as part of the message.

To start with, Sheila creates a new webhook. This is a Slack webhook, and according to the Slack documentation for incoming webhooks, it needs to have a content type of application/json. So Sheila enters the new webhook endpoint, chooses Handlebars Template as the Payload Format, and picks JSON (application/json) as the Template Format.

She's only interested in packages that have synchronised, so she selects Send Specific Events (choose) in Event Subscriptions, and then ticks the Package Synchronised checkbox. Going back to the Payload Templates, she clicks on the Package Synchronised tab to start a new template for that type of event.

Now, for the fun part, to meet her requirements Sheila writes out the following template using the Handlebars language, but constructs it to make a Slack-compatible payload:

  "username": "cloudsmith-bot",
  "icon_emoji": ":cloud:",
  "blocks": [
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "The <{{data.self_html_url}}|{{}}{{#if (truth data.version)}} ({{data.version}}){{/if}}> {{data.format}} package is ready for download."
     {{#if (eq this "hotfix")}}
         "type": "section",
         "text": {
           "type": "mrkdwn",
           "text": "*HOTFIX*: Warning, this is an non-standard release."
    {{#each data.files}}
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "Download File: <{{this.cdn_url}}|{{this.filename}}>"
    }{{#if (not @last)}},{{/if}}

Also, to make the Ping event (for testing the endpoint) compatible with Slack, she also fills in the template for that too but makes it a simple one:

  "username": "cloudsmith-bot",
  "icon_emoji": ":cloud:",
  "text": "Ping? Ping!"

Putting this altogether, the final form looks like:

She tests the integration by uploading a package called genesis, at version 1.0.3, and assigns it the hotfix tag. When Cloudsmith has synchronised the content, she receives a ChatOps alert in her Slack channel where she created the incoming webhook:

Mission. Success! Now her team has a way of being informed directly in Slack of packages that are uploaded. Along with an easy link to the UI for the package, and a download link for the file. She's also informed if the package was labelled as a hot fix release.

Webhook Payloads

Common Structure

All webhooks sent from Cloudsmith have the following structure (in JSON Object format):

  "context": object,
  "data": object,
  "meta": {
    "attempt_at": string,
    "event_at": string,
    "event_id": string,
    "trigger_id": string,
    "webhook_id": integer

With the following definitions:

Field (Path)







An object for the event context if available (e.g. "old_tags" and "new_tags" for "Package Tags Changed" events).


  "old_tags": ["foo"],
  "new_tags": ["bar"]



An object for the event, usually a Package model.


See Example Package Payload below.



An ISO 8601 datetime string, representing when the webhook was sent at.













A globally (as in, all of Cloudsmith) unique identifier for the trigger.





A sequential id for the source webhook. Unique per repository.



Example Package Payload

An example of a Package payload, sent for webhooks emitted by packages:

  "data": {
    "architectures": [],
    "cdn_url": "",
    "checksum_md5": "f64c6c0eb95e8455d0d5b248e988b4ff",
    "checksum_sha1": "4d10412ec6c66b5e2bfd28fbda893a9d7c8fd1a4",
    "checksum_sha256": "82ee34b2ee3715e055f58a5825799b5d763e8517bc2d5da80a8ac5c59d9940d3",
    "checksum_sha512": "b6075cb64564ab9048c28426ebb1345aef52f0a65f2ff1dcf5caba1b228be85e29775c419a6dc36ac0b455888544e2948f6182ef38064bebebc349e2851027e1",
    "description": "My Awesome Package",
    "distro": null,
    "distro_version": null,
    "downloads": 0,
    "epoch": null,
    "extension": ".deb",
    "filename": "my-file.deb",
    "files": [
        "cdn_url": "",
        "checksum_md5": "f64c6c0eb95e8455d0d5b248e988b4ff",
        "checksum_sha1": "4d10412ec6c66b5e2bfd28fbda893a9d7c8fd1a4",
        "checksum_sha256": "82ee34b2ee3715e055f58a5825799b5d763e8517bc2d5da80a8ac5c59d9940d3",
        "checksum_sha512": "b6075cb64564ab9048c28426ebb1345aef52f0a65f2ff1dcf5caba1b228be85e29775c419a6dc36ac0b455888544e2948f6182ef38064bebebc349e2851027e1",
        "downloads": 0,
        "filename": "my-file.deb",
        "is_downloadable": true,
        "is_primary": true,
        "is_synchronised": true,
        "size": 2204,
        "slug_perm": "8m7hRtzW7Ylq",
        "tag": "pkg"
    "format": "raw",
    "format_url": "",
    "identifier_perm": "xKYgfsOsboz6",
    "indexed": true,
    "is_sync_awaiting": false,
    "is_sync_completed": true,
    "is_sync_failed": false,
    "is_sync_in_flight": false,
    "is_sync_in_progress": false,
    "license": null,
    "name": "my-file.deb",
    "namespace": "my-org",
    "namespace_url": "",
    "num_files": 0,
    "package_type": 1,
    "release": null,
    "repository": "testo2",
    "repository_url": "",
    "self_html_url": "",
    "self_url": "",
    "size": 2204,
    "slug": "my-package",
    "slug_perm": "xKYgfsOsboz6",
    "stage": 9,
    "stage_str": "Fully Synchronised",
    "stage_updated_at": "2020-07-06T21:00:50.635246Z",
    "status": 4,
    "status_reason": null,
    "status_str": "Completed",
    "status_updated_at": "2020-07-06T21:00:50.635221Z",
    "status_url": "",
    "subtype": "file",
    "summary": null,
    "sync_finished_at": "2020-07-06T21:00:50.635239Z",
    "sync_progress": 100,
    "tags": {
      "version": [
    "tags_immutable": {},
    "type_display": "file",
    "uploaded_at": "2020-07-06T18:57:07.199040Z",
    "uploader": "my-user",
    "uploader_url": "",
    "version": null,
    "version_orig": null
  "meta": {
    "attempt_at": "2020-07-07T17:30:34.342167+00:00",
    "event_at": "2020-07-07T17:30:34.296482+00:00",
    "event_id": "package.synced",
    "trigger_id": "c0e2b63e-3d84-4d54-bd62-ae7d0b2764a7",
    "webhook_id": 1

Webhook Origin IP Addresses

The webhooks can originate from the following IP addresses:


These are not guaranteed to remain static forever, but we have plans on our roadmap to implement an API so that they can be discovered (retrieved) at any point. If this is important to you, let us know!

Updated 2 months ago


Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.