API Watchdog

Capacité en slots, destinataires nommés, alertes et Webhooks signés.

Dernière mise à jour: 30 sept. 2026

Acheter de la capacité, puis créer des watches

Utilisez GET /api/x402/pricing et l’endpoint de devis d’abonnement pour les produits, types de watch, signaux, valeurs par défaut et remises actuels. Les types payants consomment la capacité de leur propre produit ; les types gratuits ont des limites par wallet. Les watches en pause comptent toujours. Achetez avec spend ; créez ou modifiez des watches avec write. Créer une watch n’est pas un achat d’abonnement.

curl 'https://ftso.app/api/x402/subscriptions/quote?product=watchdog-slot&quantity=5&periods=12' \
  -H 'authorization: Bearer fbx_READ_TOKEN'
curl -X POST 'https://ftso.app/api/x402/subscriptions' \
  -H 'authorization: Bearer fbx_SPEND_TOKEN' \
  -H 'content-type: application/json' \
  -H 'Idempotency-Key: purchase_20260930_001' \
  -d '{"product":"watchdog-slot","quantity":5,"periods":12,"autoRenew":true}'

Auto-Renew répète la quantité et la durée achetées au prix actuel. L’activer requiert spend ; le désactiver requiert write. L’acceptation des conditions existantes peut être requise avant un achat. Un essai unique est disponible via POST /api/x402/subscriptions/trial, sous réserve d’éligibilité.

Créer et modifier une watch

curl -X POST 'https://ftso.app/api/x402/watches' \
  -H 'authorization: Bearer fbx_WRITE_TOKEN' \
  -H 'content-type: application/json' \
  -H 'Idempotency-Key: watch_20260930_001' \
  -d '{"type":"feed-move","label":"FLR swing",
       "config":{"chainId":14,"symbol":"FLR","percent":2.5,"windowMinutes":60},
       "signals":{"price-move":{"enabled":true}}}'

curl -X PATCH 'https://ftso.app/api/x402/watches/7' \
  -H 'authorization: Bearer fbx_WRITE_TOKEN' -H 'content-type: application/json' \
  -d '{"action":"pause"}'

PATCH prend en charge config, signals, routing, label, cooldownSeconds, messageTemplate, webhookUrl, rotateSecret et les actions pause/resume. Les modifications de config réinitialisent l’état de surveillance. Les overrides de signaux sont fusionnés champ par champ ; null réinitialise un override. signalsMode: replace remplace les overrides, tandis qu’un objet signals vide avec le merge par défaut ne fait rien. La rotation du secret et la configuration initiale du webhook révèlent un secret : stockez-le de manière sécurisée. Un rejeu avec la même clé peut le récupérer pendant la rétention d’idempotence de 24 heures.

Destinataires et routage

Les destinataires nommés peuvent être réutilisés entre plusieurs watches. Les canaux de saisie peuvent être créés par des clients machine ; les canaux liés suivent leurs propres règles de vérification et de permission. La liaison Discord reste réservée à la session. Les destinataires en attente ne peuvent recevoir ni alertes ni tests. Les anciens endpoints de canal adressent le plus ancien destinataire de leur type ; préférez les ID de destinataire pour un contrôle précis. Les URL de Webhook sont masquées en lecture : omettre une cible la conserve, une suppression intentionnelle par valeur vide/null l’efface. Ne réécrivez pas un masque d’affichage comme nouvelle URL.

curl -X POST 'https://ftso.app/api/x402/recipients' \
  -H 'authorization: Bearer fbx_WRITE_TOKEN' -H 'content-type: application/json' \
  -d '{"name":"Ops","type":"webhook","target":{"url":"https://example.com/hooks/ftsobest"}}'
# Use the returned recipient id in routing.
curl -X PATCH 'https://ftso.app/api/x402/watches/7' \
  -H 'authorization: Bearer fbx_WRITE_TOKEN' -H 'content-type: application/json' \
  -d '{"routing":{"default":["inapp",12],"groups":{"alerts":[12]}}}'

Une route de groupe de signaux prime sur la valeur par défaut de la watch ; les destinataires par défaut sont le repli. Les événements de compte/système atteignent toujours la cloche et les destinataires explicitement marqués par défaut. La livraison des alarmes de signal à la cloche peut être désactivée. Les heures calmes retiennent les canaux personnels ; les groupes, les Webhooks et la cloche continuent de livrer. Un cooldown de watch supprime les répétitions du même événement, pas un événement différent ni son rétablissement.

Aperçus de messages et heures calmes

curl -X PUT 'https://ftso.app/api/x402/settings' \
  -H 'authorization: Bearer fbx_WRITE_TOKEN' -H 'content-type: application/json' \
  -d '{"quietHours":{"start":"22:00","end":"07:00","timezone":"Europe/Berlin"},"notificationLocale":"de"}'
curl -X POST 'https://ftso.app/api/x402/message-preview' \
  -H 'authorization: Bearer fbx_READ_TOKEN' -H 'content-type: application/json' \
  -d '{"watchId":7,"notificationLocale":"de","scope":"wallet","messageTemplate":null}'

Les modèles contiennent title, body et appendDetails. Les modèles de watch priment sur les modèles de wallet ; null restaure la valeur par défaut. Les espaces réservés sont des substitutions littérales, jamais du balisage exécutable. Espaces réservés autorisés : {watch}, {type}, {title}, {severity}, {emoji}, {network}, {identity}, {round}, {epoch}, {details}, {time}, {link}. L’aperçu ne livre aucun message.

