Use the lifecycle surface when memories mirror records your database owns — CRM rows, profile fields, tickets. Unlike append-only save, these memories have a durable identity and version history, so corrections and deletes from the source of truth apply exactly once, in order, no matter how messy delivery gets.
The identity model
A source-owned memory is identified by (endUserId, source, externalId). version must increase whenever the source record changes.
Delivery guarantees
Mutations are synchronous, and the rules are simple:
- Retrying the same version + payload returns the same durable receipt. Re-sending after a crash is safe — that is the crash-recovery story.
- A different payload for an existing version returns
409. Versions are immutable.
- A delayed older version returns
409 and never overwrites newer content or resurrects a deleted memory.
Deletes follow the same versioning:
The delete is durable: retries converge to the original receipt, and delayed upserts with lower versions cannot recreate the memory.
Bootstrapping with an outbox
Bulk-mirror existing records through lifecycleBatch — up to 100 items and 1 MiB of aggregate content per call. There is no server-side import job; a client-side outbox that re-sends after a crash is the entire resume story:
result.success only means “the batch was processed” — always check per-item outcomes. Mark a row done on success or stale_source_version (both mean the version is already durable), then send the next batch.
Reading back
GET /api/v1/memories/{externalId} returns the memory and its latest applied receipt — useful for verifying convergence after a migration.