Attesto

Webhooks

Signed tenant webhooks

Attesto wysyła signed HTTP POST deliveries dla ważnych lifecycle events. Twój endpoint musi zweryfikować signature, deduplikować delivery IDs i zwrócić response 2xx w ciągu 10 sekund.

Kiedy używać webhooks

Webhooks informują twoje systemy, że Attesto evidence się zmieniła. Używaj ich do workflow automation: rozpocznij internal review po przygotowaniu bundle, powiadom case system po zamknięciu checkpoint albo wstrzymaj reliance na stream, gdy pojawi się fork evidence. Nie traktuj webhook jako samej evidence. Pobierz albo zweryfikuj wskazany receipt, checkpoint, fork evidence lub bundle, zanim na nim polegasz.

NeedUseWhy
Receive lifecycle notificationsTenant webhooksAttesto wywołuje twój endpoint po zmianach evidence.
Send source evidence into AttestoConnectors or SDK/APITwój system tworzy event; Attesto wystawia receipt.
Verify a received bundleOffline verifier or POST /v2/verifyVerification sprawdza evidence integrity; notification nie.

Supported events

EventKiedy fires
batch.confirmedMerkle batch tenant events został potwierdzony on-chain.
batch.failedBatch trwale się nie powiódł albo przekroczył orphan window.
event.anchoredPer-event notification po potwierdzeniu related batch.
proofstream.checkpointedProofstream checkpoint został zamknięty i jest dostępny do verification.
proofstream.fork_detectedFork evidence utworzona dla stream history conflict.
proofstream.bundle_readyVerifier bundle jest gotowy dla skonfigurowanej range.

Utwórz subscription

: "${ATTESTO_WEBHOOK_URL:?set this to an HTTPS endpoint controlled by your organization}"

curl -X POST https://dashboard.attesto.eu/v1/webhooks \
  -H "Authorization: Bearer $ATTESTO_TOKEN" \
  -H "Content-Type: application/json" \
  --data-binary @- <<JSON
{
  "name": "audit-notifications",
  "url": "$ATTESTO_WEBHOOK_URL",
  "eventTypes": ["batch.confirmed", "batch.failed"],
  "description": "Posts lifecycle notifications to the configured endpoint"
}
JSON

Weryfikuj delivery signatures

Każda delivery zawiera te headers:

Delivery body shape:

{
  "id": "delivery_...",
  "event": "proofstream.bundle_ready",
  "tenant_id": "tenant_...",
  "created_at": "2026-06-07T12:00:00Z",
  "data": {
    "stream_id": "str_...",
    "bundle_id": "bundle_...",
    "from_seq_no": 1,
    "to_seq_no": 250,
    "verification_url": "https://verify.attesto.eu/v2/verify"
  }
}
import hashlib
import hmac
import time

def verify(signing_value: str, body: bytes, timestamp: str, signature: str) -> bool:
    ts = int(timestamp)
    if abs(int(time.time()) - ts) > 300:
        return False
    expected = hmac.new(
        signing_value.encode("ascii"),
        f"{ts}.".encode("ascii") + body,
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

Minimalny Node handler

import crypto from "node:crypto";
import express from "express";

const app = express();
app.use(express.raw({ type: "application/json" }));

function verifyDelivery(signingValue, body, timestamp, signature) {
  const ts = Number(timestamp);
  if (!Number.isFinite(ts) || Math.abs(Date.now() / 1000 - ts) > 300) {
    return false;
  }
  const expected = crypto
    .createHmac("sha256", signingValue)
    .update(`${timestamp}.`)
    .update(body)
    .digest("hex");
  const expectedBytes = Buffer.from(expected, "hex");
  const receivedBytes = Buffer.from(signature || "", "hex");
  return expectedBytes.length === receivedBytes.length
    && crypto.timingSafeEqual(expectedBytes, receivedBytes);
}

app.post("/attesto/webhook", async (req, res) => {
  const ok = verifyDelivery(
    process.env.ATTESTO_WEBHOOK_SIGNING_VALUE,
    req.body,
    req.header("X-Attesto-Timestamp"),
    req.header("X-Attesto-Signature"),
  );
  if (!ok) return res.status(401).end();

  const deliveryId = req.header("X-Attesto-Delivery-Id");
  const payload = JSON.parse(req.body.toString("utf8"));
  await recordDeliveryOnce(deliveryId, payload);
  res.status(204).end();
});

Retry i dedupe

Delivery jest at least once. Każda non-2xx response, timeout albo refused connection jest retry. Dedupe według X-Attesto-Delivery-Id przed side effects.

AttemptDelay
1Immediate
230 seconds
32 minutes
410 minutes
51 hour
66 hours
7Final attempt

Endpoint requirements

Używaj HTTPS, weryfikuj raw body przed parsing, przechowuj delivery IDs dla dedupe, odpowiadaj szybko i przenieś kosztowne processing do własnej queue po pomyślnej signature verification.