REST API Reference¶
PrimeStamp exposes a FastAPI-based REST API for document stamping, verification, and fingerprinting. Interactive documentation is available at /docs (Swagger UI) and /redoc (ReDoc) when the server is running.
Starting the Server¶
Authentication¶
Requests are identified by API key or client IP. Include your key in one of these headers:
| Header | Format |
|---|---|
Authorization |
Bearer ps_live_... or Bearer ps_test_... |
X-API-Key |
ps_live_... or ps_test_... |
Unauthenticated requests fall back to IP-based identification and receive the anonymous rate-limit tier. See Rate Limiting for tier details.
Health¶
GET /health¶
Returns server health status.
Response (HealthResponse):
GET /¶
API root with navigation links.
{
"name": "PrimeStamp API",
"version": "0.1.0",
"docs": "/docs",
"health": "/health",
"dashboard": "/dashboard"
}
Stamps¶
POST /stamps¶
Create a new document stamp. Upload a file as multipart form data.
Parameters (form/query):
| Parameter | Type | Default | Description |
|---|---|---|---|
file |
UploadFile |
required | Document to stamp |
preset |
string |
null |
casual, standard, archival, or maximum |
anchors |
string |
null |
Comma-separated anchor types (e.g. bitcoin,ethereum) |
trust_threshold |
int |
5 |
Minimum trust score required |
version |
string |
1.0.0 |
Document version |
generate_fp |
bool |
false |
Generate a Prime-Space fingerprint |
identity_id |
string |
null |
Identity for signing |
Example (curl):
curl -X POST http://localhost:8800/stamps \
-F "file=@document.pdf" \
-F "preset=standard" \
-F "generate_fp=true"
Response (StampResponse):
{
"stamp_id": "a1b2c3d4-...",
"created_at": "2026-04-10T12:00:00+00:00",
"document_hash": "abc123...",
"hash_algorithm": "sha3-256",
"author_public_key": "ed25519:...",
"is_signed": true,
"anchors_requested": ["bitcoin", "ethereum"],
"trust_score": 9,
"trust_threshold": 5,
"trust_met": true,
"has_fingerprint": true,
"stamp_json": { ... }
}
GET /stamps/{stamp_id}¶
Retrieve a stamp by its ID.
Returns the same StampResponse structure.
POST /stamps/{stamp_id}/verify¶
Verify a stored stamp, optionally against the original document content.
Parameters:
| Parameter | Type | Description |
|---|---|---|
stamp_id |
string (path) |
Stamp ID to verify |
file |
UploadFile (optional) |
Original document for content hash verification |
Response (VerifyResponse):
{
"is_valid": true,
"signature_valid": true,
"content_hash_valid": true,
"trust_score": 9,
"trust_threshold": 5,
"trust_met": true,
"confirmed_anchors": 2,
"pending_anchors": 0,
"details": { ... }
}
POST /verify¶
Verify a stamp from raw JSON (without needing a stored stamp).
Request body (VerifyRequest):
Optionally include a file upload for content hash verification. Response is the same VerifyResponse.
Fingerprints¶
POST /fingerprint¶
Generate a Prime-Space fingerprint for a document.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
file |
UploadFile |
required | Document to fingerprint |
method |
string |
hierarchical |
Decomposition method: hierarchical, flat, content_addressed, semantic |
Response (FingerprintResponse):
{
"standard_hash": "sha3-256:abc123...",
"merkle_root": "def456...",
"chunk_count": 12,
"tree_depth": 4,
"shadow_scales": [2, 3, 5, 7, 11, 13],
"entropy": 4.23,
"decomposition_method": "hierarchical",
"proofs_available": ["existence", "structure", "similarity"],
"fingerprint_json": { ... }
}
POST /fingerprint/compare¶
Compare two fingerprints for structural similarity.
Request body (CompareRequest):
Response (CompareResponse):
{
"similarities": {
"2": 0.95,
"3": 0.91,
"5": 0.88,
"7": 0.82,
"11": 0.79,
"13": 0.76
},
"overall_similarity": 0.85,
"assessment": "Similar - documents share significant structure"
}
Similarity assessments:
| Range | Assessment |
|---|---|
| >= 0.9 | Very similar -- likely same or nearly identical documents |
| >= 0.7 | Similar -- documents share significant structure |
| >= 0.5 | Somewhat similar -- some structural overlap |
| < 0.5 | Different -- documents have distinct structure |
POST /fingerprint/proof¶
Generate a partial proof from a fingerprint.
Request body (ProofRequest):
Supported proof types:
| Proof Type | Required Fields | Description |
|---|---|---|
existence |
section_index |
Prove a section exists without revealing content |
structure |
scale (default 7) |
Reveal structure at a shadow resolution |
similarity |
reference_fingerprint |
Prove similarity to another document |
GET /fingerprint/{stamp_id}/shadow/{scale}¶
Get the shadow transform at a specific prime scale for a stamped document.
{
"scale": 7,
"resolution": "14%",
"length": 128,
"hash": "abc123...",
"values": [42, 17, 89, ...]
}
Identity¶
POST /identity¶
Generate a new Ed25519 signing identity.
Response (IdentityResponse):
GET /identity/{identity_id}¶
Retrieve identity information. The identity_id is the first 16 hex characters of the public key.
Configuration¶
GET /presets¶
List all available stamp presets.
[
{
"name": "casual",
"description": "...",
"storage_mode": "local",
"encryption": "none",
"anchors": ["rfc3161"],
"trust_threshold": 2
},
...
]
GET /presets/{name}¶
Get details for a specific preset (casual, standard, archival, maximum).
Utilities¶
POST /hash¶
Hash a document without creating a stamp.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
file |
UploadFile |
required | Document to hash |
algorithm |
string |
sha3-256 |
sha3-256, sha256, or blake3 |
Error Responses¶
All errors return a JSON body with a detail field:
| Status Code | Meaning |
|---|---|
400 |
Bad request -- invalid parameters or processing error |
404 |
Resource not found |
429 |
Rate limit exceeded (see Rate Limiting) |
Verification Portal¶
PrimeStamp provides a public verification portal where anyone can verify a stamp by visiting its URL. The portal is served at /verify/{stamp_id} and does not require authentication.
Verification URL Format¶
The base URL is configurable via the PRIMESTAMP_BASE_URL environment variable. In self-hosted deployments, set this to your own domain:
GET /verify/{stamp_id}¶
Renders an HTML page showing the stamp's verification status, document hash, anchor timeline, and trust score. This page is designed for sharing with third parties who need to confirm document authenticity without installing PrimeStamp.
The portal is implemented in primestamp/web/verify_portal.py and can be deployed alongside the API server or as a standalone service.
Vault¶
The Vault API provides dead man's switch key escrow. Vaults hold encrypted keys that are released when heartbeat deadlines expire or upon manual release.
POST /vault/create¶
Create a new vault.
Request body (CreateVaultRequest):
{
"encrypted_key": "<base64-encoded encrypted key>",
"heartbeat_deadline": 259200,
"content_uris": ["ipfs://Qm...", "arweave://tx123"],
"allow_manual_release": true,
"metadata": {
"label": "project-keys"
}
}
| Field | Type | Required | Description |
|---|---|---|---|
encrypted_key |
string (base64) |
yes | The encrypted key material to escrow |
heartbeat_deadline |
int |
yes | Seconds until release if no heartbeat is received |
content_uris |
string[] |
no | URIs pointing to the encrypted content (IPFS, Arweave, S3, etc.) |
allow_manual_release |
bool |
no | Whether the vault owner can trigger early release (default false) |
metadata |
object |
no | Arbitrary key-value metadata |
Response (VaultResponse):
{
"id": "vault-a1b2c3d4...",
"state": "active",
"created_at": "2026-04-10T12:00:00+00:00",
"deadline": "2026-04-13T12:00:00+00:00",
"content_uris": ["ipfs://Qm...", "arweave://tx123"],
"allow_manual_release": true,
"metadata": {"label": "project-keys"}
}
POST /vault/{id}/heartbeat¶
Submit a heartbeat to extend the vault deadline. A mandatory fee is required with each heartbeat.
Path parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string |
Vault ID |
Request body (HeartbeatRequest):
Response (HeartbeatReceipt):
{
"vault_id": "vault-a1b2c3d4...",
"heartbeat_at": "2026-04-11T12:00:00+00:00",
"next_deadline": "2026-04-14T12:00:00+00:00",
"fee_amount": "0.001",
"fee_currency": "ETH"
}
POST /vault/batch-heartbeat¶
Submit heartbeats for multiple vaults in a single request.
Request body (BatchHeartbeatRequest):
{
"vault_ids": ["vault-aaa...", "vault-bbb...", "vault-ccc..."],
"fee_receipt": "tx_receipt_batch456"
}
Response (BatchHeartbeatResult):
{
"renewed": 3,
"failed": 0,
"results": [
{"vault_id": "vault-aaa...", "next_deadline": "2026-04-14T12:00:00+00:00"},
{"vault_id": "vault-bbb...", "next_deadline": "2026-04-14T12:00:00+00:00"},
{"vault_id": "vault-ccc...", "next_deadline": "2026-04-14T12:00:00+00:00"}
],
"errors": []
}
GET /vault/{id}¶
Get the current status of a vault.
Path parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string |
Vault ID |
Response (VaultResponse):
{
"id": "vault-a1b2c3d4...",
"state": "active",
"created_at": "2026-04-10T12:00:00+00:00",
"deadline": "2026-04-14T12:00:00+00:00",
"last_heartbeat": "2026-04-11T12:00:00+00:00",
"heartbeat_count": 2,
"content_uris": ["ipfs://Qm...", "arweave://tx123"],
"allow_manual_release": true,
"metadata": {"label": "project-keys"}
}
Vault states: active, released, burned, expired.
POST /vault/{id}/release¶
Manually release the vault key. Only available when allow_manual_release was set to true at creation.
Path parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string |
Vault ID |
Request body (ReleaseRequest):
Response (ReleaseResult):
{
"vault_id": "vault-a1b2c3d4...",
"released": true,
"released_at": "2026-04-11T15:00:00+00:00",
"reason": "Project handover"
}
POST /vault/{id}/retrieve¶
Retrieve the escrowed key from a released or expired vault.
Path parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string |
Vault ID |
Request body (RetrieveRequest):
Response (RetrievedKey):
{
"vault_id": "vault-a1b2c3d4...",
"encrypted_key": "<base64-encoded encrypted key>",
"released_at": "2026-04-11T15:00:00+00:00"
}
GET /vault/list¶
List vaults belonging to the authenticated user.
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
state |
string |
null |
Filter by state: active, released, burned, expired |
limit |
int |
50 |
Maximum number of results |
offset |
int |
0 |
Pagination offset |
Response (VaultList):
{
"items": [
{
"id": "vault-a1b2c3d4...",
"state": "active",
"deadline": "2026-04-14T12:00:00+00:00",
"heartbeat_count": 2
}
],
"total": 1,
"limit": 50,
"offset": 0
}
POST /vault/group/create¶
Create a heartbeat group to manage multiple vaults with a shared schedule.
Request body (HeartbeatGroupRequest):
Response (HeartbeatGroup):
{
"id": "group-xyz789...",
"name": "production-vaults",
"vault_ids": ["vault-aaa...", "vault-bbb..."],
"interval": 172800,
"created_at": "2026-04-10T12:00:00+00:00"
}
GET /vault/fees¶
Get current vault fee schedule.
Response (VaultFees):
{
"create_fee": "0.005",
"heartbeat_fee": "0.001",
"batch_discount": "0.10",
"currency": "ETH",
"fee_recipient": "0xabc..."
}
POST /vault/{id}/add-mirror¶
Add a content URI mirror to an existing vault for redundant storage.
Path parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string |
Vault ID |
Request body:
Response:
{
"vault_id": "vault-a1b2c3d4...",
"content_uris": ["ipfs://Qm...", "arweave://tx123", "s3://bucket/backup-key.enc"]
}
Explorer¶
The Explorer API provides public read-only access to vault and network statistics.
GET /explorer/api/vaults¶
List publicly visible vaults.
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
int |
100 |
Maximum number of results |
offset |
int |
0 |
Pagination offset |
state |
string |
null |
Filter by state |
Response:
{
"items": [
{
"id": "vault-a1b2c3d4...",
"state": "active",
"created_at": "2026-04-10T12:00:00+00:00",
"deadline": "2026-04-14T12:00:00+00:00",
"heartbeat_count": 2
}
],
"total": 250,
"limit": 100,
"offset": 0
}
GET /explorer/api/stats¶
Get aggregate network statistics.
Response:
{
"active_vaults": 1523,
"total_vaults": 4210,
"total_heartbeats": 89432,
"total_releases": 312,
"total_burns": 45,
"total_fees_collected": "42.5",
"fee_currency": "ETH"
}
CORS¶
The server enables CORS for all origins by default. Configure allow_origins in production.