Using Webhooks

Freckle is now Noko! Learn how to migrate your apps here

In Beta!

Webhooks and Broadcasts are in beta while we make sure they're rock solid. The specs are finalized though, so they're safe to add to your integration!

How do Webhooks work?

Webhooks allow your application or integration to be notified of specific events in your Noko account. You can use this to automatically update project estimates, generate summary reports for the time logged every day, integrate your Noko invoices with your bookkeeping software; the possibilities are endless!

Rather than polling for new data or changes, you can subscribe to specific events, and we’ll notify you as soon as they happen!

Once a Webhook has been created, we’ll send POST requests for the events that you’ve subscribed to for that webhook.

How do I create a Webhook?

To create a webhook, you’ll need:

Which type of setup should I choose?

Webhooks Endpoint (Strongly recommended)
My application will be running in a production environment, I’m writing an integration for Noko in my project, or I want to automate setup.
Creating a webhook from the Webapp
My application is a script or for internal use only.

Creating a Webhook from the API

In order to create a Webhook from the API, you’ll need to have valid API credentials. Using the API to manage your webhooks allows you automatically set up your integration, without requiring a user to copy/paste any URLs, or configure anything else!

Creating a Webhook from the Webapp

You can create a Webhook from the main Noko app by going to the “Webhooks” tab in your “Integrations & Connected Apps” section.

How are Webhooks different than the API?

Webhooks are a way to be notified of changes in your Noko account, while the API is a way to access and interact with your Noko account.

When a Webhook is notified of an event, it will receive an object that matches the way the resource is given in the API. This is so you can reuse the same code between your Webhooks & API actions.

Oftentimes, an integration will use both Webhooks & the API to connect with Noko.

Example: Project Management Tool

Let’s say you have a project management tool that integrates with your Noko account.

Pinging your Webhook

When your Webhook is created (either through the Webapp or from the API), we send a webhook.ping event, so you can verify that your webhook is receiving data from Noko.

You can also manually trigger a ping at any time, either from the Webapp (if it’s a standalone webhook), or using the Ping action in the Webhook Endpoint for API Webhooks.

A Ping event has the following structure:

Content-Type: application/json
X-Noko-EventCategory: webhook
X-Noko-Delivery: 6578e997-d144-46fb-a67d-07c886d1a7a1
X-Noko-Signature: 97edbb33123042fb0df0f78eef173123d50b095b769f419a601fbdf40918b8fe
User-Agent: Noko-Webhooks
{
  "payload_id": "6578e997-d144-46fb-a67d-07c886d1a7a1",
  "created_at": "2020-07-29T15:19:28Z",
  "type": "webhook.ping",
  "object": {
  },
  "webhook": {
    "id": 123456,
    "name": "Da Best Noko Webhook"
  }
}

What does a Webhook payload look like?

A Webhook payload has the following structure:

POST http://dabestnokoapp.com/webhooks/entry_events
Content-Type: application/json
X-Noko-EventCategory: entry
X-Noko-Delivery: 050db47d-20f3-4479-86c3-e7a237f670e5
X-Noko-Signature: 97edbb33123042fb0df0f78eef173123d50b095b769f419a601fbdf40918b8fe
User-Agent: Noko-Webhooks
{
  "webhook": {
    "id": 123456,
    "name": "Da Best Noko Webhook"
  },
  "type": "entry.updated",
  "created_at": "2012-01-09T08:33:29Z",
  "changes": {
    "minutes": [
      30,
      60
    ],
    "invoiced_at": [
      null,
      "2012-01-10T08:33:29Z"
    ],
    "invoice": [
      null,
      {
        "id": 12345678,
        "reference": "AA001",
        "invoice_date": "2013-07-09",
        "state": "unpaid",
        "total_amount": 189.33,
        "url": "https://api.nokotime.com/v2/invoices/12345678"
      }
    ]
  },
  "object": {
    "id": 1,
    "date": "2012-01-09",
    "user": {
      "id": 5538,
      "email": "john.test@test.com",
      "first_name": "John",
      "last_name": "Test",
      "profile_image_url": "https://api.nokotime.com/images/avatars/0000/0001/avatar.jpg",
      "url": "https://api.nokotime.com/v2/users/5538"
    },
    "billable": true,
    "minutes": 60,
    "description": "noko",
    "project": {
      "id": 37396,
      "name": "Gear GmbH",
      "billing_increment": 10,
      "enabled": true,
      "billable": true,
      "color": "#ff9898",
      "url": "https://api.nokotime.com/v2/projects/37396"
    },
    "tags": [
      {
        "id": 249397,
        "name": "noko",
        "billable": true,
        "formatted_name": "#noko",
        "url": "https://api.nokotime.com/v2/tags/249397"
      }
    ],
    "source_url": "http://someapp.com/special/url/",
    "invoiced_at": "2012-01-10T08:33:29Z",
    "invoice": {
      "id": 12345678,
      "reference": "AA001",
      "invoice_date": "2013-07-09",
      "state": "unpaid",
      "total_amount": 189.33,
      "url": "https://api.nokotime.com/v2/invoices/12345678"
    },
    "import": {
      "id": 8910,
      "url": "https://api.nokotime.com/v2/imports/8910"
    },
    "approved_at": "2012-01-10T08:33:29Z",
    "approved_by": {
      "id": 5538,
      "email": "john.test@test.com",
      "first_name": "John",
      "last_name": "Test",
      "profile_image_url": "https://api.nokotime.com/images/avatars/0000/0001/avatar.jpg",
      "url": "https://api.nokotime.com/v2/users/5538"
    },
    "url": "https://api.nokotime.com/v2/entries/1711626",
    "invoiced_outside_of_noko_url": "https://api.nokotime.com/v2/entries/1711626/marked_as_invoiced",
    "approved_url": "https://api.nokotime.com/v2/entries/1711626/approved",
    "unapproved_url": "https://api.nokotime.com/v2/entries/1711626/unapproved",
    "created_at": "2012-01-09T08:33:29Z",
    "updated_at": "2012-01-09T08:33:29Z"
  }
}

Verifying a Webhook payload

A secret key is automatically generated when a webhook is created, make sure you store this signature when you create your webhook! (but you can always re-roll the signature if you need to). We use this secret to generate a signature for each webhook payload, so you can verify that the request came from Noko. This signature is stored in the X-Noko-Signature request header.

To verify the signature:

  1. Retrieve the secret value that you stored
  2. Use a SHA 256 HMAC hexdigest to compute the hash, using the secret as the key.
  3. Compare your generated signature with the one in X-Noko-Signature.

Make sure to use a secure comparison method, like Rack::Utils.secure_compare

Webhook failures and retries

Each webhook sends its payloads serially, and will not send future payloads if a payload fails. We wait until the webhook responds with a successful status code before sending the next payload to help prevent state bugs and simplify the bugfixing process on your end. We want any bugs to be as easy and straightforward to fix as possible, and consistent, serialized results help with that.

We retry failed payloads for up to 3 days, using an exponential backoff algorithm to space out the retries. Because each Webhook sends its payloads serially, a webhook will stop receiving events if it’s failed to successfully process a payload after 3 days. You can manually retry a failing payload from the Webapp (if it’s a standalone Webhook) or using the Retry action in the Webhook Endpoint.