Notifications API

Subscribe to real-time vessel events via webhooks or WebSocket. Get notified instantly when vessels arrive at ports, change course, enter geofences, or update their ETA -- without polling the API.

Overview

The Notifications API lets you create event-driven subscriptions for the vessels you care about. Instead of repeatedly polling endpoints, you define a notification configuration specifying which vessels to watch, which event types to listen for, and where to deliver events. VesselAPI then pushes matching events to your webhook URL or WebSocket connection in real time.

This is ideal for building alerting systems, operational dashboards, supply chain triggers, and any workflow that needs to react immediately to changes in vessel activity.

Subscription Note: The Notifications API is available on paid plans (Basic, Starter, and Pro). View pricing for details.

Quick Start

1

Get your API key

Sign up at vesselapi.com/pricing and grab your Bearer token from the dashboard.

2

Create a notification configuration

POST to /notifications with the vessels to watch, event types, and your webhook URL.

3

Receive events

VesselAPI pushes JSON event envelopes to your webhook. Verify signatures, process events, and respond with a 2xx status.

Event Types

Events are organized into four categories. Subscribe to individual event types or all events in a category.

Category Event Type Description
Port Events port.arrival Vessel has entered a port area
port.departure Vessel has left a port area
ETA / Voyage Changes eta.destination_changed Vessel has changed its reported destination
eta.eta_changed ETA to destination has shifted beyond the configured threshold
eta.draught_changed Vessel draught reading has changed (loading/unloading indicator)
Position Changes position.nav_status_changed AIS navigational status has changed (e.g., underway to anchored)
position.speed_changed Speed over ground changed beyond the configured threshold
position.update Generic — fires on every new AIS position report received for the vessel, regardless of whether the position actually changed. Use this for continuous tracking or heartbeat monitoring.
position.position_changed Specific — fires only when the vessel's actual geographic coordinates have changed. Filters out duplicate or stationary position reports, so you only get notified when the vessel moves.
Geofence position.geofence_enter Vessel has entered a user-defined geofence area
position.geofence_exit Vessel has left a user-defined geofence area

position.update vs position.position_changed

These two event types serve different use cases. position.update is a generic event that fires on every AIS position report received — even if the vessel hasn't moved. This is useful for heartbeat monitoring or building a complete position timeline. position.position_changed is a specific event that only fires when the vessel's actual geographic coordinates change, filtering out duplicate or stationary reports. Use this when you only care about actual movement.

Delivery Methods

Webhooks

Webhooks are the primary delivery method. When an event matches your notification configuration, VesselAPI sends an HTTP POST request to your configured webhookUrl with the event payload as JSON.

  • Your endpoint must respond with a 2xx status within 10 seconds.
  • Failed deliveries are retried up to 3 times with exponential backoff (1s, 2s, 4s).
  • After all retries are exhausted, the event is dropped.

HMAC Signature Verification

Every webhook request includes an X-Signature-256 header containing an HMAC-SHA256 digest of the request body, signed with your webhookSecret. Always verify this signature to confirm events originate from VesselAPI.

import hmac
import hashlib

def verify_signature(payload_body: bytes, secret: str, signature: str) -> bool:
    expected = hmac.new(
        secret.encode("utf-8"),
        payload_body,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)

WebSocket

For low-latency or real-time dashboard use cases, you can enable WebSocket delivery by setting websocket: true in your notification configuration. WebSocket can be used alongside or instead of webhooks.

Connection

Connect to the WebSocket endpoint with your notification ID:

wss://api.vesselapi.com/v1/ws?notification_id=YOUR_NOTIFICATION_ID

Authentication is done via the Authorization header during the HTTP upgrade request, using the same Bearer token as the REST API.

Detail Value
Message format JSON text frames — same EventEnvelope structure as webhooks
Keepalive Server sends ping every 30 seconds. Respond with pong within 10 seconds or the connection closes.
Connection limit One connection per notification. Opening a new connection for the same notification replaces the previous one.
Reconnection Use exponential backoff. Events during disconnection are not replayed.

