# API des soldes de tokens de wallet : actifs ERC-20 et historique des transferts

> Source: https://docs.blockvectra.com/fr/guides/wallet-assets/

Créez une page des actifs de wallet avec l'API de données de wallet blockchain : utilisez l'[API des soldes de tokens](https://blockvectra.com/fr/data/balances/) pour les avoirs ERC-20 non nuls et l'[API des transferts de tokens](https://blockvectra.com/fr/data/transfers/) pour l'historique du wallet. Les développeurs et les agents IA utilisent les mêmes requêtes authentifiées. Avant d'interroger, lisez [GET /v1/status](https://api.blockvectra.com/v1/data) et vérifiez les champs `data_features` et `data_status` de la chaîne sélectionnée ; la couverture des soldes varie selon la chaîne. Les paramètres de requête et les schémas de réponse se trouvent dans la [référence de la Data API](https://docs.blockvectra.com/fr/api/data/).

## Tâches que ce guide vous aide à accomplir

* [Lire les soldes de tokens du wallet](#request-1-address-balances) avec une clé et paginer les avoirs ERC-20 non nuls.
* [Lire l'historique des transferts du wallet](#request-2-address-transfers) dans une fenêtre de blocs fixe et suivre les curseurs pour l'adresse sélectionnée.
* [Compléter les métadonnées des tokens](#request-3-token-metadata-and-tokensbatch) pour afficher les noms et les symboles aux côtés des soldes entiers bruts, en préservant les champs manquants.

## Les trois types de données nécessaires à une page des actifs de wallet

Une page des actifs de wallet peut afficher les soldes de tokens ERC-20 d'une adresse, l'historique des transferts de tokens et les métadonnées des tokens. La Data API fournit un point de terminaison pour chacun d'eux :

* **Soldes** : `GET /{chain}/addresses/{address}/balances` renvoie les soldes ERC-20 non nuls de l'adresse, triés par adresse de `token` croissante, avec le `symbol` et les `decimals` du token inclus lorsqu'ils sont disponibles. Une adresse sans solde renvoie `200` avec `data: []`.
* **Transferts** : `GET /{chain}/addresses/{address}/transfers` renvoie les transferts de tokens impliquant l'adresse dans une fenêtre de blocs requise, triés par `(block_number, log_index)` décroissants.
* **Métadonnées de tokens** : `GET /{chain}/tokens/{token}` lit le nom, le symbole, les décimales et l'offre totale d'un token par son adresse de contrat ; `POST /{chain}/tokens:batch` lit les mêmes métadonnées pour un maximum de 100 adresses en une seule requête.

Tous trois utilisent `https://api.blockvectra.com/v1/data` comme URL de base et l'en-tête de requête `x-api-key`, avec `robinhood_mainnet` comme chaîne d'exemple. Ils appartiennent respectivement aux fonctionnalités `balances`, `transfers` et `token_metadata` ; pour connaître les chaînes proposant chaque fonctionnalité, consultez la page des [chaînes prises en charge](https://docs.blockvectra.com/fr/chains/). Sur une chaîne ne disposant pas de la fonctionnalité, le point de terminaison renvoie `422 no_coverage`.

## Requête 1 : soldes d'adresses

Ce point de terminaison prend moins de paramètres, ce qui en fait une bonne première requête pour une page :

* `{chain}` (paramètre de chemin, obligatoire) : identifiant de chaîne, la valeur `chain` d'une entrée dans `GET /chains` (par exemple `robinhood_mainnet`). La correspondance est exacte et sensible à la casse ; les alias et les identifiants numériques de chaîne ne sont pas acceptés.
* `{address}` (paramètre de chemin, obligatoire) : adresse de 20 octets ; le préfixe `0x` est facultatif et la casse majuscule ou minuscule est acceptée.
* `limit` (paramètre de requête, facultatif) : taille de la page. Vaut 50 par défaut ; les valeurs supérieures à 500 sont ramenées à 500 ; `0` ou un non-entier renvoie `400 bad_request`.
* `cursor` (paramètre de requête, facultatif) : le `next_cursor` de la réponse précédente, renvoyé tel quel pour récupérer la page suivante. Un curseur n'est valide que pour la chaîne, le point de terminaison et les paramètres de requête qui l'ont émis ; le réutiliser ailleurs renvoie `400 bad_request`.

Il utilise une pagination par jeu de clés (keyset pagination) : `next_cursor` n'apparaît que lorsqu'il y a une page suivante. Sur la dernière page, la clé est entièrement absente, jamais `null`.

**cURL**

```bash
export BLOCKVECTRA_API_KEY=rgw_your_api_key

curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/0x1111111111111111111111111111111111111111/balances?limit=50" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY"
```


  **TypeScript**

```ts
const address = "0x1111111111111111111111111111111111111111";
const url = new URL(
  `https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/${address}/balances`,
);
url.searchParams.set("limit", "50");

const res = await fetch(url, {
  headers: { "x-api-key": process.env.BLOCKVECTRA_API_KEY! },
});
const balanceBody = await res.json();
console.log(balanceBody.data, balanceBody.meta);

// npx tsx example.mts
```


  **Python**

```python
import os
import requests

address = "0x1111111111111111111111111111111111111111"
res = requests.get(
    f"https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/{address}/balances",
    params={"limit": 50},
    headers={"x-api-key": os.environ["BLOCKVECTRA_API_KEY"]},
)
res.raise_for_status()
balance_body = res.json()
print(balance_body["data"], balance_body["meta"])
```


L'enveloppe de réponse est `AddressBalanceListEnvelope`, contenant `data` et `meta`. Chaque élément de `data` est un `AddressBalance` :

| Champ      | Type                | Description                                                                                                                                                           |
| ---------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `token`    | `string` (adresse)  | Adresse du contrat de token ; la forme canonique est `0x` suivi de 40 chiffres hexadécimaux en minuscules.                                                            |
| `balance`  | `string` (décimal)  | Solde entier brut, pouvant dépasser `2^53`, renvoyé sous la forme d'une chaîne décimale brute — jamais un nombre JSON, une notation scientifique ou de l'hexadécimal. |
| `symbol`   | `string` ou `null`  | Symbole du token, ou `null` lorsqu'il est indisponible.                                                                                                               |
| `decimals` | `integer` ou `null` | Décimales du token, de `0` à `255`, ou `null` lorsqu'elles sont indisponibles.                                                                                        |

## Requête 2 : transferts d'adresses

Le point de terminaison des transferts nécessite une fenêtre de blocs explicite : `from_block` et `to_block` sont tous deux obligatoires et doivent satisfaire `from_block <= to_block`. Il prend quelques paramètres supplémentaires :

* `standard` (paramètre de requête, obligatoire) : `erc20` ou `erc721`. Les requêtes restreintes à une adresse ne couvrent pas `erc1155` ; le transmettre renvoie `422 no_coverage`.
* `direction` (paramètre de requête, facultatif) : `in`, `out` ou `any` ; vaut `any` par défaut et filtre par direction relative à l'adresse.
* `token` (paramètre de requête, facultatif) : restreint les résultats à un contrat de token.
* `clamp` (paramètre de requête, facultatif) : seule la chaîne littérale `true` l'active ; toute autre valeur est traitée comme `false`.

Bornes de la fenêtre et finalité : un `to_block` explicite supérieur à `as_of_block` renvoie `409 not_indexed_yet` à moins que `clamp=true` ne le tronque à `as_of_block` ; une fenêtre plus large que la limite de la chaîne (`limits.max_window_blocks` issu de `GET /chains`) renvoie `409 window_too_large` à moins que `clamp=true` ne la tronque du côté le plus ancien (en augmentant `from_block` et en maintenant `to_block` fixe). Si `from_block` dépasse déjà lui-même `as_of_block`, l'erreur `409` persiste même avec `clamp=true`. Lorsque la fenêtre est tronquée ou partiellement couverte, le champ `meta.coverage` de la réponse vaut `"partial"` ; sinon, il vaut `"full"`.

Dans les enregistrements de transferts, les éléments ERC-20 ajoutent `amount` ; les éléments ERC-721 ajoutent `token_id`. Les deux incluent `token`, `standard`, `from`, `to`, `block_number`, `block_timestamp`, `tx_hash`, `tx_index` et `log_index`.

**cURL**

```bash
export BLOCKVECTRA_API_KEY=rgw_your_api_key

# 1) Lire as_of_block depuis la réponse des soldes.
AS_OF_BLOCK=$(curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/0x1111111111111111111111111111111111111111/balances" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY" | grep -o '"as_of_block":[0-9]*' | cut -d: -f2)

# 2) clamp=true tronque une fenêtre trop large ou un to_block supérieur à as_of_block, au lieu de renvoyer 409.
curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/0x1111111111111111111111111111111111111111/transfers?standard=erc20&from_block=0&to_block=$AS_OF_BLOCK&direction=any&clamp=true" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY"
```


  **TypeScript**

```ts
const address = "0x1111111111111111111111111111111111111111";

// 1) Lire as_of_block depuis les métadonnées de toute réponse précédente.
const head = await fetch(
  `https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/${address}/balances`,
  { headers: { "x-api-key": process.env.BLOCKVECTRA_API_KEY! } },
).then((r) => r.json());

// 2) Utiliser as_of_block comme borne supérieure de la fenêtre de transferts.
const url = new URL(
  `https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/${address}/transfers`,
);
url.searchParams.set("standard", "erc20");
url.searchParams.set("from_block", "0");
url.searchParams.set("to_block", String(head.meta.as_of_block));
url.searchParams.set("direction", "any");
url.searchParams.set("clamp", "true");

const res = await fetch(url, {
  headers: { "x-api-key": process.env.BLOCKVECTRA_API_KEY! },
});
const body = await res.json();
console.log(body.data, body.meta);

// npx tsx example.mts
```


  **Python**

```python
import os
import requests

address = "0x1111111111111111111111111111111111111111"
headers = {"x-api-key": os.environ["BLOCKVECTRA_API_KEY"]}

# 1) Lire as_of_block depuis les métadonnées de toute réponse précédente.
head = requests.get(
    f"https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/{address}/balances",
    headers=headers,
).json()

# 2) Utiliser as_of_block comme borne supérieure de la fenêtre de transferts.
res = requests.get(
    f"https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/{address}/transfers",
    params={
        "standard": "erc20",
        "from_block": 0,
        "to_block": head["meta"]["as_of_block"],
        "direction": "any",
        "clamp": "true",
    },
    headers=headers,
)
res.raise_for_status()
body = res.json()
print(body["data"], body["meta"])
```


## Parcourir tous les transferts avec la pagination

Le champ `next_cursor` du point de terminaison des transferts d'adresses est optimiste : il n'apparaît que lorsque la page a renvoyé exactement `limit` lignes, de sorte qu'une page peut comporter un `next_cursor` tout en s'avérant être la dernière page. Ne vous arrêtez pas lorsqu'une page est vide ; suivez `next_cursor` jusqu'à ce que la clé soit absente.

Le code ci-dessous récupère chaque transfert dans la fenêtre :

**TypeScript**

```ts
const address = "0x1111111111111111111111111111111111111111";
const head = await fetch(
  `https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/${address}/balances`,
  { headers: { "x-api-key": process.env.BLOCKVECTRA_API_KEY! } },
).then((r) => r.json());
const asOfBlock = head.meta.as_of_block;
const transfers: unknown[] = [];
let cursor: string | undefined;

do {
  const url = new URL(
    `https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/${address}/transfers`,
  );
  url.searchParams.set("standard", "erc20");
  url.searchParams.set("from_block", "0");
  url.searchParams.set("to_block", String(asOfBlock));
  url.searchParams.set("limit", "500");
  // clamp truncates from the older end
  url.searchParams.set("clamp", "true");
  if (cursor) url.searchParams.set("cursor", cursor);

  const res = await fetch(url, {
    headers: { "x-api-key": process.env.BLOCKVECTRA_API_KEY! },
  });
  const page = await res.json();
  transfers.push(...page.data);
  cursor = page.next_cursor; // absent on the last page
} while (cursor);
```


  **Python**

```python
import os
import requests

address = "0x1111111111111111111111111111111111111111"
head = requests.get(
    f"https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/{address}/balances",
    headers={"x-api-key": os.environ["BLOCKVECTRA_API_KEY"]},
).json()
as_of_block = head["meta"]["as_of_block"]
transfers = []
cursor = None

while True:
    params = {
        "standard": "erc20",
        "from_block": 0,
        "to_block": as_of_block,
        "limit": 500,
        # clamp truncates from the older end
        "clamp": "true",
    }
    if cursor:
        params["cursor"] = cursor
    res = requests.get(
        f"https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/{address}/transfers",
        params=params,
        headers={"x-api-key": os.environ["BLOCKVECTRA_API_KEY"]},
    )
    res.raise_for_status()
    page = res.json()
    transfers.extend(page["data"])
    cursor = page.get("next_cursor")  # absent on the last page
    if not cursor:
        break
```


## Requête 3 : métadonnées de tokens et tokens:batch

Lisez un seul token avec `GET /{chain}/tokens/{token}` ; le chemin ne prend que `{chain}` et `{token}`, sans pagination. L'enveloppe de réponse est `TokenEnvelope`, et `data` est un `Token` :

| Champ                 | Type                  | Description                                                                                                                                                                              |
| --------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `address`             | `string` (adresse)    | Adresse du contrat de token.                                                                                                                                                             |
| `standard`            | `string`              | `erc20`, `erc721` ou `unknown`.                                                                                                                                                          |
| `name`                | `string` ou `null`    | Nom du token, ou `null` lorsqu'il est indisponible.                                                                                                                                      |
| `symbol`              | `string` ou `null`    | Symbole du token, ou `null` lorsqu'il est indisponible.                                                                                                                                  |
| `decimals`            | `integer` ou `null`   | Décimales du token, de `0` à `255`, ou `null` lorsqu'elles sont indisponibles.                                                                                                           |
| `total_supply`        | `string` ou `null`    | Offre totale brute ; l'API n'applique pas d'ajustement selon les `decimals`. `null` lorsqu'elle est indisponible.                                                                        |
| `first_seen_block`    | `integer` (int64)     | Hauteur de bloc où le token a été vu pour la première fois.                                                                                                                              |
| `metadata_updated_at` | `string` (horodatage) | Heure UTC de la dernière mise à jour des métadonnées.                                                                                                                                    |
| `metadata_block`      | `integer` (int64)     | Hauteur de bloc à laquelle les métadonnées ont été lues.                                                                                                                                 |
| `metadata_status`     | `string`              | `ok`, `partial` ou `unavailable`.                                                                                                                                                        |
| `metadata_issues`     | `object`              | Enregistrements d'anomalies par champ indexés par `name`, `symbol`, `decimals`, `total_supply`, avec les valeurs `reverted`, `no_data`, `invalid_encoding` ou `temporarily_unavailable`. |

Un `{token}` qui n'est pas une adresse valide de 20 octets renvoie `400 bad_request` ; un `{token}` inconnu renvoie `404 not_found` ; une `{chain}` inconnue renvoie `404 unknown_chain`.

Le point de terminaison des soldes inclut déjà `symbol` et `decimals` lorsqu'ils sont disponibles, mais les deux peuvent valoir `null`. Pour compléter le nom et les décimales de chaque token dans un wallet, utilisez `POST /{chain}/tokens:batch` :

* Le corps de la requête est `{"addresses": [...]}` avec au maximum 100 adresses par requête ; plus de 100 entrées, ou une entrée qui n'est pas une adresse valide de 20 octets, renvoie `400 bad_request` (la requête échoue sur la première adresse invalide rencontrée).
* Les adresses introuvables ne déclenchent pas d'erreur ; elles sont répertoriées dans `data.missing`, tandis que `data.tokens` contient uniquement les tokens dont les métadonnées ont été trouvées.
* Les adresses dupliquées sont dédupliquées dans `tokens` et `missing`, chacune selon l'ordre de première apparition dans la requête.

**cURL**

```bash
export BLOCKVECTRA_API_KEY=rgw_your_api_key

# Token unique
curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/tokens/0x1111111111111111111111111111111111111111" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY"

# Lot : jusqu'à 100 adresses par requête
curl -s -X POST "https://api.blockvectra.com/v1/data/robinhood_mainnet/tokens:batch" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"addresses":["0x1111111111111111111111111111111111111111","0x2222222222222222222222222222222222222222"]}'
```


  **TypeScript**

```ts
// Single token
const single = await fetch(
  "https://api.blockvectra.com/v1/data/robinhood_mainnet/tokens/0x1111111111111111111111111111111111111111",
  { headers: { "x-api-key": process.env.BLOCKVECTRA_API_KEY! } },
).then((r) => r.json());
console.log(single.data);

// Lot : grouper par 100 adresses pour enrichir les tokens issus de la réponse des soldes
const BATCH_SIZE = 100;
const addresses = balanceBody.data.map((item: { token: string }) => item.token);
const tokens = new Map<string, unknown>();
const missing: string[] = [];

for (let i = 0; i < addresses.length; i += BATCH_SIZE) {
  const res = await fetch("https://api.blockvectra.com/v1/data/robinhood_mainnet/tokens:batch", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": process.env.BLOCKVECTRA_API_KEY!,
    },
    body: JSON.stringify({ addresses: addresses.slice(i, i + BATCH_SIZE) }),
  });
  const body = await res.json();
  for (const token of body.data.tokens) tokens.set(token.address, token);
  missing.push(...body.data.missing);
}

// npx tsx example.mts
```


  **Python**

```python
import os
import requests

headers = {"x-api-key": os.environ["BLOCKVECTRA_API_KEY"]}

# Token unique
single = requests.get(
    "https://api.blockvectra.com/v1/data/robinhood_mainnet/tokens/0x1111111111111111111111111111111111111111",
    headers=headers,
).json()
print(single["data"])

# Lot : grouper par 100 adresses pour enrichir les tokens issus de la réponse des soldes
BATCH_SIZE = 100
addresses = [item["token"] for item in balance_body["data"]]
tokens = {}
missing = []

for i in range(0, len(addresses), BATCH_SIZE):
    res = requests.post(
        "https://api.blockvectra.com/v1/data/robinhood_mainnet/tokens:batch",
        json={"addresses": addresses[i : i + BATCH_SIZE]},
        headers={**headers, "Content-Type": "application/json"},
    )
    res.raise_for_status()
    body = res.json()
    for token in body["data"]["tokens"]:
        tokens[token["address"]] = token
    missing.extend(body["data"]["missing"])
```


## Ajuster les montants selon les décimales

Le champ de solde `balance` et le champ de transfert ERC-20 `amount` sont des entiers bruts restitués sous forme de chaînes décimales (`UInt256String`) ; l'offre totale `total_supply` d'un token est également un entier brut on-chain sans ajustement de `decimals`. Pour afficher une quantité lisible par un humain, divisez par les `decimals` de ce token.

* `decimals` provient du champ `symbol`/`decimals` propre à l'élément de solde, ou de `GET /{chain}/tokens/{token}` et `POST /{chain}/tokens:batch` ; il peut valoir `null`.
* Ces valeurs pouvant dépasser `2^53`, n'effectuez pas l'opération arithmétique avec un nombre JSON : utilisez `BigInt` en TypeScript et `Decimal` en Python, en analysant la chaîne décimale telle quelle pour éviter toute perte de précision.

**TypeScript**

```ts
function toDisplayAmount(raw: string, decimals: number | null): string {
  if (decimals === null) return raw; // pas de métadonnées de décimales : conserver l'entier brut
  const value = BigInt(raw);
  const base = 10n ** BigInt(decimals);
  const whole = value / base;
  const fraction = (value % base)
    .toString()
    .padStart(decimals, "0")
    .replace(/0+$/, "");
  return fraction ? `${whole}.${fraction}` : whole.toString();
}

// balance.balance est une chaîne décimale brute ; decimals provient du même élément ou de tokens:batch.
const display = toDisplayAmount(balance.balance, balance.decimals);
```


  **Python**

```python
from decimal import Decimal


def to_display_amount(raw: str, decimals: int | None) -> str:
    if decimals is None:
        return raw  # pas de métadonnées de décimales : conserver l'entier brut
    value = Decimal(raw)  # analyser la chaîne décimale avec précision
    return format(value.scaleb(-decimals).normalize(), "f")


# balance["balance"] est une chaîne décimale brute ; decimals provient du même élément ou de tokens:batch.
display = to_display_amount(balance["balance"], balance["decimals"])
```


## Fraîcheur des données

Chaque réponse réussie ciblée sur une chaîne comporte `meta` :

* `as_of_block` : le bloc le plus récent entièrement écrit de la chaîne. Les points de terminaison délimités par des blocs fournissent des données jusqu'à cette hauteur.
* `safe_block` : un marqueur indiquant l'étiquette de bloc de consensus `safe` du nœud (`null` tant qu'il est inconnu). Jamais inférieur à `finalized_block`, et ne tronque, ne rejette ni ne retarde les réponses.
* `finalized_block` : un marqueur indiquant l'étiquette de bloc de consensus `finalized` du nœud (`null` tant qu'il est inconnu). Il ne tronque, ne rejette ni ne retarde les réponses ; les clients décident du niveau de sécurité requis à partir du marqueur (comme le statut de confirmation).
* `coverage` : `"full"` ou `"partial"`. Les transferts d'adresses et points de terminaison similaires indiquent `"partial"` lorsque `clamp` a restreint la fenêtre servie, ou lorsque la fenêtre commence avant le premier bloc indexé de la chaîne.
* `refreshed_at` : moment où les données sous-jacentes à la réponse ont été mises à jour pour la dernière fois (UTC). Peut valoir `null` : `null` signifie que l'heure de mise à jour des données est inconnue et qu'elles doivent être traitées comme périmées ; les points de terminaison basés sur des blocs renvoient toujours une valeur.
* Il répète également `chain`, `chain_slug` et `chain_external_id`.

Un schéma courant : lisez `meta.as_of_block` dès la première réponse pour lire jusqu'au bloc indexé le plus récent, et vérifiez `meta.safe_block` / `meta.finalized_block` si vous souhaitez afficher le statut confirmé.

## Estimation en CU pour le chargement d'une page

Chaque méthode est facturée selon son poids en CU, lu depuis l'API des forfaits de la plateforme :

**Poids en CU par appel**

| Méthode | CU par appel |
| --- | --- |
| `data.address_balances` | 25 |
| `data.address_transfers` | 25 |
| `data.tokens_batch` | 10 |

**Un chargement de page (estimé)**

1 requête balances + 3 pages de transferts + 1 requête(s) `tokens:batch`, 5 appels au total, environ 110 CU. L'utilisation réelle dépend du nombre de pages et de tokens.

Pour les décisions de facturation et les réponses d'erreur non facturées, consultez les [règles de facturation](https://docs.blockvectra.com/fr/guides/billing-rules/). Si vous n'avez pas besoin d'un historique de transferts indexé mais des logs des blocs les plus récents, lisez d'abord [Données récentes de nœud vs historique indexé](https://docs.blockvectra.com/fr/guides/logs-vs-transfers/) avant de décider de basculer vers `eth_getLogs`.

## Prochaines étapes

* [Parcourir le catalogue des jeux de données](https://blockvectra.com/fr/data/) pour découvrir chaque jeu de données indexé par BlockVectra.
* [Consulter le forfait gratuit et les tarifs](https://blockvectra.com/fr/pricing/#free) pour vérifier ce que comprend votre compte.
* [Se connecter à la console](https://console.blockvectra.com/login/?next=%2Fkeys%2F) pour créer une API key.
