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

# Tu primera compra con tarjeta virtual

> Ejecuta el flujo feliz completo de punta a punta: elige un programa de tarjeta, emite una tarjeta con la configuración correcta, revélala y haz seguimiento de su gasto, todo en el sandbox.

Este Quickstart te lleva desde una cuenta nueva de Fluz hasta una tarjeta virtual emitida y lista para gastar. Registrarás una app, acuñarás un token de acceso con alcance, luego explorarás programas de tarjetas, crearás una tarjeta configurada para tu caso de uso, revelarás sus detalles y observarás sus transacciones, todo en el sandbox, donde no se mueve dinero real.

<Info>
  **Requisitos previos**

  * Una **cuenta de Fluz**: crearás credenciales de API de staging y acuñarás un token de acceso en los Pasos 1–2 más abajo.
  * Las solicitudes van al endpoint GraphQL del **sandbox**. Nada aquí cobra una tarjeta real — consulta [Entorno de Staging vs. Live](/concepts/environments).
  * Cada mutación necesita un `idempotencyKey` único (un UUID generado por el cliente) para que una solicitud solo se procese una vez — consulta [Idempotencia](/concepts/idempotency).
</Info>

## Antes de comenzar

Excepto para acuñar tu token (Paso 2), cada llamada es una solicitud `POST` a un único endpoint GraphQL, autenticada con tu bearer token:

<CodeGroup>
  ```bash Endpoint & headers theme={null}
  POST https://transactional-graph.staging.fluzapp.com/api/v1/graphql

  Authorization: Bearer <YOUR_USER_ACCESS_TOKEN>
  Content-Type: application/json
  ```

  ```bash Example request (cURL) theme={null}
  curl -X POST https://transactional-graph.staging.fluzapp.com/api/v1/graphql \
    -H "Authorization: Bearer <YOUR_USER_ACCESS_TOKEN>" \
    -H "Content-Type: application/json" \
    -d '{
      "query": "query GetVirtualCardOffers { getVirtualCardOffers { offerId programName rewardValue } }"
    }'
  ```
</CodeGroup>

<Tip>
  Staging viene con **programas de tarjeta de prueba** listos para emitir, y tu cuenta de sandbox incluye una tarjeta bancaria de prueba preagregada para fondeo. Consulta [Comercios de prueba](/test-merchants) y [Tarjetas bancarias de prueba](/test-bank-cards) para el conjunto completo de datos del sandbox.
</Tip>

## El flujo completo

