Skip to Content

Deletion

Permanently remove records from a topic by seq range (before_seq) and/or by tag match (match). A delete removes records that exist right now: it is permanent, effective immediately for every reader, silent (never a tombstone), and point-in-time — future records with the same tag are never affected.

This page covers the delete request grammar, the semantics of each before_seq/match combination, the response, and the errors. Deletion is the voluntary-removal half of the data model; for why it never produces a tombstone, see the deletion guarantee.

POST /v0/topics/:topic/delete — remove records

POST/v0/topics/:topic/delete

Permanently remove records by seq range, tag match, or both. Deletion is:

  • Permanent — deleted records are gone for good; there is no un-delete in /v0.
  • Effective immediately — invisible to all reads at once (diff, topic-state count/bytes, and SSE); the reader’s cursor simply advances past the deleted seqs.
  • Asynchronous, no compaction / no reclaim — records are logically gone instantly (work runs off the call path), but a deleted record stays on disk, just marked: on disk a delete flips an in-place delete-flag byte in segment files (the WAL stays append-only), and the only space released is a whole segment dropped when a delete clears it entirely.
  • Silent — a delete never produces a tombstone. Tombstones are reserved for involuntary cap/TTL loss.
  • Point-in-time — it is not a standing filter. It removes only records present at call time; future records, even with a matching tag, are never affected.

A delete advances the topic’s earliest_seq (its first live seq) but not its evict_floor (the involuntary cap/TTL floor), so reading across a purely-deleted gap is silent — there is no way for a lagging consumer to “miss a deletion,” because the record is gone for all readers at the same instant.

Request body

At least one of before_seq / match is required (else 400 invalid_request); supply both to AND them.

# Cancel one order by exact tag match. curl -X POST $TOPICS/v0/topics/orders/delete \ -H 'content-type: application/json' \ -d '{ "match": ["tag", "Eq", "order-7731"] }'
# → 200 OK { "topic": "orders", "deleted": 1, "earliest_seq": 480001, "head_seq": 480234, "count": 233, "bytes": 478342, "performance": { "server_total_ms": 0.12 } }
FieldTypeReq?Meaning
before_sequ64one ofDelete every record with $seq < before_seq (a snapshot / drop-prefix by seq — logical removal, not physical compaction).
matchpredicateone ofA tag predicate: ["tag","Eq","X"] exact match, or ["tag","Glob","X*"] trailing-prefix only (a literal prefix followed by a single *). A bare string is shorthand for Eq: "match": "order-7731" == ["tag","Eq","order-7731"].

Glob is deliberately limited to a trailing * — a literal prefix plus one *. Full glob/regex is excluded so a tag delete is always either a point lookup or a bounded range scan over the per-topic tag index, never a full-log scan. Records with no tag are never matched by match.

Semantics by combination

BodyEffect
before_seq onlyDelete every record with $seq < before_seq (a snapshot / drop-prefix by seq).
match onlyDelete every existing record whose tag matches, bounded by the current head at call time. Point-in-time: future records with that tag are not deleted (e.g. revoke a kicked user’s chat history with match ["tag","Glob","user-1042:*"]).
match + before_seqDelete records with $seq < before_seq AND a matching tag (e.g. publish v2 of a message then delete its prior versions, keeping the new one: match ["tag","Eq","user-1042:msg-5"], before_seq = <seq of v2>).

Response

{ "topic": "orders", "deleted": 14, "earliest_seq": 480001, "head_seq": 480234, "count": 234, "bytes": 478820, "performance": { "server_total_ms": 0.12 } }
FieldTypeMeaning
topicstringThe topic name.
deletedintCount of records removed by this call.
earliest_sequ64New first live seq (advanced past any deleted prefix).
head_sequ64Topic log end (unchanged by a delete).
countintRecords currently retained, already excluding the deleted ones.
bytesintCurrently retained payload bytes, already excluding the deleted ones.
performanceobjectTiming block.

Errors

error.codeHTTPWhen
invalid_request400Neither before_seq nor match supplied; a malformed match tuple; a match op outside {Eq, Glob}; or a Glob pattern without a trailing *.
topic_not_found404The topic does not exist (delete never auto-creates).

See also

Last updated on