> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blockradar.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Effectuer des Paiements par Agents

> Permettez aux agents IA de payer des API en stablecoins depuis un portefeuille Blockradar, sans que la cle privee ne quitte Blockradar

<Note>
  En bref<br />
  Les agents IA peuvent payer des API et des données à la requête, en stablecoins, grâce à des protocoles ouverts de paiement par agents. Avec Blockradar, un agent paie depuis un portefeuille dont la clé privée ne quitte jamais Blockradar, en utilisant le point de terminaison de [signature de données typées](/fr/essentials/signing#signature-de-données-typées-evm-uniquement) dont vous disposez déjà.
</Note>

## Protocoles pris en charge

| Protocole | Réseaux et tokens |
| - | - |
| [x402](https://www.x402.org) | Chaînes EVM, USDC (EIP-3009) |

<Tip>
  Vous vendez plutôt aux agents ? Consultez [Accepter des Paiements par Agents](/fr/use-cases/accept-agent-payments).
</Tip>

## Prérequis

<Steps>
  <Step title="Clé API">
    Obtenez votre clé API depuis le [Tableau de bord Blockradar](https://dashboard.blockradar.co). Naviguez vers **Developers** pour en générer une.
  </Step>

  <Step title="Portefeuille Principal EVM">
    Créez un portefeuille principal dans le tableau de bord sur la chaîne sur laquelle l'API facture, comme Base (voir [Créer un Portefeuille Principal](/fr/guides/create-master-wallet)). Les paiements par agents via Blockradar sont réservés aux chaînes EVM.
  </Step>

  <Step title="USDC Activé">
    Activez USDC sur le portefeuille afin que les soldes et les dépôts soient suivis. Voir [Gestion des Actifs](/fr/use-cases/asset-management).
  </Step>
</Steps>

## Un budget dédié pour chaque agent

<Warning>
  La signature n'a pas de plafond de dépense par paiement<br />
  Toute personne détenant une clé API ayant accès à un portefeuille peut signer un paiement de n'importe quel montant depuis ce portefeuille ou ses adresses. Blockradar ne plafonne pas ce qu'un agent signe. Limitez les dégâts que peuvent causer un agent défaillant ou une clé divulguée en attribuant à l'agent une adresse dédiée qui ne détient que ce qu'il est autorisé à dépenser.
</Warning>

Une adresse enfant avec l'auto-sweep désactivé constitue un bon budget pour un agent. Approvisionnez-la du montant que l'agent peut dépenser, et l'agent ne pourra jamais payer plus que ce solde.

<CodeGroup>
  ```bash Curl theme={null}
  curl --request POST \
    --url https://api.blockradar.co/v1/wallets/{walletId}/addresses \
    --header 'Content-Type: application/json' \
    --header 'x-api-key: <api-key>' \
    --data '{
      "name": "Research agent budget",
      "disableAutoSweep": true,
      "metadata": {
        "purpose": "agent-payments"
      }
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    `https://api.blockradar.co/v1/wallets/${walletId}/addresses`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': apiKey
      },
      body: JSON.stringify({
        name: 'Research agent budget',
        disableAutoSweep: true,
        metadata: { purpose: 'agent-payments' }
      })
    }
  ).then(r => r.json());

  console.log('Agent address:', response.data.address);
  console.log('Address ID:', response.data.id);
  ```
</CodeGroup>

<Note>
  Conservez `disableAutoSweep: true` sur l'adresse d'un agent. Avec l'auto-sweep activé, l'USDC que vous envoyez pour approvisionner l'agent est consolidé (sweep) vers le portefeuille principal, et les paiements de l'agent échouent faute de fonds.
</Note>

Payer depuis le portefeuille principal fonctionne également. Utilisez les points de terminaison du portefeuille principal dans les exemples ci-dessous et omettez `addressId`. La totalité du solde du portefeuille principal est alors à la portée de l'agent : ne le faites donc qu'avec un portefeuille principal dédié à l'agent.

Avec le [Plan Checkout](/fr/use-cases/checkout#plan-checkout), les opérations sur les adresses enfants ne sont pas disponibles : utilisez un portefeuille principal dédié à l'agent.

***

## Fonctionnement de x402

[x402](https://www.x402.org) est un protocole ouvert qui permet à une API de facturer à la requête : elle répond avec un HTTP `402 Payment Required`, et l'appelant réessaie avec un paiement USDC signé. x402 implique trois parties : l'**acheteur** (votre agent), le **vendeur** (l'API payée) et un **facilitateur** qui vérifie le paiement et le soumet on-chain.

<Steps>
  <Step title="L'API demande un paiement">
    L'agent appelle un point de terminaison payant. L'API répond avec `402 Payment Required` et un en-tête `PAYMENT-REQUIRED` listant ce qu'elle accepte : réseau, token, montant et adresse `payTo`.
  </Step>

  <Step title="Blockradar signe le paiement">
    L'agent transforme l'une de ces options en un `TransferWithAuthorization` [EIP-3009](https://eips.ethereum.org/EIPS/eip-3009) et le signe avec le point de terminaison de données typées de Blockradar. Rien n'est encore envoyé on-chain.
  </Step>

  <Step title="L'agent réessaie avec la signature">
    L'agent renvoie la requête avec le paiement signé dans l'en-tête `PAYMENT-SIGNATURE`.
  </Step>

  <Step title="Le facilitateur règle le paiement">
    Le facilitateur du vendeur vérifie la signature et soumet le transfert on-chain, en payant lui-même le gas. L'API renvoie la réponse, avec le résultat du règlement dans un en-tête `PAYMENT-RESPONSE`.
  </Step>
</Steps>

Le portefeuille de l'agent a besoin d'**USDC mais pas de gas**. La signature autorise un seul transfert d'un montant exact vers une adresse exacte, et le facilitateur ne peut modifier ni l'un ni l'autre.

***

## Payer avec x402

Approvisionnez d'abord l'adresse de l'agent, comme décrit dans [Un budget dédié pour chaque agent](#un-budget-dédié-pour-chaque-agent).

### Option 1 : Utiliser le SDK client x402

Le client officiel [`@x402/fetch`](https://www.npmjs.com/package/@x402/fetch) gère l'échange 402 pour vous. Il n'a besoin que d'un signataire doté d'une `address` et d'une méthode `signTypedData`. L'adaptateur ci-dessous implémente ce signataire sur le point de terminaison de données typées de Blockradar, de sorte que la clé reste dans Blockradar.

```bash theme={null}
npm install @x402/fetch @x402/evm
```

```javascript JavaScript theme={null}
import { wrapFetchWithPaymentFromConfig, decodePaymentResponseHeader } from '@x402/fetch';
import { ExactEvmScheme } from '@x402/evm';

