# Crear transacción de moneda virtual

> Acredita o debita una o más monedas virtuales para un perfil en una única transacción atómica. Utiliza un `amount` positivo para acreditar (conceder) y un `amount` negativo para debitar (gastar). Todos los elementos se aplican de forma conjunta: si alguno falla, ninguno se aplica.
>
> Cada código de moneda puede aparecer solo una vez por solicitud. Una acreditación a través de este endpoint siempre crea un saldo sin vencimiento.

## OpenAPI

```yaml
/api-specs/adapty-api.yaml post /api/v2/server-side-api/vc/transactions/
openapi: 3.1.0
info:
  title: API del servidor de Adapty
  version: 1.0.0
servers:
  - url: https://api.adapty.io
    description: Servidor de producción
paths:
  /api/v2/server-side-api/vc/transactions/:
    post:
      summary: Crear transacción de moneda virtual
      description: |
        Acredita o debita una o más monedas virtuales para un perfil en una única transacción atómica. Utiliza un `amount` positivo para acreditar (conceder) y un `amount` negativo para debitar (gastar). Todos los elementos se aplican de forma conjunta: si alguno falla, ninguno se aplica.

        Cada código de moneda puede aparecer solo una vez por solicitud. Una acreditación a través de este endpoint siempre crea un saldo sin vencimiento.
      operationId: createVirtualCurrencyTransaction
      tags:
        - Virtual Currency
      security:
        - apikeyAuth: []
      parameters:
        - name: adapty-customer-user-id
          in: header
          required: false
          schema:
            type: string
          description: El ID único del cliente en tu sistema. Se requiere `adapty-customer-user-id` o `adapty-profile-id`.
        - name: adapty-profile-id
          in: header
          required: false
          schema:
            type: string
          description: El ID único del perfil en tu sistema. Es la mejor opción si trabajas con perfiles anónimos. Se requiere `adapty-customer-user-id` o `adapty-profile-id`.
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            format: uuid
          description: |
            Un UUID v4 que hace la solicitud idempotente. Si reintentas una solicitud con la misma clave, Adapty devuelve el resultado de la transacción original sin modificar los saldos nuevamente. Debe ser un UUID v4 válido.

            Las claves se recuerdan hasta una hora, dentro del ámbito de un único perfil. Pasado ese período, una solicitud con la misma clave se aplica como una nueva transacción; por lo tanto, usa la clave para reintentar una llamada de forma segura, no para deduplicar una concesión a largo plazo.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/VirtualCurrencyTransactionRequest"
            examples:
              debit:
                summary: Gastar (debitar) una moneda
                value:
                  items:
                    - currency_code: COINS
                      amount: -10
              credit:
                summary: Conceder (acreditar) una moneda
                value:
                  items:
                    - currency_code: COINS
                      amount: 500
              multi_currency:
                summary: Debitar dos monedas a la vez
                value:
                  items:
                    - currency_code: GOLD
                      amount: -50
                    - currency_code: SILVER
                      amount: -200
              conversion:
                summary: Convertir una moneda en otra
                value:
                  items:
                    - currency_code: SILVER
                      amount: -100
                    - currency_code: GOLD
                      amount: 10
                  metadata:
                    reason: exchange
      responses:
        "200":
          description: Transacción aplicada correctamente
          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: |
            Solicitud incorrecta. El campo `error_code` identifica la causa: `insufficient_balance`, `unknown_currency`, `duplicate_currency`, `amount_zero`, `balance_overflow`, `empty_items` o `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: No autorizado. La clave de API falta o no es válida.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Prohibido. La Server API para monedas virtuales no está habilitada para esta aplicación. Contacta con el soporte de Adapty para solicitar acceso.
          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: Perfil no encontrado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: |
            Conflicto. El campo `error_code` identifica la causa:

            - `idempotency_in_flight` — una solicitud con el mismo `Idempotency-Key` aún está siendo procesada. Reintenta después del intervalo indicado en el encabezado de respuesta `Retry-After`.
            - `duplicate_source_transaction` — la transacción de store subyacente ya fue acreditada, por lo que no se aplica de nuevo.
          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: |
            Entidad no procesable. El cuerpo de la solicitud no superó la validación del esquema; por ejemplo, `items` contiene más de 20 entradas, o una clave o valor de `metadata` incumple sus restricciones.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: |
            Demasiadas solicitudes. Se superó el límite de velocidad por aplicación o global (`error_code` es `rate_limited`). Los límites predeterminados son 600 solicitudes por minuto por aplicación y 6000 solicitudes por minuto a nivel global.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "500":
          description: Error interno del servidor
components:
  schemas:
    VirtualCurrencyTransactionRequest:
      type: object
      description: Cuerpo de la solicitud para crear una transacción de moneda virtual.
      properties:
        items:
          type: array
          minItems: 1
          maxItems: 20
          description: Ajustes de saldo que se aplican de forma atómica. Cada código de moneda puede aparecer solo una vez.
          items:
            $ref: "#/components/schemas/VirtualCurrencyBalanceAdjustment"
        metadata:
          type: object
          nullable: true
          additionalProperties:
            type: string
          description: |
            Pares clave-valor opcionales almacenados con la transacción. Como máximo 5 claves. Cada clave debe coincidir con `^[a-z0-9_]{1,30}$`, y cada valor tiene como máximo 200 caracteres.
      required:
        - items
    VirtualCurrencyTransactionResponse:
      type: object
      description: Resultado de una transacción de moneda virtual.
      properties:
        transaction_id:
          type: string
          format: uuid
          description: ID único de la transacción creada.
        balances:
          type: array
          description: |
            Saldo posterior a la transacción para cada moneda afectada por esta solicitud (una entrada por cada elemento en `items`). Para leer la lista completa de saldos del perfil, use `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: Fuente del error
              errors:
                type: array
                items:
                  type: string
                description: Array de mensajes de error
        error_code:
          type: string
          description: Nombre corto del error
        status_code:
          type: integer
          description: Código de estado HTTP
      required:
        - errors
        - error_code
        - status_code
    VirtualCurrencyBalanceAdjustment:
      type: object
      properties:
        currency_code:
          type: string
          description: El código de moneda virtual a ajustar.
        amount:
          type: integer
          format: int32
          description: |
            El importe a aplicar. Un valor positivo acredita (otorga) la moneda; un valor negativo debita (gasta) la moneda. No puede ser cero.
      required:
        - currency_code
        - amount
    VirtualCurrencyBalanceSnapshot:
      type: object
      properties:
        code:
          type: string
          description: Código de moneda virtual.
        name:
          type: string
          description: Nombre visible de la moneda virtual.
        balance:
          type: integer
          format: int32
          minimum: 0
          description: Saldo total, incluidos los importes retenidos actualmente.
        held:
          type: integer
          format: int32
          minimum: 0
          description: Suma de todas las retenciones activas (importes reservados). Actualmente siempre es 0.
        available:
          type: integer
          format: int32
          description: Saldo disponible para gastar, calculado como `balance - held`.
      required:
        - code
        - name
        - balance
        - held
        - available
  securitySchemes:
    apikeyAuth:
      type: apiKey
      name: Authorization
      in: header
      default: Api-Key {Your secret API key}
      description: |
        Las solicitudes a la API deben autenticarse con tu clave de API secreta como encabezado **Authorization**
        con el valor `Api-Key {your_secret_api_key}`, por ejemplo,
        `Api-Key secret_live_...`. Encuentra esta clave en el Adapty Dashboard ->
        **App Settings** -> pestaña **General** -> sección **API keys**.
```
