# Créer une transaction de monnaie virtuelle

> Crédite ou débite une ou plusieurs monnaies virtuelles pour un profil en une seule transaction atomique. Utilisez un `amount` positif pour créditer (accorder) et un `amount` négatif pour débiter (dépenser). Tous les éléments sont appliqués ensemble — si l'un échoue, aucun n'est appliqué.
>
> Chaque code de monnaie ne peut apparaître qu'une seule fois par requête. Un crédit via ce point de terminaison crée toujours un solde sans expiration.

## OpenAPI

```yaml
/api-specs/adapty-api.yaml post /api/v2/server-side-api/vc/transactions/
openapi: 3.1.0
info:
  title: API côté serveur Adapty
  version: 1.0.0
servers:
  - url: https://api.adapty.io
    description: Serveur de production
paths:
  /api/v2/server-side-api/vc/transactions/:
    post:
      summary: Créer une transaction de monnaie virtuelle
      description: |
        Crédite ou débite une ou plusieurs monnaies virtuelles pour un profil en une seule transaction atomique. Utilisez un `amount` positif pour créditer (accorder) et un `amount` négatif pour débiter (dépenser). Tous les éléments sont appliqués ensemble — si l'un échoue, aucun n'est appliqué.

        Chaque code de monnaie ne peut apparaître qu'une seule fois par requête. Un crédit via ce point de terminaison crée toujours un solde sans expiration.
      operationId: createVirtualCurrencyTransaction
      tags:
        - Virtual Currency
      security:
        - apikeyAuth: []
      parameters:
        - name: adapty-customer-user-id
          in: header
          required: false
          schema:
            type: string
          description: L'identifiant unique du client dans votre système. `adapty-customer-user-id` ou `adapty-profile-id` est requis.
        - name: adapty-profile-id
          in: header
          required: false
          schema:
            type: string
          description: L'identifiant unique du profil dans votre système. Meilleure option si vous travaillez avec des profils anonymes. `adapty-customer-user-id` ou `adapty-profile-id` est requis.
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            format: uuid
          description: |
            Un UUID v4 qui rend la requête idempotente. Si vous relancez une requête avec la même clé, Adapty renvoie le résultat de la transaction originale sans modifier à nouveau les soldes. Doit être un UUID v4 valide.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/VirtualCurrencyTransactionRequest"
            examples:
              debit:
                summary: Dépenser (débiter) une monnaie
                value:
                  items:
                    - currency_code: COINS
                      amount: -10
              credit:
                summary: Accorder (créditer) une monnaie
                value:
                  items:
                    - currency_code: COINS
                      amount: 500
              multi_currency:
                summary: Débiter deux monnaies simultanément
                value:
                  items:
                    - currency_code: GOLD
                      amount: -50
                    - currency_code: SILVER
                      amount: -200
              conversion:
                summary: Convertir une monnaie en une autre
                value:
                  items:
                    - currency_code: SILVER
                      amount: -100
                    - currency_code: GOLD
                      amount: 10
                  metadata:
                    reason: exchange
      responses:
        "200":
          description: Transaction appliquée avec succès
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/VirtualCurrencyTransactionResponse"
              example:
                transaction_id: 0190e8a4-1c2b-7def-8abc-2c1a4b6d8e90
                balances:
                  - code: COINS
                    name: Gold Coins
                    balance: 12950
                    held: 0
                    available: 12950
        "400":
          description: |
            Requête incorrecte. Le champ `error_code` identifie la cause : `insufficient_balance`, `unknown_currency`, `duplicate_currency`, `amount_zero`, `balance_overflow`, `empty_items`, ou `idempotency_key_invalid`.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
              example:
                errors:
                  - source: currency_code
                    errors:
                      - Insufficient balance for currency COINS
                error_code: insufficient_balance
                status_code: 400
        "401":
          description: Non autorisé. La clé API est manquante ou invalide.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Interdit. L'API serveur pour les monnaies virtuelles n'est pas activée pour cette application. Contactez le support Adapty pour en demander l'accès.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
              example:
                errors:
                  - source: null
                    errors:
                      - Server API for virtual currencies is not enabled for this app. Contact Adapty support to request access.
                error_code: feature_not_enabled
                status_code: 403
        "404":
          description: Profil introuvable.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: |
            Conflit. Le champ `error_code` identifie la cause :

            - `idempotency_in_flight` — une requête avec la même `Idempotency-Key` est toujours en cours de traitement. Réessayez après l'intervalle indiqué dans l'en-tête de réponse `Retry-After`.
            - `duplicate_source_transaction` — la transaction du store sous-jacente a déjà été créditée, elle n'est donc pas appliquée à nouveau.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
              example:
                errors:
                  - source: null
                    errors:
                      - A similar request is being processed.
                error_code: idempotency_in_flight
                status_code: 409
        "422":
          description: |
            Entité non traitable. Le corps de la requête n'a pas passé la validation du schéma — par exemple, `items` contient plus de 20 entrées, ou une clé ou valeur de `metadata` ne respecte pas ses contraintes.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: |
            Trop de requêtes. La limite de débit par application ou globale a été dépassée (`error_code` est `rate_limited`). Les limites par défaut sont 600 requêtes par minute par application et 6 000 requêtes par minute globalement.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "500":
          description: Erreur interne du serveur
components:
  schemas:
    VirtualCurrencyTransactionRequest:
      type: object
      description: Corps de la requête pour créer une transaction de monnaie virtuelle.
      properties:
        items:
          type: array
          minItems: 1
          maxItems: 20
          description: Ajustements de solde à appliquer de manière atomique. Chaque code de monnaie ne peut apparaître qu'une seule fois.
          items:
            $ref: "#/components/schemas/VirtualCurrencyBalanceAdjustment"
        metadata:
          type: object
          nullable: true
          additionalProperties:
            type: string
          description: |
            Paires clé-valeur optionnelles stockées avec la transaction. Maximum 5 clés. Chaque clé correspond à `^[a-z0-9_]{1,30}$`, et chaque valeur comporte au plus 200 caractères.
      required:
        - items
    VirtualCurrencyTransactionResponse:
      type: object
      description: Résultat d'une transaction de monnaie virtuelle.
      properties:
        transaction_id:
          type: string
          format: uuid
          description: Identifiant unique de la transaction créée.
        balances:
          type: array
          description: |
            Solde après transaction pour chaque monnaie affectée par cette requête (une entrée par élément dans `items`). Pour consulter la liste complète des soldes du profil, utilisez `GET /api/v2/server-side-api/vc/balances/`.
          items:
            $ref: "#/components/schemas/VirtualCurrencyBalanceSnapshot"
      required:
        - transaction_id
        - balances
    ErrorResponse:
      type: object
      properties:
        errors:
          type: array
          items:
            type: object
            properties:
              source:
                type: string
                nullable: true
                description: Source de l'erreur
              errors:
                type: array
                items:
                  type: string
                description: Tableau de messages d'erreur
        error_code:
          type: string
          description: Nom court de l'erreur
        status_code:
          type: integer
          description: Code de statut HTTP
      required:
        - errors
        - error_code
        - status_code
    VirtualCurrencyBalanceAdjustment:
      type: object
      properties:
        currency_code:
          type: string
          description: Le code de la monnaie virtuelle à ajuster.
        amount:
          type: integer
          format: int32
          description: |
            Le montant à appliquer. Une valeur positive crédite (accorde) la monnaie ; une valeur négative la débite (dépense). Ne peut pas être nul.
      required:
        - currency_code
        - amount
    VirtualCurrencyBalanceSnapshot:
      type: object
      properties:
        code:
          type: string
          description: Code de la monnaie virtuelle.
        name:
          type: string
          description: Nom d'affichage de la monnaie virtuelle.
        balance:
          type: integer
          format: int32
          minimum: 0
          description: Solde total, y compris les montants actuellement retenus.
        held:
          type: integer
          format: int32
          minimum: 0
          description: Somme de toutes les retenues actives (montants réservés). Actuellement toujours 0.
        available:
          type: integer
          format: int32
          description: Solde disponible à dépenser, calculé comme `balance - held`.
      required:
        - code
        - name
        - balance
        - held
        - available
  securitySchemes:
    apikeyAuth:
      type: apiKey
      name: Authorization
      in: header
      default: Api-Key {Your secret API key}
      description: |
        Les requêtes API doivent être authentifiées par votre clé API secrète via l'en-tête **Authorization** 
        avec la valeur `Api-Key {your_secret_api_key}`, par exemple, 
        `Api-Key secret_live_...`. Retrouvez cette clé dans l'Adapty Dashboard -> 
        **App Settings** -> onglet **General** -> section **API keys**.
```
