Events & Alerts API
MemMesh is proactive as well as reactive: the engine appends events to a durable log, and alert rules react to matching events synchronously.
Emit an event
POST /api/v1/projects/{projectId}/lattice/events/emit
Append an event to the log. The alert evaluator runs synchronously inside
this call, so “event emitted” implies “rules matched and dispatched”. Emission is
idempotent — re-emitting the same (projectId, dedupeKey) silently drops.
{
"eventType": "prediction.imminent",
"subject": { "kind": "customer", "externalId": "acct-42" },
"severity": "warn",
"payloadJson": "{\"expectedAt\":\"2026-07-18T15:00:00Z\"}",
"sourcePatternId": "mem_…"
}severity is info | warn | critical (defaults to info). The response
reports whether the event was inserted and how many alert rules dispatched:
{ "emitted": true, "event": { "id": "evt_…", "eventType": "prediction.imminent", "severity": "warn", "occurredAt": "…" }, "alertDispatches": 1 }Predictions can emit events for you: call POST /lattice/predict with
emitEvents: true to fire a prediction.imminent event for each prediction due
within imminentWithinHours. See Predictions.
Poll events
GET /api/v1/projects/{projectId}/memory-events?since=…&limit=…&eventTypes=…
Walk the log. Pass the last returned event’s occurredAt back as since to page
forward; eventTypes is a comma-separated filter.
[
{
"id": "evt_…",
"eventType": "prediction.imminent",
"subject": { "kind": "customer", "externalId": "acct-42" },
"severity": "warn",
"payload": { "expectedAt": "2026-07-18T15:00:00Z" },
"sourceMemoryIds": [],
"sourcePatternId": "mem_…",
"emittedByPack": null,
"occurredAt": "2026-07-13T00:00:00Z"
}
]Alert rules
CRUD under /api/v1/projects/{projectId}/memory-alerts.
| Method | Path | Purpose |
|---|---|---|
GET | /memory-alerts | List rules. |
GET | /memory-alerts/:alertId | Fetch one rule. |
POST | /memory-alerts | Create a rule. |
PATCH | /memory-alerts/:alertId | Patch any subset of fields. |
DELETE | /memory-alerts/:alertId | Delete a rule + its fire history. |
GET | /memory-alerts/:alertId/fires | List recent fires (last 100). |
A rule has four JSON parts:
{
"name": "Imminent churn → Slack",
"enabled": true,
"trigger": { "kind": "engine-event", "eventTypes": ["prediction.imminent"] },
"filter": { "subjectKind": "customer" },
"notify": [ { "kind": "webhook", "url": "https://hooks…" } ],
"throttle": { "cooldownMinutes": 60, "dedupOn": "subject+rule" }
}- trigger.kind —
engine-event|segment-change|pattern-emerged. - filter — narrow by
subjectKind, id pattern,categories, or a metadata match. - notify — an array of channels; a channel can also
writeAsa memory back into a scope. - throttle —
maxPerHour,cooldownMinutes, anddedupOn(subject|subject+rule|rule).
The number of active rules counts against the active-triggers entitlement.
A GET …/fires row carries the dedupeKey and parsed deliveryResults per
channel.