Skip to content

Events

An event says that something happened: a deploy finished, a container died, a lead arrived. Every SDK, plugin and hook speaks the same format, defined by the open JSON Schema event.schema.json (protocol version 0).

{
"source": "dokploy",
"type": "container.die",
"severity": "high",
"occurred_at": "2026-11-05T12:00:00Z",
"to": ["jimmy"],
"payload": { "host": "vps-01", "exit_code": 137 },
"dedup_key": "vps-01/api-v2",
"expires_when": "container.healthy",
"content": {
"summary": "api-v2 died on vps-01",
"card": { "title": "Container died", "blocks": [{ "type": "metric", "label": "Crashes in 24h", "value": 3 }] }
}
}
Field Required Description
source Yes Who generated it (dokploy, crm, finance-agent), 1–120 characters. The SDK fills it from new NotificMe({ source }).
type Yes Dotted lowercase type: container.die, lead.new. Pattern ^[a-z0-9_-]+(\.[a-z0-9_-]+)*$.
severity Yes info, low, medium, high or critical. The SDK defaults to info.
occurred_at Yes When it happened (RFC 3339). The SDK defaults to now.
id No Your id for the event, used for idempotency. The SDK always sends one.
to No Recipients: a handle, a member e-mail or a group. Without to, the workspace rules and subscriptions decide.
payload No Free-form data. The SDK sends it as is (keys are not converted).
dedup_key No Events with the same key inside the dedup window (1 hour by default, or the event ttl) are merged.
ttl No How long the notification stays relevant: 30m, 2h, 3d.
expires_when No An event type that closes this notification, such as container.healthy.
card_id No Updates an existing card instead of creating another one (a live card).
retention No ephemeral, standard (default) or regulated.
content.summary With content Short text for push, watch and simple channels (up to 240 characters).
content.card No The declarative card.
content.rich No A sandboxed HTML reference, always with card as the fallback.

to only resolves members of the service’s workspace: the current handle, an old handle still reserved, or the e-mail of the membership. Nobody can be notified without consent: a person who has not accepted the invite is not resolved, and POST /v0/events answers 422. Removing a member cuts access immediately. See Workspaces and members.

  • Idempotency: the same id sent twice is stored once. A retry returns the stored response with the Idempotent-Replayed: true header. Reusing an id with different content returns 409 idempotency_conflict.
  • Deduplication: a repeat with the same dedup_key in the window is accepted with status: "duplicate" and duplicate_of.

Events with the same card_id update the same card instead of creating new notifications. A deploy goes from building to testing to live in one card. With the SDK, pass live: true and then call update():

const deploy = await notific.send({
type: "deploy.progress",
summary: "Deploying api",
live: true,
card: { blocks: [{ type: "progress", value: 0.1, steps: ["Build", "Tests", "Rollout"], current: 0 }] },
});
await notific.update(deploy.cardId!, {
card: { blocks: [{ type: "progress", value: 0.8, steps: ["Build", "Tests", "Rollout"], current: 2 }] },
});
Limit Default
Events per token 600 per minute (burst of 100), then 429 rate_limited with Retry-After
Body size 1 MiB
Dedup window 1 hour (the event ttl takes precedence)
Idempotency memory 24 hours