{
    "swagger": "2.0",
    "info": {
        "description": "Real-time vessel event notifications via webhooks and WebSocket. Subscribe to vessel changes including port arrivals/departures, destination changes, ETA shifts, speed/status changes, and geofence events.",
        "title": "Vessel Notifications API",
        "contact": {},
        "version": "1.0"
    },
    "host": "api.vesselapi.com",
    "basePath": "/v1",
    "paths": {
        "/notifications": {
            "get": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "List all notification configurations for the authenticated user",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "Notifications"
                ],
                "summary": "List notifications",
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/NotificationListResponse"
                        }
                    },
                    "401": {
                        "description": "Unauthorized",
                        "schema": {
                            "$ref": "#/definitions/AuthenticationErrorResponse"
                        }
                    },
                    "500": {
                        "description": "Internal Server Error",
                        "schema": {
                            "$ref": "#/definitions/InternalServerErrorResponse"
                        }
                    }
                }
            },
            "post": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Create a new notification to watch vessels and receive events via webhook and/or WebSocket",
                "consumes": [
                    "application/json"
                ],
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "Notifications"
                ],
                "summary": "Create notification",
                "parameters": [
                    {
                        "description": "Notification configuration",
                        "name": "body",
                        "in": "body",
                        "required": true,
                        "schema": {
                            "$ref": "#/definitions/CreateNotificationRequest"
                        }
                    }
                ],
                "responses": {
                    "201": {
                        "description": "Created",
                        "schema": {
                            "$ref": "#/definitions/NotificationResponse"
                        }
                    },
                    "400": {
                        "description": "Bad Request",
                        "schema": {
                            "$ref": "#/definitions/BadRequestErrorResponse"
                        }
                    },
                    "401": {
                        "description": "Unauthorized",
                        "schema": {
                            "$ref": "#/definitions/AuthenticationErrorResponse"
                        }
                    },
                    "429": {
                        "description": "Too Many Requests",
                        "schema": {
                            "$ref": "#/definitions/RateLimitErrorResponse"
                        }
                    },
                    "500": {
                        "description": "Internal Server Error",
                        "schema": {
                            "$ref": "#/definitions/InternalServerErrorResponse"
                        }
                    }
                }
            }
        },
        "/notifications/advanced": {
            "get": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "List all advanced notifications for the authenticated user.",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "AdvancedNotifications"
                ],
                "summary": "List advanced notifications",
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/AdvancedNotificationListResponse"
                        }
                    },
                    "401": {
                        "description": "Unauthorized",
                        "schema": {
                            "$ref": "#/definitions/AuthenticationErrorResponse"
                        }
                    },
                    "500": {
                        "description": "Internal Server Error",
                        "schema": {
                            "$ref": "#/definitions/InternalServerErrorResponse"
                        }
                    }
                }
            },
            "post": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Create an advanced notification with polygon geofence, attribute filters, and optional uncapped vessel matching. Requires the Pro subscription plan. The notification is created with prefillStatus \"pending\" and starts delivering events once prefill completes (prefillStatus \"ready\"); poll GET /notifications/advanced/{name} to track it, or pass skipPrefill=true to start immediately and receive an enter event for every currently-matching vessel. Limits: 50 advanced notifications per account, polygon ring of 4-5000 [lon,lat] points, vessel_list mode up to 10000 vessels (each entry requires an MMSI), up to 20 filter groups of 20 predicates.",
                "consumes": [
                    "application/json"
                ],
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "AdvancedNotifications"
                ],
                "summary": "Create advanced notification",
                "parameters": [
                    {
                        "description": "Advanced notification configuration",
                        "name": "body",
                        "in": "body",
                        "required": true,
                        "schema": {
                            "$ref": "#/definitions/CreateAdvancedNotificationRequest"
                        }
                    }
                ],
                "responses": {
                    "201": {
                        "description": "Created",
                        "schema": {
                            "$ref": "#/definitions/AdvancedNotificationResponse"
                        }
                    },
                    "400": {
                        "description": "Bad Request",
                        "schema": {
                            "$ref": "#/definitions/BadRequestErrorResponse"
                        }
                    },
                    "401": {
                        "description": "Unauthorized",
                        "schema": {
                            "$ref": "#/definitions/AuthenticationErrorResponse"
                        }
                    },
                    "403": {
                        "description": "Subscription plan does not include advanced notifications (Pro required)",
                        "schema": {
                            "$ref": "#/definitions/ForbiddenErrorResponse"
                        }
                    },
                    "409": {
                        "description": "An advanced notification with this name already exists",
                        "schema": {
                            "$ref": "#/definitions/ConflictErrorResponse"
                        }
                    },
                    "429": {
                        "description": "Too Many Requests",
                        "schema": {
                            "$ref": "#/definitions/RateLimitErrorResponse"
                        }
                    },
                    "500": {
                        "description": "Internal Server Error",
                        "schema": {
                            "$ref": "#/definitions/InternalServerErrorResponse"
                        }
                    }
                }
            }
        },
        "/notifications/advanced/{name}": {
            "get": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Get an advanced notification by name.",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "AdvancedNotifications"
                ],
                "summary": "Get advanced notification",
                "parameters": [
                    {
                        "type": "string",
                        "example": "europe_registration",
                        "description": "Notification name",
                        "name": "name",
                        "in": "path",
                        "required": true
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/AdvancedNotificationResponse"
                        }
                    },
                    "401": {
                        "description": "Unauthorized",
                        "schema": {
                            "$ref": "#/definitions/AuthenticationErrorResponse"
                        }
                    },
                    "404": {
                        "description": "Not Found",
                        "schema": {
                            "$ref": "#/definitions/NotFoundErrorResponse"
                        }
                    }
                }
            },
            "put": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Update an advanced notification. Only provided fields are changed. Name and mode cannot be changed. Changing the polygon or filters (or reactivating an inactive notification) resets prefillStatus to \"pending\": event delivery pauses until prefill completes again.",
                "consumes": [
                    "application/json"
                ],
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "AdvancedNotifications"
                ],
                "summary": "Update advanced notification",
                "parameters": [
                    {
                        "type": "string",
                        "description": "Notification name",
                        "name": "name",
                        "in": "path",
                        "required": true
                    },
                    {
                        "description": "Fields to update",
                        "name": "body",
                        "in": "body",
                        "required": true,
                        "schema": {
                            "$ref": "#/definitions/UpdateAdvancedNotificationRequest"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/AdvancedNotificationResponse"
                        }
                    },
                    "400": {
                        "description": "Bad Request",
                        "schema": {
                            "$ref": "#/definitions/BadRequestErrorResponse"
                        }
                    },
                    "401": {
                        "description": "Unauthorized",
                        "schema": {
                            "$ref": "#/definitions/AuthenticationErrorResponse"
                        }
                    },
                    "403": {
                        "description": "Subscription plan does not include advanced notifications (Pro required)",
                        "schema": {
                            "$ref": "#/definitions/ForbiddenErrorResponse"
                        }
                    },
                    "404": {
                        "description": "Not Found",
                        "schema": {
                            "$ref": "#/definitions/NotFoundErrorResponse"
                        }
                    }
                }
            },
            "delete": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Delete an advanced notification and stop all event delivery. State and allowlist are removed via cascade.",
                "tags": [
                    "AdvancedNotifications"
                ],
                "summary": "Delete advanced notification",
                "parameters": [
                    {
                        "type": "string",
                        "description": "Notification name",
                        "name": "name",
                        "in": "path",
                        "required": true
                    }
                ],
                "responses": {
                    "204": {
                        "description": "No Content"
                    },
                    "401": {
                        "description": "Unauthorized",
                        "schema": {
                            "$ref": "#/definitions/AuthenticationErrorResponse"
                        }
                    },
                    "404": {
                        "description": "Not Found",
                        "schema": {
                            "$ref": "#/definitions/NotFoundErrorResponse"
                        }
                    }
                }
            }
        },
        "/notifications/advanced/{name}/test": {
            "post": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Send a test event to verify webhook + websocket delivery for an advanced notification. The notification must be active.",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "AdvancedNotifications"
                ],
                "summary": "Test advanced notification",
                "parameters": [
                    {
                        "type": "string",
                        "description": "Notification name",
                        "name": "name",
                        "in": "path",
                        "required": true
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/TestResponse"
                        }
                    },
                    "401": {
                        "description": "Unauthorized",
                        "schema": {
                            "$ref": "#/definitions/AuthenticationErrorResponse"
                        }
                    },
                    "403": {
                        "description": "Subscription plan does not include advanced notifications (Pro required)",
                        "schema": {
                            "$ref": "#/definitions/ForbiddenErrorResponse"
                        }
                    },
                    "404": {
                        "description": "Not Found",
                        "schema": {
                            "$ref": "#/definitions/NotFoundErrorResponse"
                        }
                    },
                    "409": {
                        "description": "Notification is inactive (code notification_inactive)",
                        "schema": {
                            "$ref": "#/definitions/ConflictErrorResponse"
                        }
                    }
                }
            }
        },
        "/notifications/{id}": {
            "get": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Get a notification configuration by ID",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "Notifications"
                ],
                "summary": "Get notification",
                "parameters": [
                    {
                        "type": "string",
                        "example": "550e8400-e29b-41d4-a716-446655440000",
                        "description": "Notification ID",
                        "name": "id",
                        "in": "path",
                        "required": true
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/NotificationResponse"
                        }
                    },
                    "401": {
                        "description": "Unauthorized",
                        "schema": {
                            "$ref": "#/definitions/AuthenticationErrorResponse"
                        }
                    },
                    "404": {
                        "description": "Not Found",
                        "schema": {
                            "$ref": "#/definitions/NotFoundErrorResponse"
                        }
                    },
                    "500": {
                        "description": "Internal Server Error",
                        "schema": {
                            "$ref": "#/definitions/InternalServerErrorResponse"
                        }
                    }
                }
            },
            "put": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Update a notification configuration. Only provided fields are changed.",
                "consumes": [
                    "application/json"
                ],
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "Notifications"
                ],
                "summary": "Update notification",
                "parameters": [
                    {
                        "type": "string",
                        "description": "Notification ID",
                        "name": "id",
                        "in": "path",
                        "required": true
                    },
                    {
                        "description": "Fields to update",
                        "name": "body",
                        "in": "body",
                        "required": true,
                        "schema": {
                            "$ref": "#/definitions/UpdateNotificationRequest"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/NotificationResponse"
                        }
                    },
                    "400": {
                        "description": "Bad Request",
                        "schema": {
                            "$ref": "#/definitions/BadRequestErrorResponse"
                        }
                    },
                    "401": {
                        "description": "Unauthorized",
                        "schema": {
                            "$ref": "#/definitions/AuthenticationErrorResponse"
                        }
                    },
                    "404": {
                        "description": "Not Found",
                        "schema": {
                            "$ref": "#/definitions/NotFoundErrorResponse"
                        }
                    },
                    "500": {
                        "description": "Internal Server Error",
                        "schema": {
                            "$ref": "#/definitions/InternalServerErrorResponse"
                        }
                    }
                }
            },
            "delete": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Delete a notification configuration and stop all event delivery",
                "tags": [
                    "Notifications"
                ],
                "summary": "Delete notification",
                "parameters": [
                    {
                        "type": "string",
                        "description": "Notification ID",
                        "name": "id",
                        "in": "path",
                        "required": true
                    }
                ],
                "responses": {
                    "204": {
                        "description": "No Content"
                    },
                    "401": {
                        "description": "Unauthorized",
                        "schema": {
                            "$ref": "#/definitions/AuthenticationErrorResponse"
                        }
                    },
                    "404": {
                        "description": "Not Found",
                        "schema": {
                            "$ref": "#/definitions/NotFoundErrorResponse"
                        }
                    },
                    "500": {
                        "description": "Internal Server Error",
                        "schema": {
                            "$ref": "#/definitions/InternalServerErrorResponse"
                        }
                    }
                }
            }
        },
        "/notifications/{id}/test": {
            "post": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Send a test event to verify webhook delivery and see the event payload format. The test event is delivered through all configured channels (webhook and/or WebSocket).",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "Notifications"
                ],
                "summary": "Test notification",
                "parameters": [
                    {
                        "type": "string",
                        "description": "Notification ID",
                        "name": "id",
                        "in": "path",
                        "required": true
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/TestResponse"
                        }
                    },
                    "400": {
                        "description": "Bad Request",
                        "schema": {
                            "$ref": "#/definitions/BadRequestErrorResponse"
                        }
                    },
                    "401": {
                        "description": "Unauthorized",
                        "schema": {
                            "$ref": "#/definitions/AuthenticationErrorResponse"
                        }
                    },
                    "404": {
                        "description": "Not Found",
                        "schema": {
                            "$ref": "#/definitions/NotFoundErrorResponse"
                        }
                    },
                    "500": {
                        "description": "Internal Server Error",
                        "schema": {
                            "$ref": "#/definitions/InternalServerErrorResponse"
                        }
                    }
                }
            }
        },
        "/ws": {
            "get": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Connect via WebSocket to receive real-time notification events. The notification must have websocket=true. Authenticate with the Authorization header on the upgrade request. Events arrive as JSON EventEnvelope text frames. The server pings every 30s; standard WebSocket libraries answer automatically. Server-initiated close codes: 4000 ping timeout (no pong for 40s — keep the read loop responsive and reconnect with backoff), 4001 replaced by a newer connection for this notification (only one connection per notification; the newest wins), 4002 notification deleted, deactivated, or websocket delivery disabled (do not reconnect until it is re-enabled), 1013 connection limit reached (retry later), 1012 server restart on deploy (reconnect immediately). Events emitted while no client is connected are discarded, there is no replay.",
                "tags": [
                    "WebSocket"
                ],
                "summary": "WebSocket event stream",
                "parameters": [
                    {
                        "type": "string",
                        "example": "550e8400-e29b-41d4-a716-446655440000",
                        "description": "Notification ID (must have websocket delivery enabled)",
                        "name": "notification_id",
                        "in": "query",
                        "required": true
                    }
                ],
                "responses": {
                    "101": {
                        "description": "Switching Protocols - WebSocket connection established"
                    },
                    "400": {
                        "description": "Bad Request",
                        "schema": {
                            "$ref": "#/definitions/BadRequestErrorResponse"
                        }
                    },
                    "401": {
                        "description": "Unauthorized",
                        "schema": {
                            "$ref": "#/definitions/AuthenticationErrorResponse"
                        }
                    },
                    "404": {
                        "description": "Not Found",
                        "schema": {
                            "$ref": "#/definitions/NotFoundErrorResponse"
                        }
                    }
                }
            }
        },
        "/ws/advanced": {
            "get": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Connect via WebSocket to receive real-time events from an advanced notification. The notification must have websocket=true, be active (409, code notification_inactive), and have prefillStatus \"ready\" (409, code prefill_pending, with a Retry-After header). Authenticate with the Authorization header on the upgrade request. Events arrive as JSON EventEnvelope text frames. The server pings every 30s; standard WebSocket libraries answer automatically. Server-initiated close codes: 4000 ping timeout (no pong for 40s — keep the read loop responsive and reconnect with backoff), 4001 replaced by a newer connection for this notification (only one connection per notification; the newest wins), 4002 notification deleted, deactivated, or websocket delivery disabled (do not reconnect until it is re-enabled; the close reason says which), 1013 connection limit reached (retry later), 1012 server restart on deploy (reconnect immediately). Events emitted while no client is connected are discarded, there is no replay.",
                "tags": [
                    "WebSocket"
                ],
                "summary": "Advanced WebSocket event stream",
                "parameters": [
                    {
                        "type": "string",
                        "example": "europe_registration",
                        "description": "Advanced notification name (must have websocket delivery enabled)",
                        "name": "name",
                        "in": "query",
                        "required": true
                    }
                ],
                "responses": {
                    "101": {
                        "description": "Switching Protocols - WebSocket connection established"
                    },
                    "400": {
                        "description": "Bad Request",
                        "schema": {
                            "$ref": "#/definitions/BadRequestErrorResponse"
                        }
                    },
                    "401": {
                        "description": "Unauthorized",
                        "schema": {
                            "$ref": "#/definitions/AuthenticationErrorResponse"
                        }
                    },
                    "403": {
                        "description": "Subscription plan does not include advanced notifications (Pro required)",
                        "schema": {
                            "$ref": "#/definitions/ForbiddenErrorResponse"
                        }
                    },
                    "404": {
                        "description": "Not Found",
                        "schema": {
                            "$ref": "#/definitions/NotFoundErrorResponse"
                        }
                    },
                    "409": {
                        "description": "code notification_inactive (re-enable before connecting) or prefill_pending (retry shortly; Retry-After header set)",
                        "schema": {
                            "$ref": "#/definitions/ConflictErrorResponse"
                        }
                    }
                }
            }
        }
    },
    "definitions": {
        "AdvancedMode": {
            "type": "string",
            "enum": [
                "any_vessel",
                "vessel_list"
            ],
            "x-enum-varnames": [
                "AdvancedModeAnyVessel",
                "AdvancedModeVesselList"
            ]
        },
        "AdvancedNotification": {
            "type": "object",
            "properties": {
                "active": {
                    "type": "boolean",
                    "example": true
                },
                "createdAt": {
                    "type": "string",
                    "example": "2026-04-19T12:00:00Z"
                },
                "etaShiftThresholdMinutes": {
                    "description": "ETAShiftThresholdMinutes gates emission of eta.eta_changed events: the\nabsolute delta between two consecutive reported ETA values must meet or\nexceed this threshold. Nil falls back to advanced_poller config default.\nOnly meaningful when eta.eta_changed is listed in EventTypes.",
                    "type": "integer",
                    "example": 120
                },
                "eventTypes": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    },
                    "example": [
                        "position.geofence_enter",
                        "position.geofence_exit"
                    ]
                },
                "filterGroups": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/FilterGroup"
                    }
                },
                "hysteresisMeters": {
                    "type": "integer",
                    "example": 50
                },
                "mode": {
                    "allOf": [
                        {
                            "$ref": "#/definitions/AdvancedMode"
                        }
                    ],
                    "example": "any_vessel"
                },
                "name": {
                    "type": "string",
                    "example": "europe_registration"
                },
                "polygon": {
                    "$ref": "#/definitions/Polygon"
                },
                "prefillCompletedAt": {
                    "type": "string"
                },
                "prefillError": {
                    "type": "string"
                },
                "prefillStartedAt": {
                    "type": "string"
                },
                "prefillStatus": {
                    "description": "Prefill lifecycle — surfaced in responses so callers can tell whether\ntheir notification is live yet. Polygon/filter changes return the\nnotification to \"pending\" while a background runner re-seeds state.",
                    "allOf": [
                        {
                            "$ref": "#/definitions/PrefillStatus"
                        }
                    ],
                    "example": "ready"
                },
                "updatedAt": {
                    "type": "string",
                    "example": "2026-04-19T12:00:00Z"
                },
                "vessels": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/AdvancedVesselRef"
                    }
                },
                "webhookUrl": {
                    "type": "string",
                    "example": "https://example.com/webhook"
                },
                "websocket": {
                    "type": "boolean",
                    "example": false
                }
            }
        },
        "AdvancedNotificationListResponse": {
            "type": "object",
            "properties": {
                "notifications": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/AdvancedNotification"
                    }
                }
            }
        },
        "AdvancedNotificationResponse": {
            "type": "object",
            "properties": {
                "notification": {
                    "$ref": "#/definitions/AdvancedNotification"
                }
            }
        },
        "AdvancedVesselRef": {
            "type": "object",
            "properties": {
                "imo": {
                    "type": "integer",
                    "example": 9321483
                },
                "mmsi": {
                    "type": "integer",
                    "example": 477045900
                }
            }
        },
        "AuthenticationErrorDetail": {
            "type": "object",
            "properties": {
                "code": {
                    "description": "Code is a short string identifier for this error for programmatic handling",
                    "allOf": [
                        {
                            "$ref": "#/definitions/github_com_vesselapi_common_vessel-data-contracts_responses.ErrorCode"
                        }
                    ],
                    "example": "invalid_api_key"
                },
                "message": {
                    "description": "Message is a human-readable message providing more details about the error",
                    "type": "string",
                    "example": "api key is invalid or not found"
                },
                "type": {
                    "description": "Type categorizes the error (always \"authentication_error\" for 401s)",
                    "allOf": [
                        {
                            "$ref": "#/definitions/github_com_vesselapi_common_vessel-data-contracts_responses.ErrorType"
                        }
                    ],
                    "example": "authentication_error"
                }
            }
        },
        "AuthenticationErrorResponse": {
            "type": "object",
            "properties": {
                "error": {
                    "$ref": "#/definitions/AuthenticationErrorDetail"
                }
            }
        },
        "BadRequestErrorDetail": {
            "type": "object",
            "properties": {
                "code": {
                    "description": "Code is a short string identifier for this error for programmatic handling",
                    "allOf": [
                        {
                            "$ref": "#/definitions/github_com_vesselapi_common_vessel-data-contracts_responses.ErrorCode"
                        }
                    ],
                    "example": "invalid_mmsi"
                },
                "doc_url": {
                    "description": "DocURL is a link to documentation for more information",
                    "type": "string",
                    "example": "https://vesselapi.com/docs#invalid_mmsi"
                },
                "message": {
                    "description": "Message is a human-readable message providing more details about the error",
                    "type": "string",
                    "example": "Invalid MMSI: abc123"
                },
                "param": {
                    "description": "Param identifies the parameter that caused the error (if applicable)",
                    "type": "string",
                    "example": "mmsi"
                },
                "type": {
                    "description": "Type categorizes the error (e.g., \"invalid_request_error\")",
                    "allOf": [
                        {
                            "$ref": "#/definitions/github_com_vesselapi_common_vessel-data-contracts_responses.ErrorType"
                        }
                    ],
                    "example": "invalid_request_error"
                }
            }
        },
        "BadRequestErrorResponse": {
            "type": "object",
            "properties": {
                "error": {
                    "$ref": "#/definitions/BadRequestErrorDetail"
                }
            }
        },
        "ConflictErrorDetail": {
            "type": "object",
            "properties": {
                "code": {
                    "allOf": [
                        {
                            "$ref": "#/definitions/ErrorCode"
                        }
                    ],
                    "example": "conflict"
                },
                "message": {
                    "type": "string",
                    "example": "advanced notification with this name already exists"
                },
                "type": {
                    "allOf": [
                        {
                            "$ref": "#/definitions/ErrorType"
                        }
                    ],
                    "example": "conflict_error"
                }
            }
        },
        "ConflictErrorResponse": {
            "type": "object",
            "properties": {
                "error": {
                    "$ref": "#/definitions/ConflictErrorDetail"
                }
            }
        },
        "CreateAdvancedNotificationRequest": {
            "type": "object",
            "properties": {
                "etaShiftThresholdMinutes": {
                    "description": "ETAShiftThresholdMinutes gates eta.eta_changed: 1-1440, default 120.",
                    "type": "integer",
                    "example": 120
                },
                "eventTypes": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    },
                    "example": [
                        "position.geofence_enter",
                        "position.geofence_exit"
                    ]
                },
                "filterGroups": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/FilterGroup"
                    }
                },
                "hysteresisMeters": {
                    "description": "HysteresisMeters is the exit debounce: a vessel must be at least this far\noutside the polygon before a geofence_exit fires. 0-10000, default 50.",
                    "type": "integer",
                    "example": 50
                },
                "mode": {
                    "allOf": [
                        {
                            "$ref": "#/definitions/AdvancedMode"
                        }
                    ],
                    "example": "any_vessel"
                },
                "name": {
                    "description": "Name uniquely identifies the notification per account: 1-64 chars,\nletters, digits, underscore, hyphen, dot, space. Immutable after create.",
                    "type": "string",
                    "example": "europe_registration"
                },
                "polygon": {
                    "$ref": "#/definitions/Polygon"
                },
                "skipPrefill": {
                    "description": "SkipPrefill bypasses the state-seeding phase — the notification goes\nstraight to \"ready\" on create and the first poll tick fires enter\nevents for every vessel currently matching the polygon + filters.\nDefault (nil/false) seeds state so only genuine boundary crossings\nemit enter events. Opt-in only: use when you explicitly want the\ninitial snapshot delivered as events (e.g. bootstrapping a view of\n\"everything here right now\"). Ignored on subsequent polygon/filter\nchanges — those always run a normal prefill because the stale state\nwould otherwise produce phantom enters/exits.",
                    "type": "boolean",
                    "example": false
                },
                "vessels": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/AdvancedVesselRef"
                    }
                },
                "webhookSecret": {
                    "type": "string",
                    "example": "my-secret-key"
                },
                "webhookUrl": {
                    "type": "string",
                    "example": "https://example.com/webhook"
                },
                "websocket": {
                    "type": "boolean",
                    "example": false
                }
            }
        },
        "CreateNotificationRequest": {
            "type": "object",
            "properties": {
                "etaShiftThresholdMinutes": {
                    "description": "ETAShiftThresholdMinutes overrides the global ETA shift threshold (default 120 minutes). Optional.",
                    "type": "integer",
                    "example": 120
                },
                "eventTypes": {
                    "description": "EventTypes filters which events are delivered. Empty means all events.",
                    "type": "array",
                    "items": {
                        "type": "string"
                    },
                    "example": [
                        "port.arrival",
                        "position.update"
                    ]
                },
                "geofence": {
                    "description": "Geofence defines a bounding box for geofence_enter/exit events. Optional.",
                    "allOf": [
                        {
                            "$ref": "#/definitions/Geofence"
                        }
                    ]
                },
                "imos": {
                    "description": "IMOs is a list of IMO numbers to watch (max 100 combined with MMSIs)",
                    "type": "array",
                    "items": {
                        "type": "integer"
                    },
                    "example": [
                        9321483,
                        9472440
                    ]
                },
                "mmsis": {
                    "description": "MMSIs is a list of MMSI numbers to watch (max 100 combined with IMOs)",
                    "type": "array",
                    "items": {
                        "type": "integer"
                    },
                    "example": [
                        477045900
                    ]
                },
                "name": {
                    "description": "Name is a friendly label for this notification",
                    "type": "string",
                    "example": "My fleet alerts"
                },
                "speedThresholdKnots": {
                    "description": "SpeedThresholdKnots overrides the global speed threshold (default 0.5 knots). Optional.",
                    "type": "number",
                    "example": 0.5
                },
                "webhookSecret": {
                    "description": "WebhookSecret is the HMAC-SHA256 shared secret for signing webhook payloads. Required when webhookUrl is set.",
                    "type": "string",
                    "example": "my-secret-key"
                },
                "webhookUrl": {
                    "description": "WebhookURL is the endpoint to POST events to. Required if websocket is false.",
                    "type": "string",
                    "example": "https://example.com/webhook"
                },
                "websocket": {
                    "description": "WebSocket enables WebSocket delivery. At least one of webhookUrl or websocket must be set.",
                    "type": "boolean",
                    "example": false
                }
            }
        },
        "DestinationChange": {
            "type": "object",
            "properties": {
                "current": {
                    "type": "string",
                    "example": "NLRTM"
                },
                "previous": {
                    "type": "string",
                    "example": "DEHAM"
                }
            }
        },
        "DraughtChange": {
            "type": "object",
            "properties": {
                "current": {
                    "type": "number",
                    "example": 14.2
                },
                "previous": {
                    "type": "number",
                    "example": 12.5
                }
            }
        },
        "ETAChange": {
            "type": "object",
            "properties": {
                "currentEta": {
                    "type": "string",
                    "example": "2026-03-28T14:00:00Z"
                },
                "previousEta": {
                    "type": "string",
                    "example": "2026-03-28T08:00:00Z"
                },
                "shiftMinutes": {
                    "type": "integer",
                    "example": 360
                }
            }
        },
        "ErrorCode": {
            "type": "string",
            "enum": [
                "resource_missing",
                "invalid_parameter",
                "invalid_mmsi",
                "invalid_imo",
                "invalid_coordinates",
                "invalid_time_range",
                "bounding_box_too_dense",
                "missing_parameter",
                "invalid_api_key",
                "rate_limit_exceeded",
                "forbidden",
                "conflict",
                "notification_inactive",
                "prefill_pending",
                "insufficient_credits",
                "feature_not_available",
                "internal_error",
                "database_error",
                "service_unavailable"
            ],
            "x-enum-varnames": [
                "ErrorCodeResourceMissing",
                "ErrorCodeInvalidParameter",
                "ErrorCodeInvalidMMSI",
                "ErrorCodeInvalidIMO",
                "ErrorCodeInvalidCoordinates",
                "ErrorCodeInvalidTimeRange",
                "ErrorCodeBoundingBoxTooDense",
                "ErrorCodeMissingParameter",
                "ErrorCodeInvalidAPIKey",
                "ErrorCodeRateLimitExceeded",
                "ErrorCodeForbidden",
                "ErrorCodeConflict",
                "ErrorCodeNotificationInactive",
                "ErrorCodePrefillPending",
                "ErrorCodeInsufficientCredits",
                "ErrorCodeFeatureNotAvailable",
                "ErrorCodeInternalError",
                "ErrorCodeDatabaseError",
                "ErrorCodeServiceUnavailable"
            ]
        },
        "ErrorType": {
            "type": "string",
            "enum": [
                "invalid_request_error",
                "api_error",
                "authentication_error",
                "rate_limit_error",
                "forbidden_error",
                "not_found_error",
                "conflict_error",
                "payment_required_error",
                "service_unavailable_error"
            ],
            "x-enum-varnames": [
                "ErrorTypeInvalidRequest",
                "ErrorTypeAPIError",
                "ErrorTypeAuthenticationError",
                "ErrorTypeRateLimitError",
                "ErrorTypeForbidden",
                "ErrorTypeNotFoundError",
                "ErrorTypeConflict",
                "ErrorTypePaymentRequired",
                "ErrorTypeServiceUnavailable"
            ]
        },
        "Event": {
            "type": "object",
            "properties": {
                "data": {
                    "$ref": "#/definitions/EventData"
                },
                "detectedAt": {
                    "type": "string",
                    "example": "2026-03-27T12:05:00Z"
                },
                "id": {
                    "type": "string",
                    "example": "94ff8b0d-08d8-466c-b37a-c024117b8880"
                },
                "notificationId": {
                    "type": "string",
                    "example": "550e8400-e29b-41d4-a716-446655440000"
                },
                "notificationName": {
                    "description": "NotificationName is populated only for advanced notifications, which\nidentify themselves by a user-visible name rather than an internal UUID.",
                    "type": "string",
                    "example": "europe_registration"
                },
                "timestamp": {
                    "type": "string",
                    "example": "2026-03-27T12:00:00Z"
                },
                "type": {
                    "allOf": [
                        {
                            "$ref": "#/definitions/types.EventType"
                        }
                    ],
                    "example": "position.position_changed"
                },
                "vessel": {
                    "$ref": "#/definitions/EventVessel"
                }
            }
        },
        "EventData": {
            "type": "object",
            "properties": {
                "destinationChange": {
                    "$ref": "#/definitions/DestinationChange"
                },
                "draughtChange": {
                    "$ref": "#/definitions/DraughtChange"
                },
                "etaChange": {
                    "$ref": "#/definitions/ETAChange"
                },
                "geofenceChange": {
                    "$ref": "#/definitions/GeofenceChange"
                },
                "message": {
                    "description": "Test event message (only for type \"test\")",
                    "type": "string",
                    "example": "This is a test event to verify your notification delivery."
                },
                "navStatusChange": {
                    "$ref": "#/definitions/NavStatusChange"
                },
                "portCall": {
                    "$ref": "#/definitions/PortCall"
                },
                "portEvent": {
                    "$ref": "#/definitions/PortEvent"
                },
                "position": {
                    "description": "Contract objects — exactly one populated per event (same shape as the REST API responses).",
                    "allOf": [
                        {
                            "$ref": "#/definitions/VesselPosition"
                        }
                    ]
                },
                "positionChange": {
                    "$ref": "#/definitions/PositionChange"
                },
                "positionUpdate": {
                    "description": "Typed deltas — exactly one populated per event type.",
                    "allOf": [
                        {
                            "$ref": "#/definitions/PositionUpdate"
                        }
                    ]
                },
                "speedChange": {
                    "$ref": "#/definitions/SpeedChange"
                },
                "vesselEta": {
                    "$ref": "#/definitions/VesselETA"
                }
            }
        },
        "EventEnvelope": {
            "type": "object",
            "properties": {
                "event": {
                    "$ref": "#/definitions/Event"
                },
                "object": {
                    "type": "string",
                    "example": "event"
                }
            }
        },
        "EventVessel": {
            "type": "object",
            "properties": {
                "breadth": {
                    "type": "integer",
                    "example": 11
                },
                "country": {
                    "type": "string",
                    "example": "Netherlands"
                },
                "countryCode": {
                    "type": "string",
                    "example": "NL"
                },
                "destination": {
                    "description": "ETA events",
                    "type": "string",
                    "example": "NLRTM"
                },
                "draughtCalculatedAvg": {
                    "type": "number",
                    "example": 13.8
                },
                "draughtObservedMax": {
                    "type": "number",
                    "example": 16
                },
                "eni": {
                    "description": "Static fields, from the vessels table. All omitempty.",
                    "type": "string",
                    "example": "02320524"
                },
                "heading": {
                    "description": "Dynamic fields, present per event-type.",
                    "type": "number",
                    "example": 231.5
                },
                "imo": {
                    "type": "integer",
                    "example": 9321483
                },
                "lastAISUpdate": {
                    "description": "position events",
                    "type": "string"
                },
                "length": {
                    "type": "integer",
                    "example": 110
                },
                "mmsi": {
                    "type": "integer",
                    "example": 477045900
                },
                "nameAIS": {
                    "description": "NameAIS is the name as currently broadcast on AIS; may briefly differ from VesselName after a rename.",
                    "type": "string",
                    "example": "EVER GIVEN"
                },
                "speed": {
                    "description": "SOG, position events",
                    "type": "number",
                    "example": 14.1
                },
                "speedCalculatedAvg": {
                    "description": "Long-term aggregates derived from this vessel's own AIS history (last 31 days).\n\"calculated\" = arithmetic mean we computed; \"observed\" = peak we actually saw.\nBoth are distinct from design specifications.",
                    "type": "number",
                    "example": 12.4
                },
                "speedObservedMax": {
                    "type": "number",
                    "example": 22.1
                },
                "summerDraught": {
                    "description": "SummerDraught is the design summer-load draft from class-society / Equasis particulars.\nDistinct from DraughtObservedMax (the observed peak from AIS).",
                    "type": "number",
                    "example": 16.5
                },
                "teu": {
                    "type": "integer",
                    "example": 23992
                },
                "vesselName": {
                    "type": "string",
                    "example": "EVER GIVEN"
                },
                "vesselSubtype": {
                    "type": "string",
                    "example": "Motorvrachtschip"
                },
                "vesselType": {
                    "type": "string",
                    "example": "Container Ship"
                }
            }
        },
        "FilterGroup": {
            "type": "object",
            "properties": {
                "predicates": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/FilterPredicate"
                    }
                }
            }
        },
        "FilterPredicate": {
            "type": "object",
            "properties": {
                "field": {
                    "type": "string",
                    "example": "length"
                },
                "op": {
                    "type": "string",
                    "example": "gte"
                },
                "value": {
                    "type": "object"
                },
                "values": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    },
                    "example": [
                        "Cargo",
                        "Bulk carrier"
                    ]
                }
            }
        },
        "ForbiddenErrorDetail": {
            "type": "object",
            "properties": {
                "code": {
                    "allOf": [
                        {
                            "$ref": "#/definitions/ErrorCode"
                        }
                    ],
                    "example": "feature_not_available"
                },
                "message": {
                    "type": "string",
                    "example": "advanced notifications require the Pro plan (current plan: basic)"
                },
                "type": {
                    "allOf": [
                        {
                            "$ref": "#/definitions/ErrorType"
                        }
                    ],
                    "example": "forbidden_error"
                }
            }
        },
        "ForbiddenErrorResponse": {
            "type": "object",
            "properties": {
                "error": {
                    "$ref": "#/definitions/ForbiddenErrorDetail"
                }
            }
        },
        "GeoJSON": {
            "description": "GeoJSON Point geometry for geospatial coordinates",
            "type": "object",
            "properties": {
                "coordinates": {
                    "description": "Coordinates Array of [longitude, latitude] in decimal degrees",
                    "type": "array",
                    "items": {
                        "type": "number"
                    },
                    "example": [
                        103.8215,
                        1.2644
                    ]
                },
                "type": {
                    "description": "Type GeoJSON geometry type, always \"Point\" for location data",
                    "type": "string",
                    "example": "Point"
                }
            }
        },
        "Geofence": {
            "type": "object",
            "properties": {
                "latBottom": {
                    "type": "number",
                    "example": 51.8
                },
                "latTop": {
                    "type": "number",
                    "example": 52.1
                },
                "lonLeft": {
                    "type": "number",
                    "example": 3.5
                },
                "lonRight": {
                    "type": "number",
                    "example": 4.5
                }
            }
        },
        "GeofenceChange": {
            "type": "object",
            "properties": {
                "geofence": {
                    "$ref": "#/definitions/Geofence"
                }
            }
        },
        "InternalServerErrorDetail": {
            "type": "object",
            "properties": {
                "code": {
                    "allOf": [
                        {
                            "$ref": "#/definitions/ErrorCode"
                        }
                    ],
                    "example": "internal_error"
                },
                "error_id": {
                    "type": "string",
                    "example": "550e8400-e29b-41d4-a716-446655440000"
                },
                "message": {
                    "type": "string",
                    "example": "An internal error occurred. Please reference error ID 550e8400-e29b-41d4-a716-446655440000 when contacting support."
                },
                "timestamp": {
                    "type": "string",
                    "example": "2026-03-25T12:00:00Z"
                },
                "type": {
                    "allOf": [
                        {
                            "$ref": "#/definitions/ErrorType"
                        }
                    ],
                    "example": "api_error"
                }
            }
        },
        "InternalServerErrorResponse": {
            "type": "object",
            "properties": {
                "error": {
                    "$ref": "#/definitions/InternalServerErrorDetail"
                }
            }
        },
        "NavStatusChange": {
            "type": "object",
            "properties": {
                "current": {
                    "type": "integer",
                    "example": 5
                },
                "previous": {
                    "type": "integer",
                    "example": 1
                }
            }
        },
        "NotFoundErrorDetail": {
            "type": "object",
            "properties": {
                "code": {
                    "description": "Code is a short string identifier for this error for programmatic handling",
                    "allOf": [
                        {
                            "$ref": "#/definitions/github_com_vesselapi_vessel-notifications_go-common_vessel-data-contracts_responses.ErrorCode"
                        }
                    ],
                    "example": "resource_missing"
                },
                "message": {
                    "description": "Message is a human-readable message providing more details about the error",
                    "type": "string",
                    "example": "Vessel not found: 123456789"
                },
                "type": {
                    "description": "Type categorizes the error (always \"not_found_error\" for 404s)",
                    "allOf": [
                        {
                            "$ref": "#/definitions/github_com_vesselapi_vessel-notifications_go-common_vessel-data-contracts_responses.ErrorType"
                        }
                    ],
                    "example": "not_found_error"
                }
            }
        },
        "NotFoundErrorResponse": {
            "type": "object",
            "properties": {
                "error": {
                    "$ref": "#/definitions/NotFoundErrorDetail"
                }
            }
        },
        "Notification": {
            "type": "object",
            "properties": {
                "active": {
                    "type": "boolean",
                    "example": true
                },
                "createdAt": {
                    "type": "string",
                    "example": "2026-03-27T12:00:00Z"
                },
                "etaShiftThresholdMinutes": {
                    "type": "integer",
                    "example": 120
                },
                "eventTypes": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    },
                    "example": [
                        "port.arrival",
                        "position.update"
                    ]
                },
                "geofence": {
                    "$ref": "#/definitions/Geofence"
                },
                "id": {
                    "type": "string",
                    "example": "550e8400-e29b-41d4-a716-446655440000"
                },
                "imos": {
                    "type": "array",
                    "items": {
                        "type": "integer"
                    },
                    "example": [
                        9321483,
                        9472440
                    ]
                },
                "mmsis": {
                    "type": "array",
                    "items": {
                        "type": "integer"
                    },
                    "example": [
                        477045900
                    ]
                },
                "name": {
                    "type": "string",
                    "example": "My fleet alerts"
                },
                "speedThresholdKnots": {
                    "type": "number",
                    "example": 0.5
                },
                "updatedAt": {
                    "type": "string",
                    "example": "2026-03-27T12:00:00Z"
                },
                "webhookUrl": {
                    "type": "string",
                    "example": "https://example.com/webhook"
                },
                "websocket": {
                    "type": "boolean",
                    "example": false
                }
            }
        },
        "NotificationListResponse": {
            "type": "object",
            "properties": {
                "notifications": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/Notification"
                    }
                }
            }
        },
        "NotificationResponse": {
            "type": "object",
            "properties": {
                "notification": {
                    "$ref": "#/definitions/Notification"
                }
            }
        },
        "Polygon": {
            "type": "object",
            "properties": {
                "coordinates": {
                    "description": "Coordinates is a single closed ring of 4 to 5000 [longitude, latitude]\npairs in WGS84; the first and last point must be identical. No holes or\nmultipolygons; edges crossing the antimeridian are rejected. The server\nsimplifies the ring at roughly 100 m tolerance on write and stores the\nsimplified polygon.",
                    "type": "array",
                    "items": {
                        "type": "array",
                        "items": {
                            "type": "number",
                            "format": "float64"
                        }
                    }
                }
            }
        },
        "PortCall": {
            "description": "Marker for port events. The actual port data is in the sibling 'portEvent' field of EventData.",
            "type": "object"
        },
        "PortEvent": {
            "description": "Vessel port call event including arrivals and departures",
            "type": "object",
            "properties": {
                "event": {
                    "description": "Event Type of port event - either \"Arrival\" or \"Departure\"",
                    "type": "string",
                    "example": "Arrival"
                },
                "port": {
                    "description": "Port Reference to the port where the event occurred",
                    "allOf": [
                        {
                            "$ref": "#/definitions/PortReference"
                        }
                    ]
                },
                "timestamp": {
                    "description": "Timestamp UTC timestamp when the event occurred",
                    "type": "string"
                },
                "vessel": {
                    "description": "Vessel Reference to the vessel involved in the port event",
                    "allOf": [
                        {
                            "$ref": "#/definitions/VesselReference"
                        }
                    ]
                }
            }
        },
        "PortReference": {
            "description": "Port identification details for port event reference",
            "type": "object",
            "properties": {
                "country": {
                    "description": "Country Country where the port is located",
                    "type": "string",
                    "example": "Singapore"
                },
                "name": {
                    "description": "Name The port's official name",
                    "type": "string",
                    "example": "Singapore"
                },
                "unlo_code": {
                    "description": "UnloCode UN Location Code (LOCODE) for the port",
                    "type": "string",
                    "example": "SGSIN"
                }
            }
        },
        "PositionChange": {
            "description": "Marker for position.position_changed events. The actual position data is in the sibling 'position' field of EventData.",
            "type": "object"
        },
        "PositionUpdate": {
            "description": "Marker for position.update events. The actual position data is in the sibling 'position' field of EventData.",
            "type": "object"
        },
        "PrefillStatus": {
            "type": "string",
            "enum": [
                "pending",
                "running",
                "ready",
                "failed"
            ],
            "x-enum-varnames": [
                "PrefillPending",
                "PrefillRunning",
                "PrefillReady",
                "PrefillFailed"
            ]
        },
        "RateLimitErrorDetail": {
            "type": "object",
            "properties": {
                "code": {
                    "allOf": [
                        {
                            "$ref": "#/definitions/ErrorCode"
                        }
                    ],
                    "example": "rate_limit_exceeded"
                },
                "message": {
                    "type": "string",
                    "example": "API monthly quota exceeded"
                },
                "type": {
                    "allOf": [
                        {
                            "$ref": "#/definitions/ErrorType"
                        }
                    ],
                    "example": "rate_limit_error"
                }
            }
        },
        "RateLimitErrorResponse": {
            "type": "object",
            "properties": {
                "error": {
                    "$ref": "#/definitions/RateLimitErrorDetail"
                }
            }
        },
        "SpeedChange": {
            "type": "object",
            "properties": {
                "currentSog": {
                    "type": "number",
                    "example": 0.1
                },
                "previousSog": {
                    "type": "number",
                    "example": 12.3
                },
                "stopped": {
                    "type": "boolean",
                    "example": true
                }
            }
        },
        "TestDelivery": {
            "type": "object",
            "properties": {
                "channel": {
                    "type": "string",
                    "example": "webhook"
                },
                "durationMs": {
                    "type": "integer",
                    "example": 127
                },
                "error": {
                    "type": "string",
                    "example": "connection refused"
                },
                "statusCode": {
                    "type": "integer",
                    "example": 200
                },
                "success": {
                    "type": "boolean",
                    "example": true
                }
            }
        },
        "TestResponse": {
            "type": "object",
            "properties": {
                "delivered_to": {
                    "description": "DeliveredTo lists the channels where delivery succeeded (for simple\nbackwards-compatible checks). See Results for per-channel detail.",
                    "type": "array",
                    "items": {
                        "type": "string"
                    },
                    "example": [
                        "webhook",
                        "websocket"
                    ]
                },
                "payload": {
                    "description": "Payload is the full event envelope that was delivered",
                    "allOf": [
                        {
                            "$ref": "#/definitions/EventEnvelope"
                        }
                    ]
                },
                "results": {
                    "description": "Results is the per-channel outcome including HTTP status and errors.",
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/TestDelivery"
                    }
                }
            }
        },
        "UpdateAdvancedNotificationRequest": {
            "type": "object",
            "properties": {
                "active": {
                    "type": "boolean"
                },
                "etaShiftThresholdMinutes": {
                    "type": "integer"
                },
                "eventTypes": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "filterGroups": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/FilterGroup"
                    }
                },
                "hysteresisMeters": {
                    "type": "integer"
                },
                "polygon": {
                    "$ref": "#/definitions/Polygon"
                },
                "vessels": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/AdvancedVesselRef"
                    }
                },
                "webhookSecret": {
                    "type": "string"
                },
                "webhookUrl": {
                    "type": "string"
                },
                "websocket": {
                    "type": "boolean"
                }
            }
        },
        "UpdateNotificationRequest": {
            "type": "object",
            "properties": {
                "active": {
                    "type": "boolean",
                    "example": true
                },
                "etaShiftThresholdMinutes": {
                    "type": "integer",
                    "example": 120
                },
                "eventTypes": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    },
                    "example": [
                        "port.arrival",
                        "position.update"
                    ]
                },
                "geofence": {
                    "$ref": "#/definitions/Geofence"
                },
                "imos": {
                    "type": "array",
                    "items": {
                        "type": "integer"
                    },
                    "example": [
                        9321483,
                        9472440
                    ]
                },
                "mmsis": {
                    "type": "array",
                    "items": {
                        "type": "integer"
                    },
                    "example": [
                        477045900
                    ]
                },
                "name": {
                    "type": "string",
                    "example": "Updated fleet name"
                },
                "speedThresholdKnots": {
                    "type": "number",
                    "example": 0.5
                },
                "webhookSecret": {
                    "type": "string",
                    "example": "my-secret-key"
                },
                "webhookUrl": {
                    "type": "string",
                    "example": "https://example.com/webhook"
                },
                "websocket": {
                    "type": "boolean",
                    "example": false
                }
            }
        },
        "VesselETA": {
            "description": "Vessel Estimated Time of Arrival information from AIS static/voyage data",
            "type": "object",
            "properties": {
                "destination": {
                    "description": "Destination Reported destination port or area as entered by the vessel",
                    "type": "string",
                    "example": "SINGAPORE"
                },
                "destination_port": {
                    "description": "DestinationPort Resolved UN/LOCODE of the destination port (empty if unresolved)",
                    "type": "string",
                    "example": "NLRTM"
                },
                "draught": {
                    "description": "Draught Current draught (draft) of the vessel in meters",
                    "type": "number",
                    "example": 14.5
                },
                "eta": {
                    "description": "ETA Estimated time of arrival at destination as reported by the vessel",
                    "type": "string"
                },
                "imo": {
                    "description": "IMO International Maritime Organization number - permanent vessel identifier",
                    "type": "integer",
                    "example": 9321483
                },
                "mmsi": {
                    "description": "MMSI Maritime Mobile Service Identity - unique 9-digit vessel identifier",
                    "type": "integer",
                    "example": 477045900
                },
                "timestamp": {
                    "description": "Timestamp UTC timestamp when this ETA information was received",
                    "type": "string"
                },
                "vessel_name": {
                    "description": "VesselName The vessel's registered name as reported in AIS",
                    "type": "string",
                    "example": "EVER GIVEN"
                }
            }
        },
        "VesselPosition": {
            "description": "Real-time vessel position data derived from AIS messages",
            "type": "object",
            "properties": {
                "cog": {
                    "description": "COG Course Over Ground in degrees (0-359.9), null when unavailable",
                    "type": "number",
                    "example": 231.5
                },
                "heading": {
                    "description": "Heading True heading in degrees (0-359), null when unavailable",
                    "type": "integer",
                    "example": 230
                },
                "imo": {
                    "description": "IMO International Maritime Organization number - permanent vessel identifier",
                    "type": "integer",
                    "example": 9321483
                },
                "latitude": {
                    "description": "Latitude Geographic latitude in decimal degrees (-90 to 90)",
                    "type": "number",
                    "example": 1.2644
                },
                "location": {
                    "description": "Location GeoJSON point for geospatial queries",
                    "allOf": [
                        {
                            "$ref": "#/definitions/GeoJSON"
                        }
                    ]
                },
                "longitude": {
                    "description": "Longitude Geographic longitude in decimal degrees (-180 to 180)",
                    "type": "number",
                    "example": 103.8215
                },
                "mmsi": {
                    "description": "MMSI Maritime Mobile Service Identity - unique 9-digit vessel identifier",
                    "type": "integer",
                    "example": 477045900
                },
                "nav_status": {
                    "description": "NavStatus AIS navigational status (0=under way using engine, 1=at anchor, 2=not under command, 3=restricted manoeuvrability, 5=moored, 8=under way sailing, etc.), null when unavailable",
                    "type": "integer",
                    "example": 0
                },
                "processed_timestamp": {
                    "description": "ProcessedTimestamp UTC timestamp when the position was processed by the system",
                    "type": "string"
                },
                "sog": {
                    "description": "SOG Speed Over Ground in knots (0-102.2), null when unavailable",
                    "type": "number",
                    "example": 14.1
                },
                "suspected_glitch": {
                    "description": "SuspectedGlitch indicates the position may be unreliable due to a GPS glitch or corrupted AIS transmission (implies impossible vessel speed)",
                    "type": "boolean",
                    "example": false
                },
                "timestamp": {
                    "description": "Timestamp UTC timestamp when the AIS message was transmitted by the vessel",
                    "type": "string"
                },
                "vessel_name": {
                    "description": "VesselName The vessel's registered name as reported in AIS",
                    "type": "string",
                    "example": "EVER GIVEN"
                }
            }
        },
        "VesselReference": {
            "description": "Vessel identification details for port event reference",
            "type": "object",
            "properties": {
                "imo": {
                    "description": "IMO International Maritime Organization number",
                    "type": "integer",
                    "example": 9321483
                },
                "mmsi": {
                    "description": "MMSI Maritime Mobile Service Identity number",
                    "type": "integer",
                    "example": 477045900
                },
                "name": {
                    "description": "Name The vessel's registered name",
                    "type": "string",
                    "example": "EVER GIVEN"
                }
            }
        },
        "github_com_vesselapi_common_vessel-data-contracts_responses.ErrorCode": {
            "type": "string",
            "enum": [
                "resource_missing",
                "invalid_parameter",
                "invalid_mmsi",
                "invalid_imo",
                "invalid_coordinates",
                "invalid_time_range",
                "bounding_box_too_dense",
                "missing_parameter",
                "invalid_api_key",
                "rate_limit_exceeded",
                "forbidden",
                "conflict",
                "notification_inactive",
                "prefill_pending",
                "insufficient_credits",
                "feature_not_available",
                "internal_error",
                "database_error",
                "service_unavailable"
            ],
            "x-enum-varnames": [
                "ErrorCodeResourceMissing",
                "ErrorCodeInvalidParameter",
                "ErrorCodeInvalidMMSI",
                "ErrorCodeInvalidIMO",
                "ErrorCodeInvalidCoordinates",
                "ErrorCodeInvalidTimeRange",
                "ErrorCodeBoundingBoxTooDense",
                "ErrorCodeMissingParameter",
                "ErrorCodeInvalidAPIKey",
                "ErrorCodeRateLimitExceeded",
                "ErrorCodeForbidden",
                "ErrorCodeConflict",
                "ErrorCodeNotificationInactive",
                "ErrorCodePrefillPending",
                "ErrorCodeInsufficientCredits",
                "ErrorCodeFeatureNotAvailable",
                "ErrorCodeInternalError",
                "ErrorCodeDatabaseError",
                "ErrorCodeServiceUnavailable"
            ]
        },
        "github_com_vesselapi_common_vessel-data-contracts_responses.ErrorType": {
            "type": "string",
            "enum": [
                "invalid_request_error",
                "api_error",
                "authentication_error",
                "rate_limit_error",
                "forbidden_error",
                "not_found_error",
                "conflict_error",
                "payment_required_error",
                "service_unavailable_error"
            ],
            "x-enum-varnames": [
                "ErrorTypeInvalidRequest",
                "ErrorTypeAPIError",
                "ErrorTypeAuthenticationError",
                "ErrorTypeRateLimitError",
                "ErrorTypeForbidden",
                "ErrorTypeNotFoundError",
                "ErrorTypeConflict",
                "ErrorTypePaymentRequired",
                "ErrorTypeServiceUnavailable"
            ]
        },
        "github_com_vesselapi_vessel-notifications_go-common_vessel-data-contracts_responses.ErrorCode": {
            "type": "string",
            "enum": [
                "resource_missing",
                "invalid_parameter",
                "invalid_mmsi",
                "invalid_imo",
                "invalid_coordinates",
                "invalid_time_range",
                "bounding_box_too_dense",
                "missing_parameter",
                "invalid_api_key",
                "rate_limit_exceeded",
                "forbidden",
                "conflict",
                "notification_inactive",
                "prefill_pending",
                "insufficient_credits",
                "feature_not_available",
                "internal_error",
                "database_error",
                "service_unavailable"
            ],
            "x-enum-varnames": [
                "ErrorCodeResourceMissing",
                "ErrorCodeInvalidParameter",
                "ErrorCodeInvalidMMSI",
                "ErrorCodeInvalidIMO",
                "ErrorCodeInvalidCoordinates",
                "ErrorCodeInvalidTimeRange",
                "ErrorCodeBoundingBoxTooDense",
                "ErrorCodeMissingParameter",
                "ErrorCodeInvalidAPIKey",
                "ErrorCodeRateLimitExceeded",
                "ErrorCodeForbidden",
                "ErrorCodeConflict",
                "ErrorCodeNotificationInactive",
                "ErrorCodePrefillPending",
                "ErrorCodeInsufficientCredits",
                "ErrorCodeFeatureNotAvailable",
                "ErrorCodeInternalError",
                "ErrorCodeDatabaseError",
                "ErrorCodeServiceUnavailable"
            ]
        },
        "github_com_vesselapi_vessel-notifications_go-common_vessel-data-contracts_responses.ErrorType": {
            "type": "string",
            "enum": [
                "invalid_request_error",
                "api_error",
                "authentication_error",
                "rate_limit_error",
                "forbidden_error",
                "not_found_error",
                "conflict_error",
                "payment_required_error",
                "service_unavailable_error"
            ],
            "x-enum-varnames": [
                "ErrorTypeInvalidRequest",
                "ErrorTypeAPIError",
                "ErrorTypeAuthenticationError",
                "ErrorTypeRateLimitError",
                "ErrorTypeForbidden",
                "ErrorTypeNotFoundError",
                "ErrorTypeConflict",
                "ErrorTypePaymentRequired",
                "ErrorTypeServiceUnavailable"
            ]
        },
        "types.EventType": {
            "type": "string",
            "enum": [
                "test",
                "port.arrival",
                "port.departure",
                "eta.destination_changed",
                "eta.eta_changed",
                "eta.draught_changed",
                "position.nav_status_changed",
                "position.speed_changed",
                "position.update",
                "position.position_changed",
                "position.geofence_enter",
                "position.geofence_exit"
            ],
            "x-enum-varnames": [
                "EventTest",
                "EventPortArrival",
                "EventPortDeparture",
                "EventDestinationChanged",
                "EventETAChanged",
                "EventDraughtChanged",
                "EventNavStatusChanged",
                "EventSpeedChanged",
                "EventPositionUpdate",
                "EventPositionChanged",
                "EventGeofenceEnter",
                "EventGeofenceExit"
            ]
        }
    },
    "securityDefinitions": {
        "ApiKeyAuth": {
            "description": "API key authentication. Use the format: \"Bearer your_api_key_here\" in the Authorization header.",
            "type": "apiKey",
            "name": "Authorization",
            "in": "header"
        }
    },
    "tags": [
        {
            "description": "Create and manage vessel notification configurations. Each notification watches a set of vessels and delivers events via webhook and/or WebSocket.",
            "name": "Notifications"
        },
        {
            "description": "Real-time event streaming via WebSocket. Connect to receive events as they occur instead of via webhook callbacks.",
            "name": "WebSocket"
        }
    ]
}