---
updatedAt: 2026-05-27T11:57:12.000Z
agentTools:
  projectIndex: https://developers.opentrack.co/llms.txt
---

# Register a Webhook

OpenTrack offers the ability for developers to subscribe to various events that occur in the container lifecycle. When these events occur, we will ping the server defined at the configured webhook URL with data relevant to the event.

In this request, pass in your desired Webhook URL and the events you would like to consume.

If no events are provided, the webhook will include all event types.

See <a href="/docs/webhooks" target="_blank">Webhooks Overview</a> for the list of possible event types to consume.

The API will enforce unique webhook URLs in your account. It will return a `VALIDATION_ERROR` if an attempt is made to register a webhook with a URL that is already registered.

### Using A Secret For Added Security

Optionally, you can specify a `secret` in the registration request, which we will use to identify webhook requests from OpenTrack. (See <a href="#validating-webhooks">Validating Webhooks</a>)

### Receiving Webhooks

When these events occur, we will send a `POST` request to your webhook URL. You can expect these events to have a latency of up to 1 minute of the actual event taking place.


If our `POST` request to your endpoint fails (meaning we receive a 4xx or 5xx status code in response), then we will retry the same `POST` request, no more than 30 minutes later, and keep repeating every 30 minutes until:
- We receive a 2xx response from your server.
- We have attempted to reach your server with this webhook event 5 times.

The webhook payload will look like the following:

```json
{
  "data": {...},
  "changes":
  {
    "status":
    { "previous": "DISCHARGED", "current": "AVAILABLE" }
  },
  "deliveryAttempt": 1,
  "pendingRetries": 4,
  "event": "container.status.updated",
  "sentAt": "2019-07-19T17:00:00.654Z"
}
```

The contents of data vary depending on the webhook event type. Take a look at the Webhooks section of the docs for more details.

### Validating Webhooks

In the webhook event request, we will also send a `X-OpenTrack-Signature` header which can be used to verify that this webhook event is indeed coming from OpenTrack.

To validate, encrypt the incoming webhook payload with your webhook config secret key. Check that this generated signature matches the signature in X-OpenTrack-Signature header.
For example, in Javascript:

```javascript
const crypto = require("crypto");
const hmac = crypto.createHmac("sha256", secret);
const signature = hmac.update(JSON.stringify(webhookPayload)).digest("hex");
```

# OpenAPI definition