Browser note: The browser WebSocket API does not support custom headers. For browser clients, consider proxying through your backend. For server-side clients, use a library that supports headers (e.g., ws for Node.js, websockets for Python).

WebSocket Client (Node.js)

import WebSocket from 'ws';

const ws = new WebSocket(
  'wss://api.vesselapi.com/v1/ws?notification_id=YOUR_NOTIFICATION_ID',
  { headers: { Authorization: 'Bearer YOUR_API_KEY' } }
);

ws.on('open', () => console.log('Connected to event stream'));

ws.on('message', (data) => {
  const envelope = JSON.parse(data);
  const event = envelope.event;
  console.log(`[${event.type}] ${event.vessel.vesselName}`, event.data);
});

ws.on('close', (code, reason) => {
  console.log(`Disconnected: ${code} ${reason}`);
  // Reconnect with exponential backoff
});

ws.on('error', (err) => console.error('WebSocket error:', err));

WebSocket Client (Python)

import asyncio
import json
import websockets

async def listen():
    uri = "wss://api.vesselapi.com/v1/ws?notification_id=YOUR_NOTIFICATION_ID"
    headers = {"Authorization": "Bearer YOUR_API_KEY"}

    async with websockets.connect(uri, additional_headers=headers) as ws:
        print("Connected to event stream")
        async for message in ws:
            envelope = json.loads(message)
            event = envelope["event"]
            print(f"[{event['type']}] {event['vessel']['vesselName']}")

asyncio.run(listen())

Notification Configuration

A notification configuration defines what to watch and where to deliver events. The following fields are available when creating or updating a configuration.

Field Type Required Description
name string Yes Human-readable label for this configuration
imos integer[] * List of IMO numbers to watch (max 100 combined with mmsis)
mmsis integer[] * List of MMSI numbers to watch (max 100 combined with imos)
eventTypes string[] Yes Event types to subscribe to (see table above)
webhookUrl string ** HTTPS URL to receive event payloads
webhookSecret string Conditional HMAC-SHA256 secret for signing webhook payloads. Required when webhookUrl is set.
websocket boolean No Enable WebSocket delivery (default: false)
geofence object No Bounding box defining a custom geofence area (lonLeft, lonRight, latBottom, latTop)
speedThresholdKnots number No Minimum speed change (in knots) to trigger position.speed_changed
etaShiftThresholdMinutes number No Minimum ETA shift (in minutes) to trigger eta.eta_changed

* At least one of imos or mmsis is required. ** At least one delivery method (webhookUrl or websocket: true) is required.

Configuration Examples

The difference between delivery channels is simply which fields you set. Use webhookUrl + webhookSecret for webhook delivery, websocket: true for WebSocket delivery, or set both on the same notification to receive events on both channels simultaneously.

Webhook Only

curl -X POST "https://api.vesselapi.com/v1/notifications" \
     -H "Authorization: Bearer YOUR_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{
       "name": "Fleet alerts",
       "imos": [9321483, 9472440],
       "webhookUrl": "https://example.com/webhook",
       "webhookSecret": "my-hmac-secret",
       "eventTypes": ["port.arrival", "port.departure", "position.update"]
     }'

WebSocket Only

curl -X POST "https://api.vesselapi.com/v1/notifications" \
     -H "Authorization: Bearer YOUR_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{
       "name": "Live tracking",
       "imos": [9321483, 9472440],
       "websocket": true,
       "eventTypes": ["position.position_changed"]
     }'

Then connect to the WebSocket endpoint with the returned notification ID:

wss://api.vesselapi.com/v1/ws?notification_id=<id>
# With header: Authorization: Bearer YOUR_API_KEY

API Quota: Every delivered event counts as 1 API call against your monthly quota, regardless of delivery channel. If both webhook and WebSocket are enabled on the same notification, the same event delivered to both channels still counts as 1 call, not 2.

API Endpoints

POST /notifications

Create a new notification configuration.

GET /notifications

List all notification configurations for your account.

GET /notifications/{id}

Retrieve a single notification configuration by ID.

PUT /notifications/{id}

Update an existing notification configuration.

DELETE /notifications/{id}

Delete a notification configuration.