// An x402 signer whose key stays in Blockradar. Pass addressId to pay from a child address.
function blockradarSigner({ apiKey, walletId, addressId, address }) {
  const path = addressId
    ? `/wallets/${walletId}/addresses/${addressId}/signing/typed-data`
    : `/wallets/${walletId}/signing/typed-data`;

  return {
    address,
    async signTypedData({ domain, types, message }) {
      // Blockradar derives the domain type from `domain`, so EIP712Domain must not be in `types`
      const { EIP712Domain, ...signTypes } = types;

      const res = await fetch(`https://api.blockradar.co/v1${path}`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey },
        // x402 passes uint256 values as BigInt, which JSON.stringify cannot serialize
        body: JSON.stringify({ domain, types: signTypes, message }, (_, v) =>
          typeof v === 'bigint' ? v.toString() : v
        ),
      });
      const body = await res.json();
      if (!res.ok) {
        throw new Error(`Blockradar signing failed: ${JSON.stringify(body.message)}`);
      }
      if (body.data.senderAddress.toLowerCase() !== address.toLowerCase()) {
        throw new Error(`Signed by ${body.data.senderAddress}, expected ${address}`);
      }
      return body.data.signedTransaction.signature;
    },
  };
}

const signer = blockradarSigner({
  apiKey: process.env.BLOCKRADAR_API_KEY,
  walletId: process.env.BLOCKRADAR_WALLET_ID,
  addressId: process.env.BLOCKRADAR_ADDRESS_ID, // omit to pay from the master wallet
  address: process.env.AGENT_ADDRESS,           // the address that holds the USDC
});

