Object lifecycles
Per object type, lifecycles run automated actions when entries are created, updated, or become due on a schedule. Configure them in Admin → Objects → Lifecycles, or via the API/MCP lifecycle endpoints.
How it works
A lifecycle config is `{ version: 3, events: [...] }`. Each event has: `id`, `name`, optional `enabled` (default true), `when` (trigger), `constraints` (all must pass), and `actions`. On create/update, matching events run in order. Schedule events are evaluated by a periodic worker sweep (not one-shot enqueue). Actions can send email, create in-app notifications, modify fields, or create related entries. Nested email/notification actions can include links or one-click `trigger` tokens that apply `modify_field` effects when opened.
Scheduled events
Use `when: { type: "schedule", anchorPath, offsetDays }` where `anchorPath` is an own `date`/`dateTime` field or `created_at`/`mutated_at`. `offsetDays` is an integer (default 0; negative allowed). Due instant is the start of the UTC calendar day of the anchor plus the offset. The event is eligible when `now >= due`. Each firing is recorded once per `(entry, event, due_at)`; if the anchor date later changes, a new due key can fire again.
Field bindings & templates
Binding paths reference own fields (`title`) or short relation chains (`author.display_name`, max depth limited by schema). Email/notification subject and title use template segments: `{ kind: "text", text }` or `{ kind: "field", fieldKey }`. HTML bodies may embed `{{fieldKey}}` placeholders for field chips from the rich-text editor.
Constraints
Constraints are `field_compare` (leftPath + op + optional right) or `related_count` (inverse relation count). `field_compare` rights may be a literal, another field path, or `{ kind: "relative_date", path, offsetDays }` for date comparisons. `created_at` / `mutated_at` may be used as date sides. Use `changed` / `changed_to` only on update events. `related_count` counts entries of another type whose relation field points at the current entry (`op`: eq/neq/lt/gt).
Safety guards
The engine rejects configs that form modify-field cycles across events, or that modify the same field twice in one event. `create_entry` may trigger the destination type's `entry_created` events with the same depth/`ruleStack` caps as nested updates. Prefer a single `modify_field` per field per event; chain follow-up work with constraints on the next update.
API & MCP
Read/update lifecycle JSON with `GET/PUT /api/v1/{locale}/{websiteId}/objects/{objectTypeId}/lifecycle`. MCP tools: `get_object_lifecycle`, `update_object_lifecycle`. Use `get_lifecycle_docs` for this guide.
Referans
Event triggers
entry_created: Fires after a new entry is successfully created.entry_updated: Fires after an entry is updated. Pair with `changed` / `changed_to` constraints.schedule: Fires from the task worker when now is on/after anchorPath + offsetDays (day granularity).
Actions
send_email: Email to `self`, a user-relation path, or legacy email field. Optional nested link/trigger actions.create_notification: In-app notification to a relation_user path. Optional link actions.modify_field: Set a field on the current entry to a literal value.create_entry: Create an entry of another type. Each target field maps from a literal, a compatible source field, or `self` (relation to the triggering entry).
Constraint operators
eq / neq: Equal / not equal to literal or field.empty / not_empty: Presence checks.lt / gt: Numeric comparisons (and related_count).before / after: Date/time comparisons (literal, field, or relative_date).changed / changed_to: Update-only: field changed, or changed to a value.related_count: Compare how many inverse-related entries exist (eq/neq/lt/gt).
Relation hops
forward: Follow a relation field on the current type.inverse: Hop via another type that points at this entry.match: Match another type on a shared field value.
Örnekler
Welcome email after approval
On update, when `approved` changes to true, email the member and include a login link.
{
"version": 3,
"events": [
{
"id": "welcome_after_approval",
"name": "Welcome member",
"when": {
"type": "entry_updated"
},
"constraints": [
{
"type": "field_compare",
"leftPath": "approved",
"op": "changed_to",
"right": {
"kind": "literal",
"value": true
}
}
],
"actions": [
{
"type": "send_email",
"emailFieldKey": "self",
"subject": [
{
"kind": "text",
"text": "Welcome to "
},
{
"kind": "field",
"fieldKey": "display_name"
}
],
"bodyHtml": "<p>Your account is ready.</p>",
"actions": [
{
"type": "link",
"label": "Sign in",
"pathTemplate": "/login"
}
]
}
]
}
]
}Email verification with trigger
On create, send a verification email whose button is a trigger token that sets `email_verified` (and optionally `approved`) when clicked.
{
"version": 3,
"events": [
{
"id": "send_email_verification",
"name": "Send email verification",
"when": {
"type": "entry_created"
},
"constraints": [],
"actions": [
{
"type": "send_email",
"emailFieldKey": "self",
"subject": [
{
"kind": "text",
"text": "Verify your email"
}
],
"bodyHtml": "<p>Click below to verify.</p>",
"actions": [
{
"type": "trigger",
"label": "Verify your email",
"tokenTtlMinutes": 1440,
"effects": [
{
"type": "modify_field",
"fieldKey": "email_verified",
"value": true
}
]
}
]
}
]
}
]
}Notify author on status change
Create an in-app notification for a related user when a status field changes.
{
"version": 3,
"events": [
{
"id": "notify_status",
"name": "Notify author of status",
"when": {
"type": "entry_updated"
},
"constraints": [
{
"type": "field_compare",
"leftPath": "status",
"op": "changed"
}
],
"actions": [
{
"type": "create_notification",
"targetPath": [
{
"kind": "forward",
"fieldKey": "author"
}
],
"title": [
{
"kind": "text",
"text": "Status updated"
}
],
"bodyHtml": "<p>Your item status changed.</p>",
"actions": [
{
"type": "link",
"label": "View",
"pathTemplate": "/items/[id]",
"appendEntryHash": true
}
]
}
]
}
]
}Schedule first related entry
When `first_service_after` is due and no service appointments point at this order yet, create one with mapped fields.
{
"version": 3,
"events": [
{
"id": "schedule_first_service",
"name": "Create first service appointment",
"when": {
"type": "schedule",
"anchorPath": "first_service_after",
"offsetDays": 0
},
"constraints": [
{
"type": "related_count",
"objectTypeSlug": "service_appointment",
"fieldKey": "order",
"op": "eq",
"value": 0
}
],
"actions": [
{
"type": "create_entry",
"objectTypeSlug": "service_appointment",
"fields": [
{
"fieldKey": "order",
"source": {
"kind": "self"
}
},
{
"fieldKey": "scheduled_for",
"source": {
"kind": "field",
"path": "first_service_after"
}
},
{
"fieldKey": "status",
"source": {
"kind": "literal",
"value": "planned"
}
}
]
}
]
}
]
}Notlar
- Omit `enabled` or set `enabled: true` to keep an event active; set `enabled: false` to soft-disable.
- Locale overlays can localize event names, email subject/body, and action labels per website locale.
- Trigger tokens are time-limited (`tokenTtlMinutes`) and apply effects once when redeemed.
- Schedule events use day granularity only; hour/minute offsets are out of scope for v1.