Records and entries
The words the API and the Shared Record use: record, entry, lifecycle, seal, receipt, history file, statement, and the checker.
A record
A record is one thing a machine did or produced: one agent run, one model build, one pull request, one document. You name it with record, your own id for it, and every entry about the same thing uses the same id. There is no call to create a record; the first entry creates it, and the first entry's title is the record's name. That name is stored once, when the first entry creates the record, and it never changes; a later entry that corrects the first one does not rename it. It is what the records list, the Shared Record, and the printed statement call the record, so give the first entry a title that names the thing. Later entries record what happened to it.
Inside PacSpace a record also has a recordKey, a fixed value derived from your workspace and your id. It appears in receipts, in the history file, and on the Shared Record, and it is what other entries use to refer to this record.
An entry
An entry is one event in a record's life, numbered from 1 in the order the entries were committed: the first entry is Entry 1, on the record page, on the Shared Record, on the statement, and in the SDKs, where the number is called entry. On the wire the same position is seq, counted from 0, in the receipt path, the history file, and the webhook payloads; seq is entry - 1, and the SDKs convert for you. An entry carries:
| Field | What it is |
|---|---|
title | What this entry records, in your words. At most 120 characters. This is what a person reads in the list. |
occurredAt | When it happened, in UTC: when the machine acted. The time of your call is recorded on its own. |
actorId | Who or what did it: an agent, a service, a person, named by you. |
payloads | The fingerprints of the files this entry is about. At least one. |
kind | Optional. Your own short word for the sort of thing this is, lower case with hyphens: model-build, ticket-close, approval. |
instructedBy | Optional. Who told the actor to do it, when you track that. |
description, note | Optional. A few sentences sealed with the entry. |
references | Optional. Entries of other records this one refers to, each as { recordKey, entry }. Each must already be committed in your workspace. |
amends | Optional. The committed entry this one corrects, as { recordKey, entry }, with lifecycle: amended. See Correcting an entry. |
All of this is sealed. Only someone with a receipt, a history file, or the Shared Record link can read it. What anyone can read from the record without those is the entry number and its lifecycle word, and nothing else: not the title, not the time, not who acted, not a single fingerprint.
Lifecycle
Each entry names a lifecycle state: recorded, amended, or closed. A record opens with recorded, and the SDKs send that for you. amended marks a correction: nothing in a record is edited, so a correction is a later entry that names the entry it corrects, and both stay visible. An amendment is a new entry. This one stays as it was written. closed is final. An entry sent after closed is recorded as an attempt, marked so, and the record's state does not move. That way the record shows that something tried to write after the close, which is often the point.
Record type
A record type is the shape an entry takes. The general shape, machine-action-record, carries the fields above and fits everything on What you can record. The SDKs use it by default, so you never type it. Your own vocabulary goes in kind.
Queued, committed, failed
A write is answered at once with status: QUEUED. Committed follows: from then on the entry shows committed in the history, and record.committed arrives at your webhook. If a queued entry cannot be committed, it shows failed with a code and a plain sentence, and record.failed arrives. A write that did not land is always reported.
One idempotency key is one write. Send a new key for every entry and reuse one only to retry the same entry; a repeat of a finished key returns the original answer.
The seal
When an entry is committed, PacSpace commits a seal over the sealed record: a fixed value that the entry's fields reproduce and that nothing else does. Change one character of the entry and the seal no longer matches. The check is the act of recomputing the seal from what you hold and comparing it with what was committed.
The receipt
Each committed entry has a receipt: the sealed record as it was committed, its seal, and what the check needs to compare the two. records.receipt({ record, entry }) fetches one.
The history file
records.history({ record }) returns the record's history file: every entry with its status, and each committed entry's receipt. It is the file the Shared Record's browser check runs on, the file the standalone checker takes, and the file the other side downloads to keep. It carries its own fingerprint, so a copy that was changed after it was exported no longer produces it.
The statement and the checker
A daily statement covers every entry committed up to that day. A printed statement names the record, the day, and the history file's fingerprint, so a reader who was handed paper can check the record later with npx @pacspace-io/check history.json --fingerprint 0x..., with no account and no link. The check shows the record is unchanged since it was committed. It does not show that what was recorded was true.