Seals
A seal is a snapshot of a document as it stood, with the record of how it was written and the numbers that come from it: where its words came from, whether a person was present, how many prompts and sittings it took. Each seal has a short page at proof.exalto.ai that anyone with the link can open, unless its owners made its seals private, and a seal line people paste wherever the text goes. A seal never changes once it’s made; sealing again adds a new version. See Seals.
People can also seal from the Seal button in the editor. Either way, Proof sends seal.created to your webhook endpoints.
The seal object
Section titled “The seal object”| Attribute | Type | Description |
|---|---|---|
code |
string | Nine capital letters and digits. Test seals start with T. |
url |
string | The seal’s page: https://proof.exalto.ai/ and the code. |
version |
integer | 1 for the document’s first seal, then 2, 3 and so on. |
sealed_at |
timestamp | When it was sealed. |
sealed_by |
string | The Proof id of the owner who sealed it. |
document |
string or null | The document’s id, or null once the document was deleted. |
method |
string or null | The version of the method its numbers were worked out with. They never change; under a newer method, the seal page shows a labeled reassessment beside them. This and the numbers below are null once the seal is withdrawn. |
line |
string or null | The seal line, ready to paste. |
composition |
object | Percentages of the document by where its words came from, summing to 100: typed, shaped, ai and external. |
presence |
object | share: percent of session time with a person present. verified_share: the part vouched for by check-ins. verified: true when every sitting people wrote in was verified. |
prompts |
integer | Rounds of back-and-forth with agents. |
sittings |
integer | Separate stretches of work. The seal line calls them sessions. |
duration |
string | Session time across those sittings, as the seal line writes it, such as 1hr48min. |
attested_by |
object | Who vouches for the people named in it. platform: your platform’s slug. key_ids: the ids of the secret keys that started its writing sessions. |
withdrawn_at |
timestamp or null | When it was withdrawn, or null. |
{ "code": "AH271NSHS", "url": "https://proof.exalto.ai/AH271NSHS", "document": "doc_8Hq2Lm4R", "version": 1, "sealed_at": "2026-10-13T23:31:04Z", "sealed_by": "usr_5Kq2Lm8R", "method": "v0.2", "line": "proof.exalto.ai/AH271NSHS · 87% typed/shaped · 8% AI · 5% external · 4 prompts · 2 sessions, 1hr48min", "composition": { "typed": 71, "shaped": 16, "ai": 8, "external": 5 }, "presence": { "share": 97, "verified_share": 0, "verified": false }, "prompts": 4, "sittings": 2, "duration": "1hr48min", "attested_by": { "platform": "acme", "key_ids": ["key_2Lq9Wd4T"] }, "withdrawn_at": null}When every sitting people wrote in was verified by check-ins, the line ends (verified); when some were, it ends with the share, such as (73% verified).
Seal a document
Section titled “Seal a document”POST /v1/documents/{document_id}/seals
Seals the document as it stands now, as a new version. A document with pending suggestions can’t be sealed: a seal says what the document says, so they’re accepted or rejected first.
| Parameter | Type | Description |
|---|---|---|
document_id |
string, path, required | The document’s id. |
user |
string, required | The Proof id of the person sealing it. They must be one of the document’s owners. |
curl https://api.proof.exalto.ai/v1/documents/doc_8Hq2Lm4R/seals \ -H "Authorization: Bearer $PROOF_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{"user": "usr_5Kq2Lm8R"}'const seal = await proof.seals.create("doc_8Hq2Lm4R", { user: "usr_5Kq2Lm8R" });console.log(seal.line);Returns the seal with 201.
| Error | When |
|---|---|
403 not_owner |
user isn’t one of the document’s owners. |
409 document_empty |
Nothing has been written in the document. |
409 document_trashed |
The document is in the trash. |
409 open_suggestions |
The document has pending suggestions. |
409 unchanged |
It reads exactly as its newest seal still up. |
List a document’s seals
Section titled “List a document’s seals”GET /v1/documents/{document_id}/seals
Every seal made from a document, newest first, withdrawn ones included.
| Parameter | Type | Description |
|---|---|---|
document_id |
string, path, required | The document’s id. |
limit |
integer | 1 to 100. Default 50. |
after |
string | The next cursor from the previous page. |
curl https://api.proof.exalto.ai/v1/documents/doc_8Hq2Lm4R/seals \ -H "Authorization: Bearer $PROOF_SECRET_KEY"const page = await proof.seals.list("doc_8Hq2Lm4R");{ "data": [ { "code": "AH271NSHS", "url": "https://proof.exalto.ai/AH271NSHS", "document": "doc_8Hq2Lm4R", "version": 1, "sealed_at": "2026-10-13T23:31:04Z", "sealed_by": "usr_5Kq2Lm8R", "method": "v0.2", "line": "proof.exalto.ai/AH271NSHS · 87% typed/shaped · 8% AI · 5% external · 4 prompts · 2 sessions, 1hr48min", "composition": { "typed": 71, "shaped": 16, "ai": 8, "external": 5 }, "presence": { "share": 97, "verified_share": 0, "verified": false }, "prompts": 4, "sittings": 2, "duration": "1hr48min", "attested_by": { "platform": "acme", "key_ids": ["key_2Lq9Wd4T"] }, "withdrawn_at": null } ], "next": null}Retrieve a seal
Section titled “Retrieve a seal”GET /v1/seals/{code}
Looks a seal up by its code, such as one a reader pasted into your product. You can only retrieve seals made on your platform; anyone can open a public seal’s page at proof.exalto.ai.
| Parameter | Type | Description |
|---|---|---|
code |
string, path, required | The seal’s code. Case doesn’t matter. |
curl https://api.proof.exalto.ai/v1/seals/AH271NSHS \ -H "Authorization: Bearer $PROOF_SECRET_KEY"const seal = await proof.seals.retrieve("AH271NSHS");Returns the seal, or 404 seal_not_found.
Withdraw a seal
Section titled “Withdraw a seal”DELETE /v1/seals/{code}
Takes a seal down. Its page then says it was withdrawn, and when, instead of showing the text. A withdrawn seal can’t be brought back, and other versions of the same document stay up. Seals can be withdrawn but never changed.
| Parameter | Type | Description |
|---|---|---|
code |
string, path, required | The seal’s code. |
curl https://api.proof.exalto.ai/v1/seals/AH271NSHS \ -X DELETE \ -H "Authorization: Bearer $PROOF_SECRET_KEY"const seal = await proof.seals.withdraw("AH271NSHS");Returns the seal with withdrawn_at set, and Proof sends seal.withdrawn. Withdrawing a seal that’s already withdrawn returns it unchanged.
While a document is in its owners’ trash, its seals are down: their pages show nothing until it’s restored.
Who reads seals
Section titled “Who reads seals”A document’s owners choose who reads its seals, every version alike, in the editor’s seal dialog (the openSeal method opens it):
- Anyone with the link, the default. Only these seals have a link preview.
- Private: the document’s members; readers the owners list by email, or
*@domainfor everyone at a domain; and, if they set one, whoever has its password.
A private seal’s page asks the reader for the password, or to sign in with your platform, which says who they are with a reader request. Signing in works only when you’ve set a reader URL (reader_url on the platform).
Reader requests
Section titled “Reader requests”A reader request is someone asking to read a private seal, sent to your reader URL with its id, as an agent request is sent to your consent page:
https://acme.com/proof/read?request=srq_4Wn8Kd2PYour page signs the person in, then approves the request from your server with who they are and their verified email, and sends the browser to the redirect_url it returns. Proof lets them in if they’re a member or their email is one of the readers, and remembers them in that browser for 30 days. A request lasts 10 minutes.
Retrieve a reader request
Section titled “Retrieve a reader request”GET /v1/reader-requests/{request_id}
{ "id": "srq_4Wn8Kd2P", "seal": "AH271NSHS", "title": "On the Analytical Engine", "status": "pending", "expires_at": "2026-10-30T18:30:00Z"}status is pending, answered once you’ve approved it, or finished once the reader is back at the seal. Returns 404 request_not_found for an id that isn’t one of yours.
Approve a reader request
Section titled “Approve a reader request”POST /v1/reader-requests/{request_id}/approve
| Parameter | Type | Description |
|---|---|---|
request_id |
string, path, required | The request’s id. |
user |
string, required | The Proof id of the person signed in to your product. |
email |
string or null | Their email, only if you’ve verified it: Proof lets readers in by it. |
curl https://api.proof.exalto.ai/v1/reader-requests/srq_4Wn8Kd2P/approve \ -H "Authorization: Bearer $PROOF_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{"user": "usr_9Tb3Wc1X", "email": "grace@acme.com"}'const { redirect_url } = await proof.readerRequests.approve("srq_4Wn8Kd2P", { user: "usr_9Tb3Wc1X", email: "grace@acme.com",});// then redirect the browser to redirect_url{ "redirect_url": "https://proof.exalto.ai/AH271NSHS/continue?state=Vq2Lk7Tz1Mx9Pw3H" }| Error | When |
|---|---|
404 user_not_found |
The user doesn’t exist. |
409 request_expired |
The request was answered already, or more than 10 minutes have passed. The reader starts again from the seal. |