const fetchWithPayment = wrapFetchWithPaymentFromConfig(fetch, {
  schemes: [{ network: 'eip155:8453', client: new ExactEvmScheme(signer) }], // Base mainnet
});

const response = await fetchWithPayment('https://api.example.com/premium-data');
console.log(await response.json());

const settlement = response.headers.get('PAYMENT-RESPONSE');
if (settlement) {
  console.log(decodePaymentResponseHeader(settlement)); // { success, transaction, network, payer }
}
```

Enregistrez un schéma par réseau sur lequel l'agent paie (`eip155:84532` pour Base Sepolia pendant les tests), avec un portefeuille sur cette chaîne derrière chacun.

### Option 2 : Construire le paiement vous-même

Sans le SDK, ou dans un autre langage, un paiement nécessite trois appels HTTP : la première requête, l'appel de signature à Blockradar et la nouvelle tentative payée. Les étapes ci-dessous paient 0,01 USDC sur Base.

#### Étape 1 : Lire les exigences de paiement

Appelez l'API. Une réponse `402` contient un en-tête `PAYMENT-REQUIRED` encodé en base64. Une fois décodé, il ressemble à ceci :

```json theme={null}
{
  "x402Version": 2,
  "error": "PAYMENT-SIGNATURE header is required",
  "resource": {
    "url": "https://api.example.com/premium-data",
    "description": "Access to premium market data",
    "mimeType": "application/json"
  },
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:8453",
      "amount": "10000",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
      "maxTimeoutSeconds": 60,
      "extra": {
        "name": "USD Coin",
        "version": "2"
      }
    }
  ]
}
```

Choisissez dans `accepts` une entrée que votre portefeuille peut payer :

* `scheme` vaut `exact`.
* `network` correspond à la chaîne du portefeuille. `eip155:8453` est Base mainnet.
* `extra.assetTransferMethod` est absent ou vaut `eip3009`. La méthode `permit2` nécessite d'abord une approbation de token on-chain, qui coûte du gas ; ce guide ne la couvre donc pas.

`amount` est exprimé dans la plus petite unité du token. USDC a 6 décimales, donc `10000` correspond à 0,01 USDC.

#### Étape 2 : Signer l'autorisation

Construisez le `TransferWithAuthorization` à partir des exigences et signez-le depuis l'adresse de l'agent :

| Champ | Valeur |
| - | - |
| `domain.name`, `domain.version` | `extra.name` et `extra.version` |
| `domain.chainId` | Le nombre après `eip155:` dans `network`, sous forme de nombre JSON |
| `domain.verifyingContract` | `asset`, le contrat USDC |
| `message.from` | L'adresse de l'agent |
| `message.to` | `payTo` |
| `message.value` | `amount` |
| `message.validAfter` | Un horodatage Unix légèrement dans le passé, par exemple maintenant moins 600 secondes |
| `message.validBefore` | Maintenant plus `maxTimeoutSeconds` |
| `message.nonce` | 32 octets aléatoires en hexadécimal. Générez-en un nouveau pour chaque paiement |

<CodeGroup>
  ```bash Curl theme={null}
  curl --request POST \
    --url https://api.blockradar.co/v1/wallets/{walletId}/addresses/{addressId}/signing/typed-data \
    --header 'Content-Type: application/json' \
    --header 'x-api-key: <api-key>' \
    --data '{
      "domain": {
        "name": "USD Coin",
        "version": "2",
        "chainId": 8453,
        "verifyingContract": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
      },
      "types": {
        "TransferWithAuthorization": [
          { "name": "from", "type": "address" },
          { "name": "to", "type": "address" },
          { "name": "value", "type": "uint256" },
          { "name": "validAfter", "type": "uint256" },
          { "name": "validBefore", "type": "uint256" },
          { "name": "nonce", "type": "bytes32" }
        ]
      },
      "message": {
        "from": "0x947514e4B803e312C312da0F1B41fEDdbe15ae7a",
        "to": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
        "value": "10000",
        "validAfter": "1791106604",
        "validBefore": "1791107264",
        "nonce": "0x312a453ed3d129ba71de863aa623245c0e5e120bad410d995cea6739aa8ee98b"
      }
    }'
  ```

  ```javascript JavaScript theme={null}
  import { randomBytes } from 'node:crypto';

  const now = Math.floor(Date.now() / 1000);
  const authorization = {
    from: agentAddress,
    to: accepted.payTo,
    value: accepted.amount,
    validAfter: String(now - 600),
    validBefore: String(now + accepted.maxTimeoutSeconds),
    nonce: '0x' + randomBytes(32).toString('hex'),
  };

  const res = await fetch(
    `https://api.blockradar.co/v1/wallets/${walletId}/addresses/${addressId}/signing/typed-data`,
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey },
      body: JSON.stringify({
        domain: {
          name: accepted.extra.name,
          version: accepted.extra.version,
          chainId: Number(accepted.network.split(':')[1]),
          verifyingContract: accepted.asset,
        },
        types: {
          TransferWithAuthorization: [
            { name: 'from', type: 'address' },
            { name: 'to', type: 'address' },
            { name: 'value', type: 'uint256' },
            { name: 'validAfter', type: 'uint256' },
            { name: 'validBefore', type: 'uint256' },
            { name: 'nonce', type: 'bytes32' },
          ],
        },
        message: authorization,
      }),
    }
  );
  const signed = await res.json();
  if (!res.ok) throw new Error(`Signing failed: ${JSON.stringify(signed.message)}`);

  const signature = signed.data.signedTransaction.signature;
  ```
</CodeGroup>

Pour signer depuis le portefeuille principal, utilisez plutôt `POST /v1/wallets/{walletId}/signing/typed-data` et définissez `from` sur l'adresse du portefeuille principal. La réponse est la [réponse des données typées](/fr/essentials/signing#réponse-des-données-typées) standard ; la signature se trouve dans `data.signedTransaction.signature`.

#### Étape 3 : Réessayer avec le paiement

Enveloppez la signature et l'autorisation dans un payload de paiement, encodez-le en base64 et envoyez-le dans l'en-tête `PAYMENT-SIGNATURE` sur la même requête :

```javascript JavaScript theme={null}
const paymentPayload = {
  x402Version: 2,
  resource: paymentRequired.resource,
  accepted,                              // the entry you chose from `accepts`
  payload: { signature, authorization },
};

