Skip to main content

Record History

Trace one database record across captures with GET /v1/db-snapshots/sources/:id/history: every change event with full before/after values, newest first.

GET /v1/db-snapshots/sources/:connectionId/history answers "what happened to this specific record over time". Given a table and a primary-key value, it returns every change event the retained deltas recorded for that row — added, modified, or removed, each with full before/after values and the capture it landed in — plus the row's current stored values from the latest ready snapshot's corpus. It is the drill-down behind a changed row: from any change you can pivot to the record's whole life.

Both query parameters are required — the route rejects a missing table or pk with a 400 rather than guessing. table is the stable table key: `schema.table` (for example public.customers), except on MySQL where it is the bare table name (MySQL schemas are databases, so the connection already pins one). pk is the rendered primary-key value exactly as it appears in change rows and history events — for composite keys, the same joined rendering the delta surface shows.

Events come back newest first and are capped at 100: the response always carries events_total (how many exist) and events_truncated (whether the cap cut the list), so a long history is never silently short. The cap exists because this surface feeds agents — a row touched by every nightly capture accumulates events without bound, and the newest ones are the ones that answer "what happened to this record". identity_columns names the columns that form the row's identity, so you can reconstruct how pk was rendered.

Events only include changes from servable captures: a failed capture's partial change rows are not history, unless the capture was incremental and its corpus mutations actually applied. current is null when the row does not exist in the latest corpus — which is exactly what you expect after a removed event, and is itself information: history plus a null current row is a deletion story, not a gap.

Use history when you already know which record you care about; use the delta changes endpoint when you are sweeping what changed in a capture. The two return the same before/after shapes, so a consumer can share its diff-rendering code between them.
GET/v1/db-snapshots/sources/:connectionId/history

Query parameters

table*stringThe table key: schema.table (e.g. public.customers); on MySQL sources, the bare table name. Missing → 400.
pk*stringThe rendered primary-key value, exactly as it appears in change rows. Missing → 400.

curl

curl -s "https://api.talonic.com/v1/db-snapshots/sources/8d2f1c4a-6b3e-4f7d-9a1c-5e8b2d4f6a0c/history?table=public.customers&pk=10442" \
  -H "Authorization: Bearer tlnc_your_api_key"

Response (200)

{
  "table_key": "public.customers",
  "pk": "10442",
  "current": {
    "id": 10442,
    "name": "Acme GmbH",
    "status": "active",
    "credit_limit": 75000
  },
  "identity_columns": ["id"],
  "events": [
    {
      "delta_id": "b4c6e8a0-1d3f-4b5c-9e7a-2f4d6b8c0e1a",
      "snapshot_id": "3f9a7b1d-2c4e-4a6f-8b0d-1e3c5a7f9b2d",
      "captured_at": "2026-08-29T02:00:04.221Z",
      "change_type": "modified",
      "before": { "id": 10442, "name": "Acme GmbH", "status": "active", "credit_limit": 50000 },
      "after": { "id": 10442, "name": "Acme GmbH", "status": "active", "credit_limit": 75000 }
    },
    {
      "delta_id": "7a9c1e3f-5b7d-4a2e-8c4a-6f0b2d4e6c8a",
      "snapshot_id": "9e1c3a5f-7b9d-4e2c-8a4f-6b0d2e4c6a8f",
      "captured_at": "2026-08-12T02:00:02.874Z",
      "change_type": "added",
      "before": null,
      "after": { "id": 10442, "name": "Acme GmbH", "status": "active", "credit_limit": 50000 }
    }
  ],
  "events_total": 2,
  "events_truncated": false
}

Errors

Error responses

400VALIDATION_ERRORMissing table or pk ("Both `table` and `pk` are required."), or a master-view credential.
401unauthorizedMissing or invalid API key.
404RESOURCE_NOT_FOUNDThe connection does not exist in your workspace or is not snapshot-capable. An unknown table/pk pair is not an error — it returns an empty events list with current: null.

Frequently asked questions

How do I write the table parameter for my engine?+
Use the stable table key the delta surface reports: schema-qualified schema.table on Postgres and SQL Server (e.g. public.customers, dbo.orders), and the bare table name on MySQL, where the connection already pins one database. The easiest source of a correct key is the table_key field on any delta or change row.
What does a composite primary key look like in pk?+
The pk parameter takes the rendered identity value exactly as change rows carry it — for composite keys, the joined rendering of the identity columns in capture order. Read identity_columns on the response (or the table's entry in a delta) to see which columns participate, and copy pk values from change rows rather than constructing them by hand.
Why is events_total larger than the number of events returned?+
The response caps events at 100, newest first, and events_truncated: true marks the cut. The cap keeps the surface safe to feed into agent context windows; a record's recent behaviour is fully covered, and the totals tell you honestly that an older tail was dropped rather than pretending the list is complete.
Can current disagree with the newest event's after value?+
Briefly, yes: current reads the latest ready snapshot's corpus, so while a capture is running, current still reflects the previous corpus even though a partial delta may already record newer changes. Once the capture completes, the two converge. For a consistent pair, read history after the source's capturing flag returns to false.