Documents
Upload, import, list, download, verify, certificates, and timestamps
All routes require a Clerk Bearer token and are scoped to the active tenant.
The document object
{
"id": "abc123xyz",
"serialNumber": "JAT-7K2M9",
"fileName": "contrato.pdf",
"fileSize": 45023,
"mimeType": "application/pdf",
"sha256Hash": "a1b2c3...",
"sourceType": "upload",
"sourceUri": null,
"screenshot": null,
"onchainStatus": "registered",
"onchainTxHash": "0x...",
"onchainAttestationUid": "0x...",
"onchainAt": "2026-05-01T12:01:00.000Z",
"stacksStatus": "registered",
"stacksTxId": "...",
"stacksAnchoredAt": "2026-05-01T12:30:00.000Z",
"consentGiven": true,
"consentTimestamp": "2026-05-01T12:00:00.000Z",
"createdAt": "2026-05-01T12:00:00.000Z",
"published": false,
"publishedAt": null,
"acervoTitle": null,
"acervoAuthor": null,
"metadata": null
}sourceType is one of upload, ipfs, fileverse, web-capture. screenshot is a presigned preview URL, only for web captures.
POST /api/documents/upload
Upload via multipart/form-data. Consent is mandatory (LGPD Art. 7º I) — send consent=true as a form field alongside the file. Max 250 MB, 10 req/min. In an organization, requires editor or higher.
curl -X POST https://jatoba-web3-production.up.railway.app/api/documents/upload \
-H "Authorization: Bearer $CLERK_TOKEN" \
-F "file=@contrato.pdf" \
-F "consent=true"201 — the document object. Anchoring on both chains starts in the background (onchainStatus/stacksStatus begin as pending). 400 missing file or consent, 403 insufficient org role.
POST /api/documents/import/ipfs
Fetches a file from the configured IPFS gateway, hashes it, and registers a reference-only record (sourceType: "ipfs") — the bytes are not copied to R2.
| Body field | Type | Description |
|---|---|---|
cid | string (required) | Bare IPFS CID (v0 Qm... or v1 base32) |
fileName | string | Display name, defaults to the CID |
consent | boolean (required) | Must be true |
201 document object · 400 invalid CID / missing consent · 413 over 250 MB · 502 gateway failure.
GET /api/documents
Lists the active tenant's non-deleted documents, newest first.
200 — { "documents": [Document] }
GET /api/documents/:id
Single document. 403 when outside your tenant, 404 when missing.
200 — { "document": Document }
PATCH /api/documents/:id/publish
Publishes/unpublishes a document on the tenant's public acervo feed. While publishing you may set curator copy — only fields actually sent are rewritten:
| Body field | Type | Description |
|---|---|---|
published | boolean (required) | Target state |
title | string | Acervo display title (falls back to file name) |
author | string | Acervo display author |
metadata | string | Free-form metadata string |
200 { "document": Document } · 410 when LGPD-deleted. Requires editor+ in an org.
GET /api/documents/:id/download
Presigned download URL (5 min). R2 downloads force attachment disposition and a neutral MIME so stored XSS can't execute; IPFS imports resolve to a gateway URL.
200
{ "downloadUrl": "https://...", "sha256": "a1b2c3...", "expiresInSeconds": 300 }410 when the document was deleted via LGPD (the hash stays on record).
GET /api/documents/:id/view
Presigned inline view URL for browser tabs. Safe types (PDF, PNG/JPEG/GIF/WebP, plain text) render inline with their real Content-Type; anything else falls back to forced attachment.
200 — { "viewUrl": "https://...", "inline": true, "expiresInSeconds": 300 }
GET /api/documents/:id/verify
Compares a provided hash against the stored one.
| Query param | Type | Description |
|---|---|---|
hash | string (required) | SHA-256 to check |
200
{
"documentId": "abc123xyz",
"serialNumber": "JAT-7K2M9",
"hashMatches": true,
"storedHash": "a1b2c3...",
"providedHash": "a1b2c3..."
}GET /api/documents/:id/certificate
Generates the notarization certificate (comprovante) PDF: QR code to the permanent EAS attestation, the SHA-256, the full web3 proof, and a compliance section. When the source is a PDF, every page is stamped "Notarized with Jatobá" and the certificate page is appended — the original file in R2 is never modified.
| Query param | Description |
|---|---|
signed=1 | PAdES-sign the certificate (ICP-Brasil compatible) when a signing certificate is configured; falls back to unsigned otherwise |
Returns application/pdf as an attachment. The X-Jatoba-Signed header is pades or none.
POST /api/documents/:id/timestamp
Requests an RFC 3161 trusted timestamp over the document's SHA-256 from the configured Time-Stamping Authority. Returns the DER token (application/timestamp-reply, .tsr attachment), verifiable with openssl ts -verify — independent proof of anteriority alongside the on-chain anchors.
503 when no TSA is configured · 502 when the TSA request fails. 10 req/min.