const paid = await fetch('https://api.example.com/premium-data', {
  headers: {
    'PAYMENT-SIGNATURE': Buffer.from(JSON.stringify(paymentPayload)).toString('base64'),
  },
});
```

#### Étape 4 : Vérifier le règlement

Une réponse réussie inclut un en-tête `PAYMENT-RESPONSE` encodé en base64 :

```json theme={null}
{
  "success": true,
  "transaction": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
  "network": "eip155:8453",
  "payer": "0x947514e4B803e312C312da0F1B41fEDdbe15ae7a"
}
```

`transaction` est le hash on-chain du transfert USDC. Si le paiement échoue, l'API répond à nouveau `402`, et `PAYMENT-RESPONSE` contient un `errorReason` tel que `insufficient_funds`.

<Accordion title="Appeler une API x402 v1">
  Les serveurs en version 1 de x402 diffèrent du flux ci-dessus sur quatre points :

  * Les exigences de paiement se trouvent dans le **corps** de la réponse `402`, et non dans un en-tête.
  * Les réseaux sont nommés (`base`, `base-sepolia`) plutôt que `eip155:<chainId>`. Base correspond au chain ID `8453` ; Base Sepolia à `84532`.
  * Le champ du montant est `maxAmountRequired`, et non `amount`.
  * Le paiement est envoyé dans l'en-tête `X-PAYMENT` sous forme de JSON encodé en base64 avec `x402Version: 1`, `scheme`, `network` et le même objet `payload`, et le règlement revient dans `X-PAYMENT-RESPONSE`.

  L'étape de signature avec Blockradar est identique.
</Accordion>

### Règles de signature qui piègent les intégrations

| Règle | Ce qui se passe sinon |
| - | - |
| `domain.chainId` est un nombre JSON correspondant à la chaîne du portefeuille | `400 Chain ID mismatch`. `"8453"` sous forme de chaîne de caractères échoue également. |
| `types` ne contient que `TransferWithAuthorization` | Inclure `EIP712Domain` dans `types` échoue avec une erreur `ambiguous primary types or unused types`. Blockradar construit le type du domaine à partir de `domain`. |
| `message.from` est l'adresse qui signe | Le facilitateur rejette le paiement, car la signature correspond à une autre adresse. |
| Un nouveau `nonce` pour chaque paiement | USDC rejette un nonce réutilisé, le paiement ne peut donc pas être réglé. |
| L'adresse qui paie détient suffisamment d'USDC | Le facilitateur rejette le paiement pour solde insuffisant. Le gas n'est pas nécessaire. |

Chaque signature est enregistrée comme une transaction `SIGNED` et déclenche un [webhook](/fr/essentials/signing#événements-webhook) `signed.success`, ce qui vous fournit une piste d'audit de chaque paiement autorisé par votre agent. Une signature n'est pas un paiement : l'USDC ne bouge que lorsque le facilitateur du vendeur règle le paiement. Lorsque le vendeur est en dehors de Blockradar, le règlement apparaît comme un transfert sortant depuis l'adresse de l'agent. Pour rapprocher les paiements, comparez les webhooks `signed.success` à la transaction on-chain de l'en-tête `PAYMENT-RESPONSE`.

***

## Limites de x402

* **EVM uniquement.** Les paiements sont signés avec des données typées EIP-712, que Blockradar prend en charge uniquement sur les chaînes EVM. Solana et les autres réseaux x402 non EVM ne sont pas pris en charge.
* **Paiements EIP-3009 `exact` uniquement.** Les tokens dotés de `transferWithAuthorization`, comme USDC, fonctionnent. La méthode de transfert `permit2` et les autres schémas ne sont pas couverts.
* **Pas de nanopaiements Circle Gateway.** L'option de paiements groupés inférieurs au centime de Circle n'a pas été testée avec les portefeuilles Blockradar.

***

## Bonnes Pratiques

* **Appliquez des limites dans votre agent.** Blockradar signe toute requête bien formée provenant d'une clé API valide. Placez des limites par paiement et par jour dans le code de votre agent, et plafonnez l'exposition totale avec le solde de l'adresse de l'agent.
* **Une adresse par agent.** Des budgets séparés permettent de voir clairement quel agent a dépensé quoi, et de couper un agent en vidant son adresse.
* **Vérifiez le prix avant de signer.** Comparez `amount` au maximum que votre agent devrait payer pour cette ressource, et refusez tout montant supérieur.
* **Vérifiez le destinataire.** Si votre agent ne paie que des API connues, tenez une liste autorisée d'adresses `payTo`.
* **Utilisez `metadata` et les webhooks.** Taguez les adresses des agents avec `metadata`, et rapprochez les webhooks `signed.success` de la transaction on-chain de chaque `PAYMENT-RESPONSE`.
* **Verrouillez l'accès à l'API.** N'acceptez les requêtes API que depuis vos propres serveurs grâce à la [Liste Blanche IP](/fr/use-cases/ip-whitelist), afin qu'une clé divulguée ne puisse pas être utilisée ailleurs.
* **Testez d'abord sur Base Sepolia.** Utilisez un portefeuille testnet, `eip155:84532`, et de l'USDC testnet provenant des [faucets](/fr/use-cases/supported-assets) avant de dépenser des fonds réels.

***

## Référence API

| Endpoint | Description |
| - | - |
| [Sign Typed Data (Master Wallet)](/fr/api-reference/signing/master-wallet-typed-data) | Signe une autorisation de paiement depuis un portefeuille principal |
| [Sign Typed Data (Child Address)](/fr/api-reference/signing/child-address-typed-data) | Signe une autorisation de paiement depuis une adresse enfant |
| [Generate Address](/fr/api-reference/addresses/generate-address) | Crée une adresse dédiée pour le budget d'un agent |
| [Update Address](/fr/api-reference/addresses/update-address) | Active ou désactive l'auto-sweep pour une adresse |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.