POST /notifications/{id}/test

Send a test event to verify your webhook or WebSocket is receiving events correctly.

Authentication: All endpoints require a Bearer token in the Authorization header, the same API key used across the VesselAPI.

Event Payload

Every event is delivered as a JSON envelope containing the event type, vessel information, a timestamp, and typed data specific to the event. Here is an example port.arrival event:

{
  "object": "event",
  "event": {
    "id": "94ff8b0d-08d8-466c-b37a-c024117b8880",
    "type": "port.arrival",
    "timestamp": "2026-03-27T08:14:32Z",
    "detectedAt": "2026-03-27T08:15:00Z",
    "vessel": {
      "imo": 9811000,
      "mmsi": 353136000,
      "vesselName": "EVER GIVEN"
    },
    "data": {
      "portEvent": {
        "event": "Arrival",
        "timestamp": "2026-03-27T08:14:32Z",
        "vessel": { "name": "EVER GIVEN", "imo": 9811000, "mmsi": 353136000 },
        "port": { "name": "Rotterdam", "country": "Netherlands", "unlo_code": "NLRTM" }
      },
      "portCall": {}
    },
    "notificationId": "550e8400-e29b-41d4-a716-446655440000"
  }
}
Field Description
object Always "event" (envelope discriminator)
event.id Unique event identifier (idempotency key)
event.type One of the event type strings listed above
event.timestamp ISO 8601 UTC timestamp when the event occurred
event.detectedAt ISO 8601 UTC timestamp when VesselAPI detected the event
event.vessel Object with imo, mmsi, and vesselName
event.data Event-specific payload (port info, position, ETA details, etc.)
event.notificationId ID of the notification configuration that matched this event

Code Examples

Create a Notification (cURL)

curl -X POST "https://api.vesselapi.com/v1/notifications" \
     -H "Authorization: Bearer YOUR_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{
       "name": "Ever Given Port Alerts",
       "imos": ["9811000"],
       "eventTypes": ["port.arrival", "port.departure"],
       "webhookUrl": "https://your-app.com/webhooks/vessel-events",
       "webhookSecret": "whsec_your_secret_key"
     }'

Create a Notification (TypeScript SDK)

import { VesselAPI } from "@vesselapi/sdk";

const vessel = new VesselAPI({ apiKey: "YOUR_API_KEY" });

const notification = await vessel.notifications.create({
  name: "Ever Given Port Alerts",
  imos: ["9811000"],
  eventTypes: ["port.arrival", "port.departure"],
  webhookUrl: "https://your-app.com/webhooks/vessel-events",
  webhookSecret: "whsec_your_secret_key",
});

console.log(`Created notification: ${notification.id}`);

Create a Notification (Python SDK)

from vesselapi import VesselAPI

client = VesselAPI(api_key="YOUR_API_KEY")

notification = client.notifications.create(
    name="Ever Given Port Alerts",
    imos=["9811000"],
    event_types=["port.arrival", "port.departure"],
    webhook_url="https://your-app.com/webhooks/vessel-events",
    webhook_secret="whsec_your_secret_key",
)

print(f"Created notification: {notification.id}")

Handle Incoming Webhook (Python / Flask)

import hmac, hashlib, json
from flask import Flask, request, abort

app = Flask(__name__)
WEBHOOK_SECRET = "whsec_your_secret_key"

@app.route("/webhooks/vessel-events", methods=["POST"])
def handle_event():
    # Verify signature
    signature = request.headers.get("X-Signature-256", "")
    expected = "sha256=" + hmac.new(
        WEBHOOK_SECRET.encode(), request.data, hashlib.sha256
    ).hexdigest()
    if not hmac.compare_digest(expected, signature):
        abort(401)

    envelope = request.json
    event = envelope["event"]
    event_type = event["type"]

    if event_type == "port.arrival":
        port = event["data"]["portEvent"]["port"]["name"]
        vessel = event["vessel"]["vesselName"]
        print(f"{vessel} arrived at {port}")

    return "", 200

Try It in the API Explorer

For full endpoint details, request/response schemas, and live testing, open the interactive API Explorer.

Related Documentation