Filter events and search their text
The language tabs use earlier client interfaces. Check SDK versions and connection setup before running them.
Store structured event fields and index the event text separately. Use a shared ID to reconnect text matches with actor and time fields.
Before you run it: The two writes succeed separately. A successful row write does not prove indexing succeeded.
Use the tenant-scoped HTTP connection described in the connection notes. In these snippets, ORIGINCHAIN_URL is the origin including https://, T is its tenant ID, and OC_TOKEN is its bearer token. Do not append these routes to a different Connect URL format.
- Record the eventSave the actor, action and time under an event ID.
- Index searchable textUse the same ID for the sanitized event description.
- Find the event IDSearch for the words you are investigating.
- Read the evidenceOpen the source event to inspect its actor and time.
Follow the example
- Register the schema.
- Write the event row.
- Index text with the event ID.
- Search and fetch the matching event.
Set up the table
Two indexes: one for "find all events by this actor in this window" and one for global time-range queries.
# audit/events.toml
namespace = "audit"
table = "events"
primary_key = ["id"]
[[columns]]
name = "id"
ty = "str"
required = true
[[columns]]
name = "actor_id"
ty = "str"
required = true
[[columns]]
name = "action"
ty = "str"
required = true
[[columns]]
name = "payload_text"
ty = "str"
[[columns]]
name = "ts_ms"
ty = "u64"
required = true
[[indexes]]
name = "by_actor_and_time"
columns = ["actor_id", "ts_ms"]
[[indexes]]
name = "by_time"
columns = ["ts_ms"]The event row
curl -X POST "$ORIGINCHAIN_URL/v1/tenants/$T/rows/audit.events" \
-H "Authorization: Bearer $OC_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"id": "evt-2026-06-10-00042",
"actor_id": "user.alice",
"action": "schema.update",
"payload_text": "Added column carbon_plate to shop.products",
"ts_ms": 1749500000000
}'The keyword index
Index the sanitized payload text. Same doc_id as the row's primary key so search hits join back to the event.
curl -X POST "$ORIGINCHAIN_URL/v1/tenants/$T/fts/audit.events/payload_text" \
-H "Authorization: Bearer $OC_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"doc_id": "evt-2026-06-10-00042",
"text": "Added column carbon_plate to shop.products"
}'Handle separate writes and retries
These write calls commit separately. The documented SDKs do not provide automatic retry safety. A new SDK call can generate a new key. Retry reads with bounded backoff; for writes, confirm the endpoint supports deduplication and reuse a stable key, or reconcile the previous outcome first. See idempotency.
Important limits and checks
- Indexing PII without redaction. Indexed text remains searchable until its search entry is removed or replaced. Sanitize emails, phone numbers, tokens, internal IDs before calling
db.fts.index- never after. - Mutating audit events. Audit logs should be append-only. Don't re-put the row to "correct" an event - emit a new event that supersedes it.
- Embedding raw JSON in
payload_text. Full-text search splits text into searchable words; raw JSON punctuation does not add useful context. Render the payload as a human sentence first so the index actually has searchable words. - Forgetting an
id. If the row write generates an id server-side and the FTS call uses a different one, search hits won't join back. Set the id client-side (UUID or a sortable like ULID) and use the same string for both calls.
Expected result
Adapt the single-word search to audit.events and the field used above. Search for a word such as column, then read the event row using the returned doc_id. Check its actor, action and timestamp; a text hit alone is not the complete audit event.