Skip to main content

Pourquoi le contrôle du budget est important

Un agent IA qui appelle des API payantes en boucle peut accumuler des coûts rapidement. Le contrôle du budget vous permet de :
  • Plafonner les dépenses totales par session
  • Définir des limites par domaine (ex. : max 100 sats/session sur api.weather.com)
  • Recevoir un callback avant chaque paiement
  • Obtenir un rapport de dépenses complet à tout moment

Budget global

import { L402Client, BlinkWallet } from "l402-kit";

const client = new L402Client({
  wallet: new BlinkWallet(process.env.BLINK_API_KEY!, process.env.BLINK_WALLET_ID!),
  budgetSats: 500, // max 500 sats total this session
});
Lorsqu’une réponse 402 inclut un champ priceSats et que celui-ci dépasserait le budget restant, le client lève une BudgetExceededError avant de payer — aucun satoshi n’est dépensé.

Budget par domaine

const client = new L402Client({
  wallet,
  budgetSats: 2000,
  budgetPerDomain: {
    "api.weather.com": 100,
    "api.finance.com": 500,
  },
});
Les limites par domaine sont vérifiées indépendamment de la limite globale — les deux doivent être respectées pour que le paiement soit effectué.

Callbacks

const client = new L402Client({
  wallet,
  budgetSats: 1000,
  onSpend: (sats, url) => {
    console.log(`✓ Paid ${sats} sats → ${url}`);
    // log to your telemetry, update a dashboard, etc.
  },
  onBudgetExceeded: (url, sats) => {
    console.warn(`✗ Blocked: ${sats} sats requested by ${url} — budget exhausted`);
    // alert, notify Slack, etc.
  },
});
onBudgetExceeded / on_budget_exceeded est appelé juste avant que BudgetExceededError soit levée — utile pour la journalisation ou les alertes.

Rapport de dépenses

const report = client.spendingReport();

if (report) {
  console.log(`Total spent: ${report.total} sats`);
  console.log(`Remaining:   ${report.remaining} sats`);
  console.log("By domain:", report.byDomain);
  // { "api.weather.com": 42, "api.finance.com": 105 }

  for (const tx of report.transactions) {
    console.log(`  ${tx.ts}  ${tx.sats} sats  ${tx.url}`);
  }
}
spendingReport() retourne null / None lorsqu’aucun budget n’est configuré.

Gestion de BudgetExceededError

import { BudgetExceededError } from "l402-kit";

try {
  const res = await client.fetch("https://api.example.com/premium");
} catch (err) {
  if (err instanceof BudgetExceededError) {
    console.log(`Need ${err.required} sats, only ${err.remaining} remaining`);
    // gracefully degrade — return cached data, skip this step, etc.
  }
}

Notes sur la concurrence

Ne partagez pas une seule instance de L402Client entre des appels Promise.all concurrents lorsque les limites de budget sont importantes.BudgetTracker.check() et record() sont séparés par un await (le paiement Lightning). Deux appels client.fetch() concurrents vers des endpoints différents peuvent tous les deux passer la vérification du budget avant que l’un ou l’autre n’enregistre la dépense — ce qui signifie que le coût combiné peut temporairement dépasser votre plafond budgétaire d’un paiement.Modèle sûr — appels séquentiels :
for (const url of urls) {
  const res = await client.fetch(url); // awaited one at a time
}
Modèle risqué — appels parallèles :
// Both may pass budget.check() before either calls budget.record()
const results = await Promise.all(urls.map(url => client.fetch(url)));
Atténuation pour les charges de travail parallèles : définissez votre budgetSats de manière conservative (ex. : 80 % de votre limite réelle) pour absorber le dépassement provenant d’un paiement concurrent. Pour une application stricte, traitez les appels de manière séquentielle.

Référence complète des options

OptionTypeScriptPythonDéfautDescription
Budget globalbudgetSatsbudget_satsillimitéNombre maximum de sats pour la session
Par domainebudgetPerDomainbudget_per_domain{}Correspondance domaine → sats maximum
Hook de dépenseonSpendon_spendAppelé après chaque paiement
Hook de dépassementonBudgetExceededon_budget_exceededAppelé avant le lancement de l’exception