Documentation
Démarrez avec l'API Anchorify
REST API
L'API Anchorify est une API REST JSON simple. Authentifiez-vous avec
une clé API via le header X-API-Key.
URL de base
https://api.anchorify.cloud Spécification OpenAPI
openapi.jsonDémarrage rapide
L'API Anchorify vous permet de créer des preuves infalsifiables en ancrant des hashes sur des blockchains publiques. Voici comment commencer :
1. Obtenez votre clé API
Créez un compte et générez une clé API depuis la console.
2. Hashez vos données localement
Générez un hash de votre fichier ou donnée. Les données originales n'ont jamais besoin de quitter votre système.
# Générer un hash SHA-256 (sortie hexadécimale)
openssl dgst -sha256 document.pdf
# SHA256(document.pdf)= e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
# Utilisez la chaîne hexadécimale directement dans l'API 3. Soumettez le hash
Envoyez le hash encodé en hexadécimal à notre API REST pour créer une notarisation. Vous recevrez un ID de notarisation pour le suivi.
curl -X POST https://api.anchorify.cloud/v1/notarizations \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"algorithm": "SHA256",
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"name": "document.pdf"
}' import hashlib
import requests
with open("document.pdf", "rb") as f:
hash_hex = hashlib.sha256(f.read()).hexdigest()
resp = requests.post(
"https://api.anchorify.cloud/v1/notarizations",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"algorithm": "SHA256",
"hash": hash_hex,
"name": "document.pdf",
},
)
print(resp.json()["id"]) package main
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
func main() {
f, _ := os.Open("document.pdf")
defer f.Close()
h := sha256.New()
io.Copy(h, f)
hashHex := hex.EncodeToString(h.Sum(nil))
body, _ := json.Marshal(map[string]string{
"algorithm": "SHA256",
"hash": hashHex,
"name": "document.pdf",
})
req, _ := http.NewRequest("POST",
"https://api.anchorify.cloud/v1/notarizations",
bytes.NewReader(body))
req.Header.Set("X-API-Key", "YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var result map[string]any
json.NewDecoder(resp.Body).Decode(&result)
fmt.Println(result["id"])
} {
"id": "019c0e1a-d891-7f1f-ab6e-5588c46c2a4b",
"algorithm": "SHA256",
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"status": "pending",
"blockchain_proofs": [
{ "provider_name": "Algorand", "status": "pending", "created_at": "2026-01-30T08:52:46Z" },
{ "provider_name": "Base", "status": "pending", "created_at": "2026-01-30T08:52:46Z" },
{ "provider_name": "Polygon", "status": "pending", "created_at": "2026-01-30T08:52:46Z" }
],
"created_at": "2026-01-30T08:52:46Z",
"name": "document.pdf"
} 4. Interrogez le statut
Vérifiez le statut de la preuve. Une fois ancrée sur la blockchain, vous pouvez exporter votre document de preuve signé.
curl https://api.anchorify.cloud/v1/notarizations/019c0e1a-d891-7f1f-ab6e-5588c46c2a4b \
-H "X-API-Key: YOUR_API_KEY" resp = requests.get(
"https://api.anchorify.cloud/v1/notarizations/019c0e1a-d891-7f1f-ab6e-5588c46c2a4b",
headers={"X-API-Key": "YOUR_API_KEY"},
)
notarization = resp.json()
print(f"Statut : {notarization['status']}") req, _ := http.NewRequest("GET",
"https://api.anchorify.cloud/v1/notarizations/019c0e1a-d891-7f1f-ab6e-5588c46c2a4b",
nil)
req.Header.Set("X-API-Key", "YOUR_API_KEY")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var notarization map[string]any
json.NewDecoder(resp.Body).Decode(¬arization)
fmt.Printf("Status: %s\n", notarization["status"]) {
"id": "019c0e1a-d891-7f1f-ab6e-5588c46c2a4b",
"algorithm": "SHA256",
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"status": "completed",
"timestamp_proof": {
"status": "timestamped",
"tsa_provider": { "name": "FreeTSA" },
"timestamped_at": "2026-01-30T08:52:48Z",
"created_at": "2026-01-30T08:52:47Z"
},
"blockchain_proofs": [
{
"provider_name": "Polygon",
"transaction_id": "0xabc123...",
"explorer_url": "https://polygonscan.com/tx/0xabc123...",
"status": "anchored",
"anchored_at": "2026-01-30T08:53:32Z",
"created_at": "2026-01-30T08:52:47Z"
}
],
"merkle_root": "a1b2c3d4...",
"created_at": "2026-01-30T08:52:46Z",
"updated_at": "2026-01-30T08:53:32Z",
"notarized_at": "2026-01-30T08:53:32Z",
"name": "document.pdf"
} Référence API
POST /v1/notarizations Créer une notarisation
Body : algorithm (requis, SHA256 | SHA384 | SHA512),
hash (requis, chaîne hexadécimale),
name (optionnel),
qualified_timestamp (optionnel)
GET /v1/notarizations/{id} Récupérer une notarisation par ID
Chemin : id (requis, UUID)
Webhooks
ProLes webhooks permettent à votre application de recevoir des notifications HTTP POST en temps réel lorsque des événements de notarisation se produisent. Configurez les URL d'endpoint et abonnez-vous aux types d'événements depuis la console.
Types d'événements
Abonnez-vous aux événements pertinents pour votre workflow. Chaque livraison webhook inclut un snapshot complet de la notarisation avec l'état actuel des preuves.
| Type d'événement | Description |
|---|---|
notarization.created | Notarisation soumise et acceptée. |
notarization.sealed | Accumulateur scellé, preuve Merkle assignée. L'ancrage blockchain commence. |
notarization.timestamped | Horodatage RFC 3161 obtenu. Le champ event_context inclut les détails de l'horodatage. |
notarization.anchor_submitted | Transaction blockchain soumise pour un fournisseur. Déclenché par fournisseur. |
notarization.anchored | Transaction blockchain confirmée on-chain pour un fournisseur. |
notarization.completed | Tout le traitement est terminé. Le champ event_context inclut completed_at. |
notarization.failed | Le traitement a échoué. Le champ event_context inclut failure_reason. |
Structure du payload
Chaque livraison webhook envoie une enveloppe JSON avec un snapshot complet de la notarisation. L'objet data.notarization est autonome — vous n'avez pas besoin d'appeler GET /v1/notarizations/{id}.
{
"id": "019c0e1a-e7a2-7f3b-8c1d-4a9b2e6f8d3c",
"type": "notarization.completed",
"api_version": "2026-03-01",
"created_at": "2026-01-30T08:53:32Z",
"organization_id": "019b7a3c-5d2e-7f1a-9b4c-3e8f1a2d5c7b",
"data": {
"notarization": {
"id": "019c0e1a-d891-7f1f-ab6e-5588c46c2a4b",
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"hash_algorithm": "SHA256",
"status": "completed",
"name": "document.pdf",
"created_at": "2026-01-30T08:52:46Z",
"updated_at": "2026-01-30T08:53:32Z",
"notarized_at": "2026-01-30T08:53:32Z",
"timestamp": {
"status": "timestamped",
"serial_number": "1A2B3C",
"tsa_provider": "FreeTSA",
"tsa_cert_subject": "CN=FreeTSA,O=Free TSA,C=DE",
"tsa_cert_serial": "04B9A5",
"tsa_cert_ski": "A1B2C3D4E5F6...",
"policy_oid": "1.2.3.4.1",
"timestamped_at": "2026-01-30T08:52:48.123456Z"
},
"anchors": [
{
"provider": "Polygon",
"status": "anchored",
"transaction_hash": "0xabc123...",
"explorer_url": "https://polygonscan.com/tx/0xabc123...",
"submitted_at": "2026-01-30T08:52:50Z",
"anchored_at": "2026-01-30T08:53:32Z"
}
],
"accumulator": {
"merkle_root": "a1b2c3d4e5f6..."
}
},
"event_context": {
"completed_at": "2026-01-30T08:53:32Z"
}
}
} Note : Les champs timestamp.token_base64 et proof ne sont inclus que si l'endpoint a activé les options include_timestamp_token / include_merkle_proof.
En-têtes HTTP
Chaque requête webhook inclut les en-têtes suivants :
| En-tête | Valeur |
|---|---|
Content-Type | application/json |
User-Agent | Anchorify-Webhooks/1.0 |
X-Anchorify-Signature | t=<unix>,v1=<hex> (HMAC-SHA256) |
X-Anchorify-Event-Type | Type d'événement |
X-Anchorify-Event-ID | UUID de l'événement |
X-Anchorify-Delivery-ID | UUID de la tentative de livraison |
Vérification de la signature
Chaque webhook est signé avec HMAC-SHA256 en utilisant le secret de votre endpoint. Le format de l'en-tête de signature est t=<timestamp>,v1=<hex_signature>, calculé sur <timestamp>.<raw_body>. Nous recommandons de vérifier la signature et la fraîcheur du timestamp (tolérance de 5 minutes).
import hmac
import hashlib
import time
def verify_webhook(payload: bytes, header: str, secret: str) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
timestamp = parts["t"]
signature = parts["v1"]
# Check timestamp freshness (5 min tolerance)
if abs(time.time() - int(timestamp)) > 300:
raise ValueError("Timestamp expired")
expected = hmac.new(
secret.encode(),
f"{timestamp}.".encode() + payload,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, signature) const crypto = require("crypto");
function verifyWebhook(payload, header, secret) {
const parts = Object.fromEntries(
header.split(",").map((p) => p.split("=", 2))
);
// Check timestamp freshness (5 min tolerance)
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) {
throw new Error("Timestamp expired");
}
const expected = crypto
.createHmac("sha256", secret)
.update(`${parts.t}.${payload}`)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(parts.v1)
);
} package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"math"
"strings"
"time"
)
func verifyWebhook(payload []byte, header, secret string) error {
parts := make(map[string]string)
for _, p := range strings.Split(header, ",") {
kv := strings.SplitN(p, "=", 2)
parts[kv[0]] = kv[1]
}
// Check timestamp freshness (5 min tolerance)
ts, _ := time.Parse("", parts["t"])
if math.Abs(float64(time.Now().Unix()-ts.Unix())) > 300 {
return fmt.Errorf("timestamp expired")
}
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(parts["t"] + "."))
mac.Write(payload)
expected := hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(expected), []byte(parts["v1"])) {
return fmt.Errorf("invalid signature")
}
return nil
} Politique de retry
Les livraisons échouées sont relancées avec un backoff exponentiel. Votre endpoint doit répondre avec un statut 2xx dans les 30 secondes.
- Jusqu'à 5 tentatives par livraison.
- Backoff exponentiel : min(30s × 2^tentative, 24h) + 0–5s de jitter.
-
2xx— 2xx — livraison réussie. -
429 / 5xx— 429 ou 5xx — relancé avec backoff. -
410— 410 Gone — endpoint immédiatement désactivé. -
4xx— Autres 4xx — échec définitif, pas de relance. - Les endpoints sont automatiquement désactivés après 10 échecs consécutifs.
Algorithmes de hachage supportés
Algorithmes supportés : SHA-256 (tous les plans), SHA-384 et SHA-512 (Pro et Enterprise). Le hash doit être fourni sous forme de chaîne encodée en hexadécimal.
API asynchrone
L'API est asynchrone. Soumettez votre hash et interrogez le statut, ou utilisez les webhooks (Pro) pour les notifications.
Documents de preuve signés
Les plans Pro et Enterprise peuvent exporter des documents de preuve signés contenant toutes les preuves cryptographiques. Pro
Horodatages qualifiés
Les plans Enterprise peuvent ajouter des horodatages qualifiés eIDAS pour une valeur juridique renforcée. Enterprise