Trace & Anchor · Pro API v1
Proof of existence, from your own software
Anchor the fingerprint of any file on the Solana blockchain — optionally with an eIDAS qualified timestamp and a FranceConnect identity attestation — and receive a court-ready certificate and a machine-readable proof. Your files never leave your systems: you send a 64-character digest, nothing else.
FR — Ancrez l'empreinte de vos fichiers depuis vos logiciels ou un simple dossier sur le bureau. Les fichiers ne quittent jamais vos systèmes.
Quickstart
Base URL https://api-traceandanchor.com/api/v1. Create a key in Dashboard → Pro API, top up your wallet, then:
HASH=$(sha256sum invoice.pdf | cut -d' ' -f1) # macOS: shasum -a 256
curl https://api-traceandanchor.com/api/v1/anchors \
-H "Authorization: Bearer $TA_KEY" \
-H "Idempotency-Key: sha256:$HASH" \
-H "Content-Type: application/json" \
-d "{\"file_hash\": \"$HASH\", \"original_filename\": \"invoice.pdf\"}"
curl -OJ -H "Authorization: Bearer $TA_KEY" https://api-traceandanchor.com/api/v1/anchors/<id>/certificate.pdf
curl -OJ -H "Authorization: Bearer $TA_KEY" https://api-traceandanchor.com/api/v1/anchors/<id>/proof.jsonPython:
import hashlib, requests
API = "https://api-traceandanchor.com/api/v1"
H = {"Authorization": "Bearer ta_live_…"}
digest = hashlib.sha256(open("invoice.pdf", "rb").read()).hexdigest()
r = requests.post(f"{API}/anchors", headers={**H, "Idempotency-Key": f"sha256:{digest}"},
json={"file_hash": digest, "original_filename": "invoice.pdf",
"external_reference": "INV-2026-114"})
r.raise_for_status()
anchor = r.json()
print(anchor["certificate_number"], anchor["solana"]["explorer_url"])Node.js 18+:
import { createHash } from "node:crypto";
import { readFile } from "node:fs/promises";
const digest = createHash("sha256").update(await readFile("invoice.pdf")).digest("hex");
const res = await fetch("https://api-traceandanchor.com/api/v1/anchors", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.TA_KEY}`, "Content-Type": "application/json",
"Idempotency-Key": `sha256:${digest}` },
body: JSON.stringify({ file_hash: digest, original_filename: "invoice.pdf" }),
});
const anchor = await res.json();Authentication and keys
Send Authorization: Bearer ta_live_… (or X-API-Key). A key acts on behalf of the account that created it and spends its wallet. Scopes: anchors:write, anchors:read, identity. Keys are stored hashed and shown once; revoke them any time. Use them on servers and desktop software only — never in a web page or a mobile app. GET /account returns your balance, pricing and the key's scopes.
Computing the digest
Standard — hash_mode: "sha256", digest = SHA-256(file). Anyone holding the file can verify. Use it for photos, videos, scans — anything nobody could guess.
Protected — hash_mode: "hmac-sha256", digest = HMAC-SHA-256(K, file) with K = PBKDF2-HMAC-SHA256(NFKC(passphrase), salt, 600 000, 32 bytes). Send kdf_salt (16 random bytes, hex), kdf_iterations and kdf_algorithm — never the passphrase (requests carrying one are rejected). Use it whenever the file names a person: a template document where only a name and an amount change can otherwise be confirmed by guessing. Identical to the website, so protected anchors verify on /verify-hash with the passphrase.
K = hashlib.pbkdf2_hmac("sha256", unicodedata.normalize("NFKC", passphrase).encode(),
bytes.fromhex(salt), 600_000, 32)
digest = hmac.new(K, file_bytes, hashlib.sha256).hexdigest()Idempotency
Anchoring costs money and networks fail. Send an Idempotency-Key on every POST /anchors: a retry with the same key and body within 24 h returns the original response (header Idempotent-Replayed: true) and is not charged again. Failed requests are not remembered, so after a 402 you can top up and retry with the same key. If Solana or Datasure fails, the wallet is refunded automatically.
Certificates and proofs
GET /anchors/{id}/certificate.pdf — the legal certificate (French). GET /anchors/{id}/proof.json — its machine-readable twin, built by the server from the record: digest and how it was computed, Solana transaction and cluster, issuer and LEI, level, timestamp, identity — enough to verify without us. GET /anchors/{id}/timestamp.tsr — the RFC 3161 token when timestamped. Files are named <declared file name>_<certificate id>.
Identity-level anchors (FranceConnect)
FranceConnect works through a browser redirect, so no server can authenticate a person on their behalf. The API uses approval sessions, like signing in to a TV:
POST /identity/sessions→approval_url(valid 15 minutes).- The account holder opens it, signs in with FranceConnect and clicks Approve.
- Poll
GET /identity/sessions/{id}untilstatusisapproved. - Pass
identity_session_idtoPOST /anchors— valid one hour after the FranceConnect login.
What it proves: the identified person authenticated with FranceConnect and performed the anchoring. It does not prove ownership or authorship of the file — the certificate says so explicitly.
Desktop folders — no code
The desktop agent watches two folders on the desktop: 1 - Standard (SHA-256) for files without personal data and 2 - Protected (HMAC) for files that identify people. Drop a file in; its certificate and proof appear in Certificates. The passphrase is chosen once at setup and never leaves the computer.
python ta_agent.py setup # API key, folder, protected passphrase (once)
python ta_agent.py run # leave runningDownload ta_agent.py — Python 3.9+, no other dependency.
Errors
Every error is JSON: {"detail": "…", "code": "insufficient_funds"}
| HTTP | code | What to do |
|---|---|---|
| 400 | invalid_request, invalid_digest | Fix the request |
| 401 | not_authenticated, authentication_failed | Check or replace the key |
| 402 | insufficient_funds | Top up the wallet, retry |
| 403 | permission_denied, identity_session_not_approved | Add the scope / approve a session |
| 404 | not_found | Wrong id, or another account's record |
| 409 | idempotency_in_progress | Wait, then retry |
| 422 | idempotency_key_reused | New request → new Idempotency-Key |
| 429 | throttled | Wait Retry-After seconds |
| 502 | upstream_error | Solana/Datasure failed, wallet refunded — retry |
| 503 | service_unavailable | Maintenance — retry later |
Rate limits and pricing
120 requests/minute per key; verification 30/min and 400/h. Charged per anchor from the prepaid wallet: €1.00 (Solana), +€3.00 eIDAS qualified timestamp, +€5.00 FranceConnect identity.