Historique des alertes

curl 'https://ftso.app/api/x402/alerts?page=0&pageSize=20&watchId=7&severity=warning&delivery=failed&sort=time&direction=desc' \
  -H 'authorization: Bearer fbx_READ_TOKEN'
curl 'https://ftso.app/api/x402/alerts/export?watchId=7' \
  -H 'authorization: Bearer fbx_READ_TOKEN'

L’historique utilise des pages à base zéro avec pageSize au plus 100. L’export utilise les mêmes filtres et renvoie au plus 5 000 lignes CSV. Les listes de watches et de compte utilisent limit/cursor à la place. Les ID de watch ou d’alerte étrangers renvoient 404. Supprimer une watch n’efface pas son historique d’alertes. Supprimer des alertes est une opération write explicite ; la sélection et maxId protègent la fenêtre d’historique visée.

Payload de Webhook et vérification

Le payload v2 ajoute payloadVersion: 2, signal et group à la forme v1. Gardez les champs techniques inchangés même lorsque le texte rendu est localisé. Lisez le schéma v2 et acceptez des champs supplémentaires dans les données d’événement. Dédupliquez par deliveryId. La liste d’événements générée ci-dessous couvre les événements de signal et de rétablissement catalogués ; les messages de compte et les tests de canal sont des événements système distincts.

Cet exemple v2 abrégé montre l’enveloppe ; data contient les faits propres au type. Le schéma v1 utilise les mêmes champs de base de livraison, alerte, watch, événement, severity, firedAt et data sans les trois ajouts de la v2. rendered et renderedMessage peuvent fournir un texte d’affichage localisé ; conservez deliveryId pour la déduplication.

{
  "payloadVersion": 2,
  "deliveryId": "unique-delivery-id",
  "alertId": 41,
  "watchId": 7,
  "label": "FLR swing",
  "type": "feed-move",
  "event": "feed-move.threshold",
  "signal": "price-move",
  "group": "alerts",
  "severity": "warning",
  "firedAt": "2026-09-30T12:00:00.000Z",
  "data": {}
}
import { createHmac, timingSafeEqual } from "node:crypto";

// rawBody is the exact request body Buffer, not parsed/re-serialized JSON.
const timestamp = req.headers["x-watchdog-timestamp"];
const signature = req.headers["x-watchdog-signature"];
if (
  typeof timestamp !== "string" ||
  !/^\d+$/.test(timestamp) ||
  typeof signature !== "string" ||
  Math.abs(Date.now() / 1000 - Number(timestamp)) > 300
)
  throw new Error("invalid");
const expected = Buffer.from(
  "sha256=" +
    createHmac("sha256", secret)
      .update(timestamp + ".")
      .update(rawBody)
      .digest("hex"),
);
const received = Buffer.from(signature);
if (received.length !== expected.length || !timingSafeEqual(expected, received))
  throw new Error("invalid");

La vérification utilise X-Watchdog-Signature et X-Watchdog-Timestamp ; consultez X-Watchdog-Payload-Version pour le contrat de payload. Ne répondez qu’après avoir validé la signature et la fraîcheur. Acquittez les ID de livraison en double sans répéter les effets. Voir la documentation utilisateur Watchdog pour le parcours plus large.

Événements Webhook

  • credits.low-balance
  • credits.recovered
  • feed-move.threshold
  • fsp.balance-low
  • fsp.balance-low.recovered
  • fsp.fast-updates
  • fsp.fast-updates.recovered
  • fsp.fdc-bitvote
  • fsp.fdc-bitvote-length
  • fsp.fdc-bitvote-length.recovered
  • fsp.fdc-bitvote.recovered
  • fsp.fdc-consensus
  • fsp.fdc-consensus.recovered
  • fsp.fdc-reveal-offence
  • fsp.fdc-reveal-offence.recovered
  • fsp.fdc-signature
  • fsp.fdc-signature.recovered
  • fsp.fdc-submit1
  • fsp.fdc-submit1.recovered
  • fsp.ftso-commit
  • fsp.ftso-commit.recovered
  • fsp.ftso-reveal
  • fsp.ftso-reveal.recovered
  • fsp.ftso-signature
  • fsp.ftso-signature.recovered
  • fsp.mc-anchor
  • fsp.mc-anchor.recovered
  • fsp.mc-fdc
  • fsp.mc-fdc.recovered
  • fsp.mc-uptime
  • fsp.mc-uptime.recovered
  • fsp.monitoring
  • fsp.monitoring.recovered
  • fsp.not-in-policy
  • fsp.not-in-policy.recovered
  • fsp.registration
  • fsp.registration.recovered
  • fsp.reveal-offence
  • fsp.reveal-offence.recovered
  • fsp.rewards-unclaimed
  • fsp.rewards-unclaimed.recovered
  • fsp.signature-grace
  • fsp.signature-grace.recovered
  • fsp.signature-mismatch
  • fsp.signature-mismatch.recovered
  • fsp.tx-failed
  • fsp.tx-failed.recovered
  • fsp.validator-not-listed
  • fsp.validator-not-listed.recovered
  • provider.eligibility-lost
  • provider.recovered
  • provider.unregistered
  • signing.done
  • signing.missed
  • signing.rewards-open
  • signing.rewards-reminder
  • signing.uptime-open
  • wallet-balance.moved