🧭 TimeProofs API (v0.1)

Envoyez un hash SHA-256. Recevez un timestamp signé et une URL de vérification publique. Pas d’upload. Pas de blockchain.

🌐 Base URL

https://api.timeproofs.io/api

Production. CORS ouvert pour https://timeproofs.io.

⚡ Endpoints

EndpointMethodDescriptionAuth
/pingGETHealthcheck.
/admin/timestampPOSTCrée une preuve pour un hash SHA-256.Bearer

⚙️ Quickstart

1) cURL — ping

curl -s https://api.timeproofs.io/api/ping

2) cURL — créer une preuve

curl -s -X POST https://api.timeproofs.io/api/admin/timestamp \
  -H "Authorization: Bearer <ADMIN_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"hash":"<64-hex-sha256>","meta":{"source":"docs"},"env":"prod"}'

Exemple de réponse

{
  "ok": true,
  "hash": "7c040f8633b8823d72ed63da9b3b2dfe9846e912c66a64c9433ec9c4815d76c2",
  "ts": "2025-10-22T12:34:56.789Z",
  "sig": "hmac_sha256(secret, `${hash}|${ts}`)",
  "verify_url": "https://timeproofs.io/verify.html?hash=7c04...&ts=...&sig=...",
  "meta": { "source": "docs" }
}

🔐 Hash local (browser)

const buf = new TextEncoder().encode(text);
const digest = await crypto.subtle.digest('SHA-256', buf);
const hash = [...new Uint8Array(digest)].map(b => b.toString(16).padStart(2,'0')).join('');

Envoyez uniquement le hash hexadécimal (64 chars).

🧾 Vérifier une preuve

Utilisez la page Verify pour valider publiquement une preuve (hash, timestamp, signature).

La signature serveur est un HMAC-SHA256 de ${hash}|${ts}.

Node.js

import crypto from "node:crypto";
function verify({ hash, ts, sig }, secret){
  const msg = `${hash}|${ts}`;
  const expect = crypto.createHmac("sha256", secret).update(msg).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expect,'hex'), Buffer.from(sig,'hex'));
}

Python

import hmac, hashlib
def verify(payload, secret: bytes) -> bool:
    msg = f"{payload['hash']}|{payload['ts']}".encode()
    sig = hmac.new(secret, msg, hashlib.sha256).hexdigest()
    return hmac.compare_digest(sig, payload["sig"])

📦 Schémas JSON

POST /admin/timestamp — request

{
  "type":"object",
  "required":["hash"],
  "properties":{
    "hash":{"type":"string","pattern":"^[a-f0-9]{64}$"},
    "meta":{"type":"object","maxProperties":32,"additionalProperties":true},
    "env":{"type":"string","maxLength":16}
  },
  "additionalProperties": false
}

POST /admin/timestamp — response

{
  "type":"object",
  "required":["ok","hash","ts","sig","verify_url"],
  "properties":{
    "ok":{"type":"boolean"},
    "hash":{"type":"string"},
    "ts":{"type":"string","format":"date-time"},
    "sig":{"type":"string"},
    "verify_url":{"type":"string","format":"uri"},
    "meta":{"type":"object"}
  }
}

🚦 Status & erreurs

StatusQuandBody
200SuccèsObjet JSON
400JSON invalide / hash invalide{ "ok":false, "error":"..." }
401Bearer manquant/erroné{ "ok":false, "error":"unauthorized" }
404Route inconnue{ "ok":false, "error":"not_found" }
429Rate limit (si activée){ "ok":false, "error":"rate_limited" }
500Erreur serveur{ "ok":false, "error":"internal" }

🔒 Sécurité

Voir Privacy et Legal.