API reference: the immut agent API v1
This is the curated endpoint set that covers the entire proof lifecycle: create a proof from a hash, poll it, download the certificate, and verify publicly. It is deliberately small. The full interactive reference for every other endpoint (folders, users, billing, key management) lives at app.immut.io/docs.
Base URL: https://backend.immut.io/api/v1
CORS-open mirror (for browser-based callers): https://backend.immut.io/api/public/v1
Machine-readable version of this page: GET https://backend.immut.io/api/v1/docs (no auth) and /docs/openapi.json
How do I authenticate?
Every authenticated endpoint takes a Bearer token:
Authorization: Bearer imut_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Keys are created by a human account owner at app.immut.io/account?tab=api-keys (Professional and Enterprise plans include API access) and carry scopes. Agents should hold documents:write and certificates:read only. Rate limits: 60 requests per minute, 10,000 per day per key; a 429 response carries a Retry-After header.
Proofs created by paid organisations anchor to XRPL mainnet and are permanent.
POST /proofs
Create a proof from a locally computed SHA-256 hash. The file itself is never uploaded. Requires scope documents:write. Idempotent per hash and workspace.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
hash | string | yes | 64-character hex SHA-256 digest of the file |
workspace | string | yes | Workspace id (see GET /workspaces) |
fileName | string | no | Display name, max 255 chars |
fileSize | number | no | Bytes |
mimeType | string | no | Defaults to application/octet-stream |
metadata | object | no | metadata.description (max 500 chars) appears on listings |
Response 201
{
"success": true,
"data": {
"proofId": "6a55f4b3f8878465844f8b43",
"txHash": "02790DA05EF2999C77A2B462CE0F7A1E11A52FB295F3AE3FF542112B12B7A8E5",
"verifyUrl": "https://livenet.xrpl.org/transactions/.../detailed",
"certPath": "/api/v1/certificates/6a55f4b3f8878465844f8b43",
"ledger": "mainnet",
"ledgerIndex": 105588998,
"timestamp": "2026-07-14T08:34:59.412Z",
"hashScheme": "hmac-sha256-nonce-v3",
"proofCommitment": "64-char hex anchored on-chain",
"proofNonce": "64-char hex, KEEP THIS: required to verify a salted proof"
}
}
If the hash was already proven in that workspace, the response is 200 with "alreadyProven": true and the same data shape. Store proofNonce durably; it is confidential to the file owner and required for verification under the default salted scheme (see Security).
Errors: 400 INVALID_HASH, 400 INVALID_WORKSPACE, 401, 403 API_ACCESS_DISABLED, 429, 502 XRPL_ERROR (safe to retry: the failed attempt is rolled back).
GET /proofs/{proofId}
Poll a proof's status and details. Requires scope documents:read. Add ?includeSalt=true to include proofNonce in the response.
Response 200
{
"success": true,
"data": {
"proofId": "6a55f4b3f8878465844f8b43",
"txHash": "0279...A8E5",
"verifyUrl": "https://livenet.xrpl.org/transactions/.../detailed",
"certPath": "/api/v1/certificates/6a55f4b3f8878465844f8b43",
"ledger": "mainnet",
"ledgerIndex": 105588998,
"timestamp": "2026-07-14T08:34:59.412Z",
"blockchainStatus": "completed",
"fileName": "report-final.pdf",
"fileHash": "d287...ff6b",
"hashScheme": "hmac-sha256-nonce-v3",
"proofCommitment": "9f2c...b9c"
}
}
blockchainStatus is pending, processing, or completed. Errors: 400 INVALID_PROOF_ID, 404 PROOF_NOT_FOUND.
GET /certificates/{proofId}
Download the court-ready certificate PDF for a proof. Requires scope certificates:read. The PDF includes the transaction hash, ledger details, verification guide, and (for salted proofs) the proof salt/nonce.
curl -s https://backend.immut.io/api/v1/certificates/$PROOF_ID \
-H "Authorization: Bearer $IMMUT_API_KEY" \
-o certificate.pdf
GET /api/public/verify/{txHash}
Public keyless verification. Full URL: https://backend.immut.io/api/public/verify/{txHash}. Returns the on-chain record for any immut transaction hash, resolving the correct ledger network per proof.
Response 200
{
"success": true,
"data": {
"transactionHash": "0279...A8E5",
"network": "mainnet",
"verified": true,
"explorerUrl": "https://livenet.xrpl.org/transactions/.../detailed",
"ledgerIndex": 105588998,
"ledgerCloseTime": "2026-07-14T08:35:02.000Z",
"memo": { "fileHash": "...", "hashScheme": "hmac-sha256-nonce-v3" }
}
}
To confirm a file matches: recompute sha256(file); if memo.hashScheme is sha256-plain-v1, compare directly with memo.fileHash; if it is a salted scheme, compute HMAC-SHA-256(key=proofNonce, message=sha256 digest bytes) and compare. The browser page at app.immut.io/verify does this without any tooling.
GET /workspaces
List the organisation's workspaces. Requires scope workspaces:read. Used once during setup to find the workspace id for POST /proofs.
{ "success": true, "data": [ { "_id": "6a343b4d0de29d485cd1f710", "name": "Default Workspace" } ] }
GET /documents
List existing proofs with pagination and filters. Requires scope documents:read. Query params: page (default 1), limit (default 20, max 100), workspace, blockchainStatus, search. Response carries data (array) and meta (page, limit, total).
Webhooks: GET /webhooks, POST /webhooks
Get notified instead of polling. Requires scope webhooks:manage.
POST body: { "url": "https://your-endpoint", "events": ["upload.completed", "certificate.generated"], "description": "optional" }
Available events include document.created, upload.completed, upload.failed, certificate.generated, workspace.created. The response includes a signing secret (shown once) used to HMAC-sign deliveries. URLs must be HTTPS in production. POST /webhooks/test sends a test delivery; GET /webhooks/deliveries lists recent deliveries.
GET /docs
https://backend.immut.io/api/v1/docs, no auth. Machine-readable JSON quickstart covering this whole surface: base URLs, auth, endpoint skeletons, rate limits, verification recipes, and security notes. Agents that only have the API base URL can bootstrap from it.
What is deliberately not in this reference?
Multipart file upload. immut's agent contract is hash-only: file bytes never leave your environment, which is the property that makes the privacy model work. Humans can upload via the app at app.immut.io; the full endpoint catalogue is at app.immut.io/docs.