Webhooks version 1

Introduction

Cyke is the homebrewed delivery order tool of Cargonautes (ex OLVO). In addition to a graphical interface, it can notify external services of delivery changes using webhooks.

Webhooks are custom HTTP callbacks that you define. They are triggered by an event, such as a delivery being updated. When the event occurs, Cyke makes an HTTP request to the URL configured for the webhook.

The action to take may be anything. For example, you can use webhooks to:

  • Update the delivery status in your own inventory system;
  • Save the delivery documents (such as the delivery picture);
  • Send a Slack notification to your team, or to your customer;
  • Connect the event to a Zapier action.

The webhooks come in addition to our API, documented here.

Feature requests are very welcome, feel free to write to cyke@cargonautes.fr for that.

Configuration

Configure a webhook in Cyke

Webhooks are configured per client. To create a new webhook for a client:

  1. Sign-in to Cyke with your client user account.
  2. Click on Account menu ▸ Manage my company, then scroll to the bottom and click the Create a webhook button.
  3. In URL, enter the URL of the webhook endpoint. The URL must be HTTPS with a valid certificate (to ensure confidentiality), and percent-encoded if it contains one or more special characters.
  4. In Secret, enter a secret string of your choice; you can later use it to validate payloads.
  5. Click on Create the webhook.
  6. Click on Test webhook to send a test event, and make your webhook active.

To start receiving events, your endpoint needs to successfully respond to a test event. As soon as a test event receives a successful response (i.e. an HTTP status in the 200 range), the webhook will be marked as “Active”, and it will start sending events.

Webhook statuses

A webhook can have different statuses:

  • Unverified: the webhook is pending validation, and doesn’t send production events yet. To verify the webhook, send a test event, and ensure the HTTP response status is in the 200 range.
  • Active: the webhook is correctly configured, and sends events to your endpoint.
  • Disabled: your endpoint has too many HTTP errors, and has been disabled. Please fix your endpoint, then contact Cyke’s customer support for how to re-enable it.

Configure your webhook receiver endpoint

Webhook receivers should be fast and stable. Slow and unstable receivers may be disabled temporarily to ensure system reliability. If you are writing your own endpoint (web server) to receive Cyke webhooks, keep in mind the following:

  • Your endpoint should send its HTTP response as fast as possible. You should aim for sub-second response times in all circumstances. If the response takes longer than the default timeout, Cyke assumes the hook failed, which can lead to retries and potentially cause duplicate events.
  • Your endpoint should ALWAYS return a valid HTTP response, with a status code in the 200 range. If not, Cyke assumes the hook failed and retries it. Most HTTP libraries take care of the response for you automatically, but if you are writing a low-level hook, this is important to remember.

Best practices for a webhook receiver:

  • Prefer to return 200 or 201 status responses. Status code in the 400 or 500 range will cause Cyke to attempt to deliver the webhook again later.
  • Your service should be idempotent. In some circumstances (including timeouts), the same event may be sent twice. Be prepared to handle duplicate events. You can reduce the chances of this by ensuring that your endpoint is reliably fast and stable.
  • Keep response payloads as short as possible. Empty responses are fine. Cyke does not examine the response body.

Webhook events delivery

Webhooks events expect a HTTP response status in the 200 range. If case of another status code, or if the requests time outs, the event is marked as failing the delivery, and retried later.

Events are retried with an exponentially-increasing delay: a few seconds later, then more, then a minute, etc. Events are retried for a maximum of three days, then are marked as definitely failed, and definitely dropped.

When an error occurs while sending an event, the error message is saved in the event. You can see delivery error messages for the latest 20 events in the webhook configuration page.

Validate payloads by using a secret token

You can specify a secret token to validate received payloads. The token is sent with the hook request in the X-Cyke-Token HTTP header. Your webhook endpoint can check the token to verify that the request is legitimate.

Supported events

For now, the only events sent are when the status of a delivery changes.

Delivery events

Delivery events are trigerred when the status of a delivery in Cyke’s system changes. This includes:

  • When a new delivery is created,
  • When the packages of a delivery are picked-up,
  • When a delivery is completed, cancelled or failed.

The payload sent has the same format than an API request on the Delivery endpoint.

Here’s an example of a payload sent when the status of a delivery changes:

{
    "event_id": 17,
    "event_type": "delivery_delivered",
    "payload": {
        "delivery": {
            "id": 193386,
            "pickup": {
                "notes": "",
                "place": {
                    "city": "Paris",
                    "address": "109 rue du faubourg St-Antoine",
                    "postal_code": "75009",
                    "company_name": "Tout schuss",
                    "recipient_name": "Hugo",
                    "recipient_phone": "+33 6 25 24 63 06 ",
                    "address_instructions": "Restaurant sur rue"
                },
                "completed_at": "2022-07-07T18:00:16.620+02:00",
                "tracking_url": "http://cyke.io/t/4169028f",
                "failure_reason": null,
                "slot_ending_at": "2022-07-07T20:30:00.000+02:00",
                "slot_starting_at": "2022-07-07T18:30:00.000+02:00",
                "completion_pictures": [
                    {
                        "url": "http://cyke.io/rails/active_storage/blobs/redirect/eyJfcmFpjdnzzWVzc2FnZSI6IkJBaHBBOThtQXc9PSIsImV4cCI6bnVsbCwicHVyIjoiYmxvYl9pZCJ9fQ==--2967cc1a902219b8af9cfded2c5d69df2934259f/photo.jpg",
                        "accepted_by": null
                    }
                ],
                "completion_signature": null
            },
            "status": "delivered",
            "dropoff": {
                "notes": "",
                "place": {
                    "city": "Clichy",
                    "address": "12 Rue Le Guin",
                    "postal_code": "92110",
                    "company_name": "Le baromètre",
                    "recipient_name": "Aïcha",
                    "recipient_phone": "+33 7 60 16 92 88",
                    "address_instructions": "Code 26A48"
                },
                "completed_at": "2022-07-07T18:00:43.658+02:00",
                "tracking_url": "http://cyke.io:3000/t/b1d55bac",
                "failure_reason": null,
                "slot_ending_at": "2022-07-07T20:30:00.000+02:00",
                "slot_starting_at": "2022-07-07T18:30:00.000+02:00",
                "completion_pictures": [
                    {
                        "url": "http://cyke.io/rails/active_storage/blobs/redirect/eyJfcmFpbsjnnz3Vzc2FnZSI6IkJBaHBBK0FtQXc9PSIsImV4cCI6bnVsbCwicHVyIjoiYmxvYl9pZCJ9fQ==--2c29750bf34d8674b11a7d7d331163390a5c48f9/photo.jpg",
                        "accepted_by": null
                    }
                ],
                "completion_signature": null
            },
            "comments": null,
            "packages": [
                {
                    "type": "Cargo full - < 300L / < 80kg",
                    "amount": 1
                }
            ],
            "direction": "outbound",
            "created_at": "2022-07-07T17:22:00.619+02:00",
            "price_cents": 10560,
            "redelivery_id": null,
            "complete_after": "2022-07-07T18:30:00.000+02:00",
            "complete_before": "2022-07-07T20:30:00.000+02:00",
            "original_delivery_id": null,
            "bring_back_containers": false,
            "client_order_reference": ""
        }
    }
}