Soft Delete & Tombstones
How deletion works in an append-only system, what tombstones are, and how to list deleted records.
What you'll learn
- ✓POST .../records with flags: 2 — any writer can tombstone a record (flags & 0x02)
- ✓DELETE /v1/agents/:id/records/:hash — admin-gated soft-delete; also tombstones, plus an independent, auditable {"_deleted": true} marker
- ✓Only current/count_current actually exclude tombstoned records — scan, latest, and history always show everything regardless of flags
- ✓as_of does not filter tombstones either — it returns whatever existed by that timestamp, tombstone markers included if already written
- ✓GET .../records/deleted + POST .../records/:hash/restore — list and undo (restore appends a new record, it does not revive the original in place)
Write 3 records sharing a key field. Tombstone the middle one. Compare current({key}) before and after — count the difference. Then run scan() — confirm all 3 (including the tombstone marker) still come back.
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?
---









Sensart Technologies