Every event shares the same shape:
{
"id": "evt_<32-hex>",
"type": "<event-type>",
"created_at": "<ISO 8601 UTC>",
"data": {
"user_id": "<DSS user id>"
}
}
Bodies are JSON, UTF-8, sorted keys, no whitespace — the canonical form
that the signature is computed over. See
Signature verification for why that matters.
user.profile.updated
Fires when name, role, country, or photo URL change.
Scope required for delivery: profile:read
{
"id": "evt_3f4a9c8e2b1d4f5a8c9e0d1f2a3b4c5d",
"type": "user.profile.updated",
"created_at": "2026-05-26T09:14:00Z",
"data": {
"user_id": "65a1f0e2c3b4d5e6f7a8b9c0"
}
}
Recommended action: GET /v1/me with the user’s access token, replace
your cached profile.
user.sea_time.updated
Fires when sea-time totals change — a new sea time entry verified, an existing
entry amended, or a recalculation.
Scope required for delivery: seatime:read
{
"id": "evt_a1b2c3d4e5f6789012345678abcdef01",
"type": "user.sea_time.updated",
"created_at": "2026-05-26T09:14:00Z",
"data": {
"user_id": "65a1f0e2c3b4d5e6f7a8b9c0"
}
}
Recommended action: GET /v1/me/sea-time (and /recent if you display
the trend chart).
user.vessels.updated
Fires when a vessel period is added or amended.
Scope required for delivery: vessels:read
{
"id": "evt_77f1bb31c0c64e6db4f5e8a9c2d3e4f5",
"type": "user.vessels.updated",
"created_at": "2026-05-26T09:14:00Z",
"data": {
"user_id": "65a1f0e2c3b4d5e6f7a8b9c0"
}
}
Recommended action: GET /v1/me/vessels. If you paginate, start from the
first page — a vessel period change can shift the sort order of any page.
user.consent.revoked
Fires when the user disconnects your integration from the DSS dashboard.
Scope required for delivery: none — this event delivers regardless of
which scopes you held. A partner who never held profile:read still needs to
know to clean up.
{
"id": "evt_0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f",
"type": "user.consent.revoked",
"created_at": "2026-05-26T09:14:00Z",
"data": {
"user_id": "65a1f0e2c3b4d5e6f7a8b9c0"
}
}
Recommended action: delete any cached DSS data for this user within 30
days (DPA-enforced). Your stored OAuth tokens are already invalidated on our
side — calls with them will return 401 invalid_token even before this event
reaches you.
Disconnect handling is a frequent gap in V1 integrations. Build it before
going to production — we check for it as part of integration review.
webhook.test
Fired by GET /v1/webhooks/test. Identical shape to real events; user_id
is the calling user (the access token’s subject).
Scope required for delivery: none — the test endpoint always delivers.
{
"id": "evt_test99887766554433221100ffeeddcc",
"type": "webhook.test",
"created_at": "2026-05-26T09:14:00Z",
"data": {
"user_id": "65a1f0e2c3b4d5e6f7a8b9c0"
}
}
Recommended action: none — this is a fire-and-forget test. A 2xx response
proves your handler is reachable, signature verification works, and your
endpoint stays under the 5-second budget.
Every delivery, regardless of event type:
| Header | Value |
|---|
Content-Type | application/json |
X-DSS-Signature | t=<unix-ts>,v1=<hex-sha256> |
User-Agent | dss-public-api-webhooks/1 |
The X-DSS-Signature value is HMAC-SHA256 of <ts>.<raw-body> using your
webhook signing secret. See Verification.
Retry & give-up
| Attempt | Delay since previous |
|---|
| 1 | (immediate) |
| 2 | +1 minute |
| 3 | +5 minutes |
| 4 | +30 minutes |
| 5 | +2 hours |
| 6 | +6 hours |
We give up after 24 hours or 6 attempts total, whichever comes first.
Failed deliveries persist in our webhook delivery log; we surface gives-up
in the super-admin dashboard for the integration team to investigate
together.
Future events
We add events conservatively and announce on the changelog.
Plan your handler with an unknown-event fallback that returns 2xx and
logs — adding a new event type isn’t a breaking change.