← All lessons/Working with Records
7
Working with Records

Soft Delete & Tombstones

How deletion works in an append-only system, what tombstones are, and how to list deleted records.

Prerequisite: Lesson 6 complete

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)
Challenge

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.tool

Response: 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/query with type: "scan" — by default excludes tombstoned records
  • type: "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.tool

Records 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 tombstoneBackground sweeperYour API call
WhenAfter ttl_ms msImmediately
Use caseSessions, caches, temp dataUser-initiated deletes
ReversibleNoNo

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?

---

← Previous
Lesson 6: Reading Records in Depth
Next →
Lesson 8: Batch Writes

The Sensart ecosystem

Explore our products

One team, many agents. Each product below is built by Sensart Technologies toward an agent-native future.

Boboyka VoiceBoboyka VoiceVoice generation engineHire BoboykaHire BoboykaHire 24/7 AI employeesBoboykaBoboykaAutonomous software factoryCodiosCodiosAgent caging platformA2AA2AAI agent governance platformConduitConduitVisual MCP orchestration studioPentestPentestAI penetration testingPromoterPromoterGrow your product organicallyMactebMactebGamified homeschooling
An umbrella ofSensart TechnologiesSensart Technologies