# Portefeuilles statiques

> Adresses de dépôt permanentes liées à une commande ou un utilisateur spécifique, parfaites pour les paiements récurrents et de longue durée.

Les portefeuilles statiques sont des adresses permanentes pour recevoir des paiements en cryptomonnaie. Ils sont liés à un `order_id` spécifique et sont uniques par la combinaison `project_id + order_id + currency + network`.

Utilisez les portefeuilles statiques pour :

- Les dépôts récurrents du même utilisateur
- Les adresses de paiement de longue durée affichées sur un profil utilisateur
- Les flux de dépôt à fort volume où vous souhaitez une adresse stable par utilisateur

## Créer un portefeuille statique

`POST /v1/static-wallet`

### Paramètres de la requête

| Champ | Type | Requis | Description |
|-------|------|--------|-------------|
| `currency` | string | oui | Cryptomonnaie (USDT, BTC, ETH, etc.) |
| `network` | string | oui | Code de réseau |
| `order_id` | string | oui | Votre ID de commande/utilisateur (jusqu'à 255 caractères) |
| `label` | string | non | Libellé du portefeuille (jusqu'à 255 caractères) |
| `url_callback` | string | oui | URL pour les notifications webhook |
| `invite_code` | string | non | Code parrain |

### Exemple de requête

```json
{
  "currency": "USDT",
  "network": "TRX-TRC20",
  "order_id": "USER-123",
  "label": "User deposit #123",
  "url_callback": "https://your-site.com/webhook/static"
}
```

### Exemple de réponse

```json
{
  "state": 0,
  "result": {
    "uuid": "019b2265-34d8-7001-a230-8f97de90d481",
    "address": "TXYZabc123...",
    "currency": "USDT",
    "network": "TRX-TRC20",
    "label": "User deposit #123",
    "order_id": "USER-123",
    "status": "active",
    "url": "https://go.2328.io/static/019b2265-34d8-7001-a230-8f97de90d481",
    "created_at": "2026-01-20T12:00:00Z",
    "qr": "data:image/png;base64,iVBORw0..."
  }
}
```

## Informations sur le portefeuille

Récupérez les informations d'un portefeuille statique par `uuid` ou `address`.

`POST /v1/static-wallet/info`

### Paramètres de la requête

| Champ | Type | Requis | Description |
|-------|------|--------|-------------|
| `uuid` | string | oui* | UUID du portefeuille statique |
| `address` | string | oui* | Adresse blockchain du portefeuille |

> **INFO:** Au moins l'un des champs `uuid` ou `address` est requis.

### Exemple de réponse

```json
{
  "state": 0,
  "result": {
    "uuid": "019b2265-34d8-7001-a230-8f97de90d481",
    "address": "TXYZabc123...",
    "currency": "USDT",
    "network": "TRX-TRC20",
    "status": "active",
    "total_received": "1250.50",
    "transactions_count": 3,
    "created_at": "2026-01-20T12:00:00Z",
    "qr": "data:image/png;base64,iVBORw0..."
  }
}
```

- `total_received` — somme de tous les dépôts reçus par ce portefeuille, en `currency`.
- `transactions_count` — nombre de dépôts reçus à ce jour.
- `qr` — data URI Base64 du QR code de l'adresse de dépôt (toujours présent pour les portefeuilles statiques, l'adresse étant attribuée à la création).

## Liste des portefeuilles

`POST /v1/static-wallet/list`

### Paramètres de la requête

| Champ | Type | Requis | Description |
|-------|------|--------|-------------|
| `status` | string | non | Filtrer par statut (`active`, `inactive`) |
| `currency` | string | non | Filtrer par devise |
| `network` | string | non | Filtrer par réseau |
| `order_id` | string | non | Filtrer par order_id |
| `page` | int | non | Numéro de page (par défaut : 1) |
| `per_page` | int | non | Éléments par page (par défaut : 20, max. : 100) |

### Exemple de réponse

```json
{
  "state": 0,
  "result": {
    "items": [
      {
        "uuid": "019b2265-...",
        "address": "TXYZabc123...",
        "currency": "USDT",
        "network": "TRX-TRC20",
        "status": "active",
        "total_received": "1250.50",
        "transactions_count": 3
      }
    ],
    "paginate": {
      "count": 1,
      "current_page": 1,
      "per_page": 20,
      "total": 1,
      "total_pages": 1,
      "has_more": false
    }
  }
}
```

## Activer / désactiver un portefeuille

Activez ou désactivez l'acceptation de nouveaux paiements par un portefeuille statique.

`POST /v1/static-wallet/disable`

`POST /v1/static-wallet/enable`

### Requête

Les deux endpoints prennent un seul paramètre :

```json
{
  "uuid": "019b2265-34d8-7001-a230-8f97de90d481"
}
```

### Exemple de réponse

```json
{
  "state": 0,
  "result": {
    "uuid": "019b2265-34d8-7001-a230-8f97de90d481",
    "status": "inactive",
    "message": "Static wallet disabled successfully"
  }
}
```

Pour `enable`, `status` vaut `"active"` et `message` vaut `"Static wallet enabled successfully"`.

## Transactions du portefeuille

Récupérez la liste de tous les dépôts reçus par un portefeuille statique.

`POST /v1/static-wallet/transactions`

### Paramètres de la requête

| Champ | Type | Requis | Description |
|-------|------|--------|-------------|
| `uuid` | string | oui | UUID du portefeuille statique |
| `date_from` | date | non | Date de début (YYYY-MM-DD) |
| `date_to` | date | non | Date de fin (YYYY-MM-DD) |
| `page` | int | non | Numéro de page (par défaut : 1) |
| `per_page` | int | non | Éléments par page (par défaut : 15, max. : 5000) |

### Exemple de réponse

```json
{
  "state": 0,
  "result": {
    "items": [
      {
        "uuid": "abc123-def456-...",
        "order_id": "USER-123",
        "amount": "100.00",
        "currency": "USDT",
        "payment_status": "paid",
        "txid": "0xabc123def456...",
        "fee_amount": "3.00",
        "net_amount": "97.00",
        "created_at": "2026-01-20T15:30:00Z"
      }
    ],
    "paginate": {
      "count": 1,
      "hasPages": true,
      "perPage": 15,
      "page": 1
    }
  }
}
```

- `fee_amount` — frais de plateforme déduits de ce dépôt, en `currency`.
- `net_amount` — montant crédité au solde marchand après les frais.

## Webhooks de portefeuille statique

Lorsqu'un paiement est reçu sur un portefeuille statique, le système envoie un webhook à `url_callback`.

> **WARNING:** Le format des webhooks pour les portefeuilles statiques diffère de celui des webhooks de paiement classiques. En particulier, les webhooks de portefeuille statique incluent un champ `merchant_amount` que vous devez utiliser pour le crédit.

### Payload du webhook

```json
{
  "uuid": "a28b293f-5c76-4053-8062-ae9ca4ab784b",
  "order_id": "USER-7666308594",
  "amount": "10.00000000",
  "currency": "USDT",
  "amount_usd": "10.00000000",
  "exchange_rate": "1.00000000",
  "payer_currency": "USDT",
  "payer_amount": "10.00000000",
  "network": "TRX-TRC20",
  "address": "TMU9Tgpchvgbywkbj5SdC8KJS73t5m3M7G",
  "payment_status": "paid",
  "txid": "8369ede26a0da05b1bae154b4bb4072eb2453db30ba86b21831902670929454f",
  "tx_explorer_url": "https://tronscan.org/#/transaction/8369ede26a0da05b1bae154b4bb4072eb2453db30ba86b21831902670929454f",
  "payment_amount": "10.00000000",
  "merchant_amount": "9.920000000000000000",
  "created_at": "2026-05-09T16:13:04+03:00",
  "sign": "dd958d1405febce670a9a196e9141784b9f2a5f39cd6d1832d6f3f68d0de1e10"
}
```

> **INFO:** Les webhooks de portefeuille statique **n'incluent pas** `url` ni `expires_at` (l'adresse étant permanente, ce n'est pas une session). Ils **incluent** `exchange_rate` et `created_at`.

### Référence des champs

| Champ | Type | Description |
|-------|------|-------------|
| `uuid` | string | UUID de la transaction (facture) pour ce dépôt |
| `order_id` | string | `order_id` de votre portefeuille statique |
| `amount` | decimal (8 dp) | Montant en crypto reçu |
| `currency` | string | Crypto reçue (correspond à la `currency` du portefeuille) |
| `amount_usd` | decimal (8 dp) | Valeur en USD au moment de la réception |
| `exchange_rate` | decimal | Taux crypto / USD utilisé |
| `payer_currency` | string | Identique à `currency` pour les portefeuilles statiques |
| `payer_amount` | decimal (8 dp) | Identique à `amount` pour les portefeuilles statiques |
| `network` | string | Réseau blockchain |
| `address` | string | Adresse du portefeuille statique |
| `payment_status` | string | Statut actuel du d?p?t ; g?n?ralement `paid`, mais le contr?le AML peut produire `aml_lock`, ? ne pas cr?diter automatiquement |
| `txid` | string | Hash de la transaction blockchain |
| `tx_explorer_url` | string \| null | URL de la transaction dans l’explorateur blockchain. Vaut `null` si `txid` est absent ou si le transfert est un P2P interne. |
| `payment_amount` | decimal (8 dp) | Identique à `amount` |
| `merchant_amount` | decimal (18 dp) | **Montant après déduction des frais** — utilisez-le pour le crédit |
| `created_at` | string (ISO 8601) | Date de réception du dépôt |
| `sign` | string (hex) | Signature HMAC-SHA256 du payload |

## Bonnes pratiques

- **`order_id` unique** — Utilisez un `order_id` unique pour chaque utilisateur ou commande
- **Idempotence** — Vérifiez `txid` avant traitement pour éviter les doubles crédits
- **Vérifiez les signatures** — Vérifiez TOUJOURS la signature `sign` avant de créditer des fonds
- **Utilisez `merchant_amount`** — Créditez les utilisateurs en vous basant sur `merchant_amount`, pas sur `payment_amount`

## Cycle de vie et idempotence

Un portefeuille statique est une identité de dépôt réutilisable, pas une facture. Il n'a pas de montant attendu et pas de date d'expiration. Une adresse peut générer un nombre quelconque de transactions de dépôt au cours de sa durée de vie.

La création est idempotente pour le même projet marchand, `order_id`, `currency`, et `network` : le portefeuille existant est retourné. Gardez ce tuple stable et conservez le portefeuille retourné `uuid` ; n'utilisez pas un nouveau `order_id` chaque fois que le même client ouvre l'écran de dépôt.

L'idempotence du dépôt est différente de l'idempotence du portefeuille :

- `order_id` identifie la correspondance portefeuille/client réutilisable ;
- le portefeuille `uuid` identifie l'enregistrement permanent du portefeuille ;
- webhook `uuid` identifie une transaction de dépôt détectée ;
- `txid` identifie le transfert sur la blockchain et est la clé principale de déduplication pour le crédit.

Utilisez une contrainte d'unicité de base de données pour l'identité chaîne/réseau/txid traitée et réclamez-la dans la même transaction qui crédite le solde interne du client.

## Activer et désactiver la sémantique

Désactiver un portefeuille empêche l'application de le traiter comme une cible de dépôt active ; cela n'efface pas l'adresse ni son historique et ne peut pas arrêter un transfert blockchain déjà envoyé par un utilisateur.

> **DANGER:** Ne dites jamais aux utilisateurs que les fonds envoyés à une adresse inactive sont automatiquement retournés. Les transferts sur blockchain sont irréversibles. Désactivez uniquement après avoir retiré l'adresse de votre interface utilisateur et maintenez une procédure de récupération opérationnelle pour les dépôts tardifs.

La réactivation préserve la même identité de portefeuille et l'adresse. Ne créez pas de remplacement simplement pour changer l'étiquette ; les étiquettes ne sont pas des identifiants de règlement.

## Cas limites des portefeuilles statiques

| Situation | Gestion correcte |
|-----------|------------------|
| Demande de création en double | Acceptez le portefeuille existant retourné et vérifiez son tuple persistant au lieu d'attendre une nouvelle adresse. |
| Dépôts multiples sur une seule adresse | Créez une ligne de dépôt locale distincte pour chaque transaction `uuid`/`txid` ; ne marquez jamais le portefeuille lui-même comme « payé ». |
| Webhook en double | Retournez HTTP 200 après avoir trouvé le txid déjà engagé ; ne créditez jamais à nouveau. |
| Délai de confirmation ou ré-observation de la chaîne | Gardez le traitement idempotent et réconciliez à partir de `/v1/static-wallet/transactions`. |
| Dépôt inférieur au minimum de conversion automatique | Attendez-vous à un crédit de la devise source sans bloc `convert` complété. |
| Conversion automatique réussie | Stockez séparément les valeurs de paiement source et le résultat cible `convert`. |
| Token incorrect ou réseau incorrect | Ne pas fabriquer un crédit. Enregistrez les preuves et escaladez au support/récupération car la récupérabilité dépend de la chaîne. |
| Chaîne basée sur mémo/étiquette | Afficher et valider chaque champ de destination renvoyé par la plateforme ; une adresse seule peut être insuffisante lorsqu'un mémo est requis. |
| Verrouillage AML | Ne créditez pas l'utilisateur final tant que le statut autoritaire n'est pas libéré via le processus de conformité. |
| Portefeuille désactivé après l'affichage de l'adresse | Retirez-le immédiatement de l'interface utilisateur, mais continuez à surveiller les alertes opérationnelles pour les transferts tardifs. |

## Modèle de rapprochement

Exécutez un travail périodique qui parcourt `/v1/static-wallet/transactions`, met à jour les dépôts par txid, et compare leur `merchant_amount`, le statut et le résultat de conversion optionnel avec votre grand livre interne. La livraison par webhook devrait rendre la réconciliation rapide, mais la réconciliation doit la rendre complète.