<Steps>
  <Step title="Regístrate y registra una app" icon="user-plus">
    Crea una cuenta de Fluz en [fluz.app](https://fluz.app), luego abre la [Consola de Desarrolladores](https://uni.staging.fluzapp.com/developers) y crea una nueva aplicación **Staging**. Cuando aparezcan las credenciales, copia tu `clientId` y `clientSecret` — el secret se muestra solo una vez.

    Guía completa: [Prepara tus cuentas](/get-started/prepare-accounts).
  </Step>

  <Step title="Intercambia credenciales por un token de acceso" icon="key">
    Acuña un token de acceso de usuario de corta duración y con alcance a partir de las credenciales de tu app. Esta llamada va al servicio OAuth; cada llamada posterior usa el token devuelto como credencial Bearer.

    <CodeGroup>
      ```bash Mint token (cURL) theme={null}
          curl -X POST https://oauth-service.fluzapp.com/graphql \
            -H "Content-Type: application/json" \
            -d '{
              "query": "mutation ($clientId: String!, $clientSecret: String!, $scopes: [Scope!]!) { generateUserAccessToken(clientId: $clientId, clientSecret: $clientSecret, scopes: $scopes) { accessToken expiresIn scopes } }",
              "variables": {
                "clientId": "<APPLICATION_CLIENT_ID>",
                "clientSecret": "<APPLICATION_CLIENT_SECRET>",
                "scopes": ["MANAGE_PAYMENT", "CREATE_VIRTUALCARD", "EDIT_VIRTUALCARD", "REVEAL_VIRTUALCARD", "PCI_COMPLIANCE"]
              }
            }'
      ```

      ```json Response theme={null}
          {
            "data": {
              "generateUserAccessToken": {
                "accessToken": "eyJhbGciOi...",
                "expiresIn": 3600,
                "scopes": ["MANAGE_PAYMENT", "CREATE_VIRTUALCARD", "EDIT_VIRTUALCARD", "REVEAL_VIRTUALCARD", "PCI_COMPLIANCE"]
              }
            }
          }
      ```
    </CodeGroup>

    Almacena el `accessToken` devuelto y envíalo como `Authorization: Bearer <accessToken>` en cada solicitud a continuación. Los tokens son de corta duración (`expiresIn` está en segundos): acuñalos del lado del servidor y renuévalos antes de que expiren. Detalles completos: [Credenciales de API](/get-started/api-credentials).

    <Tip>
      Los scopes controlan lo que el token puede hacer — incluye solo lo que tu flujo necesita: `MANAGE_PAYMENT` para fondear tu saldo, `CREATE_VIRTUALCARD` para explorar programas y emitir tarjetas, `REVEAL_VIRTUALCARD` + `PCI_COMPLIANCE` para revelar tarjetas y obtener sus transacciones, y `EDIT_VIRTUALCARD` para bloquear, desbloquear o editar tarjetas después.
    </Tip>

    <Warning>
      Nunca expongas el `clientSecret` en un navegador o cliente móvil. Acuña tokens del lado del servidor y reenvía únicamente el token.
    </Warning>
  </Step>

  <Step title="Fondea tu saldo de Fluz" icon="wallet">
    Las tarjetas virtuales se fondean desde tu cuenta cuando se usan — de forma predeterminada desde tu **saldo de Fluz** (`FLUZ_BALANCE`). Asegúrate de que haya suficiente saldo disponible para cubrir el límite de gasto que planeas establecer. Puedes fondear de dos maneras:

    * **Manualmente**, a través del [sitio web de Fluz en sandbox](https://uni.staging.fluzapp.com/manage-money).
    * **Programáticamente**, mediante la mutación `depositCashBalance`.

    <Accordion title="Depositar vía API (depositCashBalance)" icon="banknote-arrow-down">
      Recupera un ID de fuente de fondos con `getWallet`, luego deposita:

      ```graphql theme={null}
            mutation depositCashBalance($input: DepositCashBalanceInput!) {
              depositCashBalance(input: $input) {
                balances {
                  cashBalance { availableBalance totalBalance pendingBalance }
                }
              }
            }
      ```

      ```json theme={null}
            {
              "input": {
                "idempotencyKey": "0284be6f-1a69-44f7-9da0-5b5edaf45d19",
                "amount": 200.00,
                "depositType": "CASH_BALANCE",
                "bankCardId": "<YOUR_TEST_BANK_CARD_ID>"
              }
            }
      ```

      El [Quickstart de tarjeta de regalo](/quickstart) recorre este paso con todo detalle, incluyendo cómo recuperar IDs de métodos de pago con `getWallet`.
    </Accordion>

    <Note>
      ¿Prefieres fondear tarjetas desde una cuenta bancaria vinculada? Establece `primaryFundingSource: BANK_ACCOUNT` al crear la tarjeta (Paso 5) y pasa el `bankAccountId` — no se necesita saldo prefondeado.
    </Note>
  </Step>

  <Step title="Explora programas de tarjeta y elige una oferta" icon="layers">
    Cada tarjeta virtual se emite contra un **programa de tarjeta** (una “oferta”): el programa determina la red, el banco emisor, la tasa de recompensas y los límites de gasto dentro de los cuales debe permanecer tu tarjeta. Recupera los programas disponibles para tu cuenta con `getVirtualCardOffers`.

    <CodeGroup>
      ```graphql Query theme={null}
          query GetVirtualCardOffers {
            getVirtualCardOffers {
              offerId
              programName
              bin
              bankName
              rewardValue
              programLimits {
                dailyLimit
                weeklyLimit
                monthlyLimit
              }
            }
          }
      ```

      ```json Response theme={null}
          {
            "data": {
              "getVirtualCardOffers": [
                {
                  "offerId": "ed669305-5e43-40a0-9a25-7a15ed174628",
                  "programName": "Virtual Card",
                  "bin": "543210",
                  "bankName": "Bank of Examples",
                  "rewardValue": "1.5%",
                  "programLimits": {
                    "dailyLimit": "500.00",
                    "weeklyLimit": "2000.00",
                    "monthlyLimit": "5000.00"
                  }
                }
              ]
            }
          }
      ```
    </CodeGroup>

    Las ofertas están ordenadas por `rewardValue`, por lo que los programas con mayor ganancia aparecen primero. Puedes filtrar con el `input` opcional — `cardType` (`DEBIT` / `PREPAID`), `cardNetwork` (`MASTERCARD` / `VISA`) y `cardBrandLocked`. Referencia completa: [Obtener ofertas de tarjeta virtual](/features/get-card-offers).

    En el sandbox, estos programas de prueba siempre están disponibles:

    | Offer ID                               | Program Name                                   | Reward Value |
    | -------------------------------------- | ---------------------------------------------- | ------------ |
    | `ed669305-5e43-40a0-9a25-7a15ed174628` | Virtual Card                                   | 1.5%         |
    | `b23630f6-8d91-43df-84aa-a541e7691197` | Virtual Card - Mastercard Prepaid              | 1.5%         |
    | `592c394e-26cc-44ac-a145-a5f81301fe77` | Brand Locked Virtual Card - Mastercard Prepaid | 1.5%         |

    <Info>
      Guarda el `offerId` que quieras y toma nota de sus `programLimits`: el `spendLimit` que establezcas en el siguiente paso debe ajustarse al límite del programa para la duración elegida.
    </Info>
  </Step>

  <Step title="Crea la tarjeta, configurada para tu caso de uso" icon="credit-card">
    Emite la tarjeta con `createVirtualCard`. La configuración del input es lo que convierte una tarjeta genérica en una hecha a la medida: elige el patrón que coincida con lo que estás construyendo:

    <Tabs>
      <Tab title="Compra única">
        Una tarjeta para exactamente una transacción. Establece `spendLimit` al monto de la compra y `lockCardNextUse: true` para que la tarjeta se bloquee sola después de su primera autorización — nada más podrá serle cobrado.

        ```json Variables theme={null}
                {
                  "input": {
                    "idempotencyKey": "07df5653-43a8-4532-9881-3ab5857bbe12",
                    "offerId": "ed669305-5e43-40a0-9a25-7a15ed174628",
                    "spendLimit": 150.00,
                    "lockCardNextUse": true,
                    "cardNickname": "Vendor payment — Acme invoice #1042"
                  }
                }
        ```
      </Tab>

      <Tab title="Suscripción con tope mensual">
        Una tarjeta dedicada a un cargo recurrente. `spendLimitDuration: MONTHLY` reinicia el límite cada mes, de modo que un aumento de precio o un cargo duplicado más allá del tope se decline automáticamente.

        ```json Variables theme={null}
                {
                  "input": {
                    "idempotencyKey": "07df5653-43a8-4532-9881-3ab5857bbe13",
                    "offerId": "ed669305-5e43-40a0-9a25-7a15ed174628",
                    "spendLimit": 29.99,
                    "spendLimitDuration": "MONTHLY",
                    "cardNickname": "SaaS — analytics subscription"
                  }
                }
        ```
      </Tab>

      <Tab title="Tarjeta presupuestada y acotada en el tiempo">
        Una tarjeta para un proyecto o viaje con una fecha de finalización fija. `lockDate` congela la tarjeta ese día (el valor predeterminado es 47 meses después), y deshabilitar `usePrepaymentBalance` / `useRewardsBalance` hace que consuma **solo** de la cuenta de gasto especificada — fondeo predecible de una sola fuente para una conciliación limpia.

        ```json Variables theme={null}
                {
                  "input": {
                    "idempotencyKey": "07df5653-43a8-4532-9881-3ab5857bbe14",
                    "offerId": "ed669305-5e43-40a0-9a25-7a15ed174628",
                    "spendLimit": 2000.00,
                    "lockDate": "2026-09-30",
                    "userCashBalanceId": "<SPEND_ACCOUNT_ID>",
                    "usePrepaymentBalance": false,
                    "useRewardsBalance": false,
                    "cardNickname": "Q3 conference travel"
                  }
                }
        ```
      </Tab>
    </Tabs>

    Las tres ejecutan la misma mutación:

    <CodeGroup>
      ```graphql Mutation theme={null}
          mutation createVirtualCard($input: CreateVirtualCardInput!) {
            createVirtualCard(input: $input) {
              virtualCardId
              cardholderName
              virtualCardLast4
              expiryMonth
              expiryYear
              status
              cardType
              initialAmount
              usedAmount
              createdAt
            }
          }
      ```

      ```json Sample response theme={null}
          {
            "data": {
              "createVirtualCard": {
                "virtualCardId": "07df5653-43a8-4532-9881-3ab5857bbe11",
                "cardholderName": "xyz789",
                "virtualCardLast4": "7890",
                "expiryMonth": "12",
                "expiryYear": "27",
                "status": "ACTIVE",
                "cardType": "MULTI_USE",
                "initialAmount": 150.00,
                "usedAmount": 0,
                "createdAt": "2026-07-09T10:00:00Z"
              }
            }
          }
      ```
    </CodeGroup>

    #### La configuración, de un vistazo

    <ParamField body="spendLimit" type="Float" required>
      El máximo que se puede cobrar a la tarjeta — solo se te cobra lo que realmente se use. Debe ajustarse al límite del programa para la duración elegida.
    </ParamField>

    <ParamField body="spendLimitDuration" default="LIFETIME" type="VirtualCardSpendLimitDuration">
      Cómo se restablece el límite. `LIFETIME` limita el gasto total; `DAILY` / `WEEKLY` / `MONTHLY` lo convierten en un presupuesto periódico — la opción adecuada para suscripciones y asignaciones de equipo.
    </ParamField>

    <ParamField body="lockCardNextUse" default="false" type="Boolean">
      Bloquea la tarjeta después de su primer uso exitoso — el patrón de "tarjeta virtual de un solo uso" para pagos únicos a proveedores.
    </ParamField>

    <ParamField body="lockDate" default="47 months from creation" type="String">
      Fecha `yyyy-mm-dd` en la que la tarjeta se congela. Acota tarjetas a un proyecto, viaje o período de contrato.
    </ParamField>

    <ParamField body="primaryFundingSource" default="FLUZ_BALANCE" type="VirtualCardFundingSource">
      De dónde se toma el gasto. `FLUZ_BALANCE` usa tu saldo prefondeado; `BANK_ACCOUNT` debita de una cuenta vinculada (requiere `bankAccountId`).
    </ParamField>

    <ParamField body="usePrepaymentBalance / useRewardsBalance" default="true" type="Boolean">
      De forma predeterminada, una tarjeta también puede tomar de saldos prepago (tarjeta de regalo) y de recompensas. Establece ambos en `false` para tarjetas solo en efectivo que consumen únicamente del `userCashBalanceId` especificado — lo más limpio para contabilidad.
    </ParamField>

    <ParamField body="memo / transactionCategory" type="String">
      Metadatos de gasto opcionales adjuntos a la transacción resultante — las categorías se crean en el primer uso. Consulta [Agregar detalles de gastos](/features/add-expense-details).
    </ParamField>

    <Note>
      **Dirección de facturación:** si tu cuenta no tiene una registrada, pasa un `billingAddress` (o un `userAddressId` guardado). Debe ser una dirección **EE. UU.** real y entregable — sin apartados postales — o la creación fallará con `VC-0025`. Consulta [Requisitos de formato de direcciones](/concepts/address-formatting-requirements).
    </Note>

    <Info>
      Conserva el `virtualCardId` de la respuesta — lo usarás para revelar la tarjeta a continuación. Si la creación falla, revisa [Códigos de error de tarjeta virtual](/features/virtual-card-error-codes).
    </Info>
  </Step>

  <Step title="Revela los detalles de la tarjeta" icon="eye">
    La respuesta de creación omite deliberadamente los números sensibles. Recupera el PAN completo, CVV y vencimiento con `revealVirtualCardByVirtualCardId` — esto es lo que tú (o tu usuario) introduces en un checkout o agregas a una billetera móvil.

    <CodeGroup>
      ```graphql Mutation theme={null}
          mutation RevealVirtualCard($virtualCardId: UUID!) {
            revealVirtualCardByVirtualCardId(virtualCardId: $virtualCardId) {
              cardNumber
              expiryMMYY
              cvv
              cardHolderName
              billingAddress {
                streetAddress
                postalCode
                city
                state
              }
            }
          }
      ```

      ```json Variables theme={null}
          {
            "virtualCardId": "07df5653-43a8-4532-9881-3ab5857bbe11"
          }
      ```
    </CodeGroup>

    Requiere el scope `REVEAL_VIRTUALCARD`.

    <Warning>
      La respuesta contiene el número completo de la tarjeta y el CVV en texto plano. Trátalo como datos sensibles del titular — transmítelos solo sobre TLS, nunca los registres, y muéstralos solo al usuario autorizado.
    </Warning>

    <Tip>
      La mayoría de los checkouts en línea no requieren PIN — pero si tu caso de uso lo necesita (o quieres tap-to-pay), consulta [Configurar PIN de tarjeta virtual](/set-virtual-card-pin) y [Aprovisionamiento por push a billetera digital](/digital-wallet-push-provisioning) para agregar la tarjeta a Apple Pay o Google Pay en un toque.
    </Tip>
  </Step>

  <Step title="Gasta y luego observa la actividad" icon="receipt">
    Usa los detalles revelados en cualquier lugar donde se acepte la red de la tarjeta, dentro de los límites que estableciste. Luego obtén la actividad de la tarjeta con `getVirtualCardTransactions` para confirmar el cargo — la misma consulta potencia tableros de gasto, conciliación y monitoreo de declinaciones.

    <CodeGroup>
      ```graphql Query theme={null}
          query GetVirtualCardTransactions {
            getVirtualCardTransactions(
              input: {
                virtualCardIds: ["07df5653-43a8-4532-9881-3ab5857bbe11"]
                filters: { transactionTypes: [PURCHASE, REFUND, DECLINE] }
                paginate: { limit: 20, offset: 0 }
              }
            ) {
              virtualCardId
              transactions {
                transactionDate
                transactionType
                transactionStatus
                transactionAmount
                merchantName
                mcc
              }
            }
          }
      ```

      ```json Sample response theme={null}
          {
            "data": {
              "getVirtualCardTransactions": [
                {
                  "virtualCardId": "07df5653-43a8-4532-9881-3ab5857bbe11",
                  "transactions": [
                    {
                      "transactionDate": "2026-07-09T14:22:31Z",
                      "transactionType": "PURCHASE",
                      "transactionStatus": "CLEARED",
                      "transactionAmount": 42.17,
                      "merchantName": "ACME OFFICE SUPPLY",
                      "mcc": 5943
                    }
                  ]
                }
              ]
            }
          }
      ```
    </CodeGroup>

    Requiere los scopes `PCI_COMPLIANCE` y `REVEAL_VIRTUALCARD`. Omite `virtualCardIds` para obtener actividad de todas las tarjetas de la cuenta y filtra por rango de fechas para vistas tipo estado de cuenta. Referencia completa: [Obtener transacciones de tarjeta virtual](/features/get-virtual-card-transactions).

    <Accordion title="¿Terminaste con la tarjeta? Bloquéala (lockVirtualCard)" icon="lock">
      Las tarjetas con `lockCardNextUse` o una `lockDate` se manejan solas. Para bloquear cualquier otra tarjeta bajo demanda:

      ```graphql theme={null}
            mutation {
              lockVirtualCard(input: { virtualCardId: "07df5653-43a8-4532-9881-3ab5857bbe11" }) {
                virtualCardId
                locked
              }
            }
      ```

      Requiere el scope `EDIT_VIRTUALCARD`. El bloqueo es reversible — consulta [Desbloquear tarjeta virtual](/features/unlock-virtual-card).
    </Accordion>
  </Step>
</Steps>

## Listo 🎉

Has emitido una tarjeta virtual creada para un trabajo específico: elegiste un programa, configuraste controles de gasto, revelaste la tarjeta y seguiste su actividad. Desde aquí, profundiza más:

<CardGroup cols={2}>
  <Card title="Editar, bloquear y administrar tarjetas" icon="pencil" href="/features/edit-virtual-card">
    Cambia límites, apodos y fechas de bloqueo en tarjetas existentes.
  </Card>

  <Card title="Billeteras digitales y PINs" icon="smartphone" href="/digital-wallet-push-provisioning">
    Envía tarjetas a Apple Pay / Google Wallet y configura PINs.
  </Card>

  <Card title="Emisión masiva" icon="layers" href="/features/create-bulk-order">
    Crea hasta 10,000 tarjetas en una sola orden.
  </Card>

  <Card title="Envía tarjetas a otros" icon="send" href="/features/send-cards">
    Distribuye tarjetas a destinatarios por enlace, email o SMS.
  </Card>
</CardGroup>

<Note>
  **¿Quieres saber más?** Contáctanos en [support@fluz.app](mailto:support@fluz.app) para hablar con nuestros expertos o solicitar una demostración.
</Note>
