Webhooks

NewReleases can send webhook events that notify your application about new version releases.

This is done by sending a JSON-encoded object via an HTTP POST request to any endpoint URLs that you have defined in your account’s Webhooks settings.

Webhook POST request body data

Webhook request data is a JSON-encoded object that contains information about project version release. It contains the following fields:

  • provider project provider id (string)
  • project project name (string)
  • version project version (string)
  • time project version release time in RFC3339 format (string)
  • is_prerelease true if version a pre-release (boolean, optional)
  • is_updated true if version updated (boolean, optional)
  • note release note information (object, optional)
    • title release note title (string, optional)
    • message release note message body in HTML format (string, optional)
An example of such request body:

{  
   "provider": "github",
   "project": "nodejs/node",
   "version": "v11.5.0",
   "time": "2018-12-30T16:08:51.864468Z",
   "is_prerelease": true,
   "is_updated": true,
   "note": {  
      "title": "Release v11.5.0",
      "message": "Release features\u003cbr\u003eBugfixes"
   }
}

Verifying signatures

NewReleases is signing every Webhook request that is sends to your endpoints. A hex-encoded HMAC-SHA256 signature is included in X-Newreleases-Signature HTTP header. The message that is signed is created from X-Newreleases-Timestamp HTTP request header, a dot . and a complete HTTP request body.

Step 1: Extract the timestamp and signature from headers

Read values as strings from X-Newreleases-Signature and X-Newreleases-Timestamp from received HTTP request.

Step 2: Prepare signed message string

You achieve this by concatenating:

  • The timestamp from X-Newreleases-Timestamp (as a string)
  • The "dot" character .
  • The request's body (JSON payload)

Step 3: Determine the expected signature

Compute an HMAC with the SHA256 hash function. Use the endpoint's signing secret as the key, and use the string from the Step 2 as the message. Every Webhook have a different secret key which can be revealed on Webhooks settings page by clicking on the "Key" button next to your Webhooks.

Step 4: Compare signatures

Hex-decode signature from X-Newreleases-Signature and compare it to the computed signature. If a signature matches, compute the difference between the current timestamp and the received UNIX timestamp in X-Newreleases-Timestamp, then decide if the difference is within your tolerance.

This is a complete webhook service example in Go programming language that listens on 8080 TCP port, handles /webhook route and validates the signature. You can build this program and start it with --secret YOUR_SECRET_KEY argument.

package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "flag"
    "io/ioutil"
    "net/http"
)

var addr = flag.String("addr", ":8080", "")
var secret = flag.String("secret", "", "")

func main() {
    flag.Parse()

    http.HandleFunc("/webhook", func(w http.ResponseWriter, r *http.Request) {
        // read request body payload
        body, err := ioutil.ReadAll(r.Body)
        if err != nil {
            w.WriteHeader(http.StatusServiceUnavailable)
            return
        }

        // prepare hash function
        h := hmac.New(sha256.New, []byte(*secret))
        // concatenate timestamp from the header
        h.Write([]byte(r.Header.Get("X-NewReleases-Timestamp")))
        h.Write([]byte("."))
        h.Write(body)
        // compute the signature
        computedSig := h.Sum(nil)

        // decode the signature that needs to be validated
        sig := r.Header.Get("X-NewReleases-Signature")
        receivedSig, err := hex.DecodeString(sig)
        if err != nil {
            w.WriteHeader(http.StatusServiceUnavailable)
            return
        }

        // compare signatures
        valid := hmac.Equal(receivedSig, computedSig)
        if !valid {
            w.WriteHeader(http.StatusBadRequest)
            return
        }

        // do something with request body payload
        // with your own code

        w.WriteHeader(http.StatusOK)
    })

    http.ListenAndServe(*addr, nil)
}

Custom HTTP headers

It is a good practice to protect your endpoints with some sort of API keys or tokens. You can add multiple custom HTTP headers that will be included in every HTTP request.

Responding to a webhook

To acknowledge receipt of a webhook, your endpoint should return a 2xx HTTP status code. All response codes outside this range, including 3xx codes, will indicate that you did not receive the webhook and will be treated as a failure. Any other information returned in the request headers or request body will be ignored.

Receiving webhooks with an HTTPS server

If you use an HTTPS URL for your webhook endpoint, NewReleases will validate that the connection to your server is secure before sending notification. For this to work, your server must be correctly configured to support HTTPS with a valid server certificate.

Retrying on errors

We will retry webhook requests if your service does not respond with HTTP status 2xx or there is network error with an exponential back off or as soon as there is another project release version.

Test your Webhook

Logged in users have a web form to test webhooks with custom data.