````json
{
  "openapi": "3.0.0",
  "servers": [
    {
      "description": "Production",
      "url": "https://api.opentrack.co"
    }
  ],
  "tags": [
    {
      "name": "/webhooks",
      "description": "Manage webhooks to receive container updates."
    }
  ],
  "info": {
    "version": "v1",
    "title": "OpenTrack API",
    "contact": {
      "email": "support@opentrack.co"
    },
    "x-logo": {
      "url": "https://s3-us-west-1.amazonaws.com/opentrack.co/images/opentrack_logo_dark.png",
      "altText": "OpenTrack Logo"
    }
  },
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "paths": {
    "/v1/webhooks": {
      "post": {
        "summary": "Register a Webhook",
        "description": "OpenTrack offers the ability for developers to subscribe to various events that occur in the container lifecycle. When these events occur, we will ping the server defined at the configured webhook URL with data relevant to the event.\n\nIn this request, pass in your desired Webhook URL and the events you would like to consume.\n\nIf no events are provided, the webhook will include all event types.\n\nSee <a href=\"/docs/webhooks\" target=\"_blank\">Webhooks Overview</a> for the list of possible event types to consume.\n\nThe API will enforce unique webhook URLs in your account. It will return a `VALIDATION_ERROR` if an attempt is made to register a webhook with a URL that is already registered.\n\n### Using A Secret For Added Security\n\nOptionally, you can specify a `secret` in the registration request, which we will use to identify webhook requests from OpenTrack. (See <a href=\"#validating-webhooks\">Validating Webhooks</a>)\n\n### Receiving Webhooks\n\nWhen these events occur, we will send a `POST` request to your webhook URL. You can expect these events to have a latency of up to 1 minute of the actual event taking place.\n\n\nIf our `POST` request to your endpoint fails (meaning we receive a 4xx or 5xx status code in response), then we will retry the same `POST` request, no more than 30 minutes later, and keep repeating every 30 minutes until:\n- We receive a 2xx response from your server.\n- We have attempted to reach your server with this webhook event 5 times.\n\nThe webhook payload will look like the following:\n\n```json\n{\n  \"data\": {...},\n  \"changes\":\n  {\n    \"status\":\n    { \"previous\": \"DISCHARGED\", \"current\": \"AVAILABLE\" }\n  },\n  \"deliveryAttempt\": 1,\n  \"pendingRetries\": 4,\n  \"event\": \"container.status.updated\",\n  \"sentAt\": \"2019-07-19T17:00:00.654Z\"\n}\n```\n\nThe contents of data vary depending on the webhook event type. Take a look at the Webhooks section of the docs for more details.\n\n### Validating Webhooks\n\nIn the webhook event request, we will also send a `X-OpenTrack-Signature` header which can be used to verify that this webhook event is indeed coming from OpenTrack.\n\nTo validate, encrypt the incoming webhook payload with your webhook config secret key. Check that this generated signature matches the signature in X-OpenTrack-Signature header.\nFor example, in Javascript:\n\n```javascript\nconst crypto = require(\"crypto\");\nconst hmac = crypto.createHmac(\"sha256\", secret);\nconst signature = hmac.update(JSON.stringify(webhookPayload)).digest(\"hex\");\n```",
        "operationId": "registerWebhook",
        "tags": [
          "/webhooks"
        ],
        "requestBody": {
          "description": "Webhook Registration",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookRegistrationRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook Registration Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookRegistrationSuccess"
                }
              }
            }
          },
          "400": {
            "description": "Webhook Registration Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Usage Error - From Rate Limitation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Server Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-internal": false
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "name": "Opentrack-API-Key",
        "in": "header"
      }
    },
    "schemas": {
      "WebhookRegistrationRequest": {
        "anyOf": [
          {
            "required": [
              "url"
            ]
          },
          {
            "required": [
              "events"
            ]
          },
          {
            "required": [
              "secret"
            ]
          },
          {
            "required": [
              "name"
            ]
          },
          {
            "required": [
              "callbackHeaders"
            ]
          }
        ],
        "properties": {
          "url": {
            "type": "string",
            "example": "https://exceptions.acme.com/webhooks"
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Event"
            }
          },
          "secret": {
            "type": "string",
            "example": "78ae6f0cd191d25147e252dc54768238"
          },
          "name": {
            "type": "string",
            "example": "acme-exceptions-endpoint"
          },
          "callbackHeaders": {
            "type": "object",
            "example": {
              "Authorization": "Bearer d74e-48d2-83dd-189fbfa68b79"
            }
          }
        }
      },
      "WebhookRegistrationSuccess": {
        "properties": {
          "id": {
            "type": "string",
            "example": "5101e125-70da-4f27-9ea6-e401f8e153bd"
          },
          "url": {
            "type": "string",
            "example": "https://exceptions.acme.com/webhooks"
          },
          "name": {
            "type": "string",
            "example": "acme-exceptions-endpoint"
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Event"
            }
          },
          "callbackHeaders": {
            "type": "object",
            "example": {
              "Authorization": "Bearer d74e-48d2-83dd-189fbfa68b79"
            }
          }
        }
      },
      "Event": {
        "type": "string",
        "enum": [
          "container.status.updated",
          "container.history.updated",
          "container.itinerary.updated",
          "container.location.updated",
          "container.holds.updated",
          "container.demurrage.updated",
          "customs.entry.status.updated"
        ],
        "example": "container.status.updated"
      },
      "Error": {
        "required": [
          "code",
          "message"
        ],
        "properties": {
          "code": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        }
      }
    }
  }
}
````