Soft Delete & Tombstones
How deletion works in an append-only system, what tombstones are, and how to list deleted records.
What you'll learn
- ✓DELETE /v1/agents/:id/records/:hash — writes a tombstone record
- ✓flags & 0x02 — the tombstone bit
- ✓Scan without vs with include_tombstones: true
- ✓as_of before the tombstone — deleted record reappears
- ✓TTL sweeper vs manual delete — comparison
Write 3 records. Delete the middle one. Scan without tombstones — how many? With? as_of before delete — how many?
Interactive Walkthrough
What you'll learn
How deletion works in an append-only system, what tombstones are, and how to list and skip deleted records.
Why deletion is different
SapixDB never removes bytes from disk. A "delete" appends a tombstone record — a special record with flags & 0x02 = 1 that marks a content_hash as logically deleted. The original record remains forever (required for audit trails and time travel).
Delete a record by hash
curl -s -X DELETE \
"http://localhost:7475/v1/agents/users/records/<HASH>" \
-H "Authorization: Bearer spx_root_YOUR_ROOT_KEY" \
| python3 -m json.toolResponse: the tombstone record's own content_hash.
What happens after deletion
GET /v1/agents/users/records/<HASH>— returns 404 (logically deleted)POST /v1/agents/users/querywithtype: "scan"— by default excludes tombstoned recordstype: "as_of"at a timestamp before the tombstone — the record is visible (history preserved)
Include tombstoned records in a scan
curl -s -X POST http://localhost:7475/v1/agents/users/query \
-H "Content-Type: application/json" \
-H "Authorization: Bearer spx_root_YOUR_ROOT_KEY" \
-d '{"type": "scan", "limit": 100, "include_tombstones": true}' \
| python3 -m json.toolRecords with "tombstone": true in the response are logically deleted. The original payload is still in the tombstone record for audit.
TTL vs manual tombstone
TTL (ttl_ms) | Manual delete | |
|---|---|---|
| Who creates tombstone | Background sweeper | Your API call |
| When | After ttl_ms ms | Immediately |
| Use case | Sessions, caches, temp data | User-initiated deletes |
| Reversible | No | No |
Challenge
Write 3 records. Delete the middle one. Scan without include_tombstones — how many records? Scan with it — how many? Use as_of (timestamp before the delete) — does the deleted record appear?
---