> ## 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.

# Agregar detalles de gasto

Puedes enriquecer cualquier transacción con un **memo**, una **categoría** y/o un **adjunto** (p. ej., recibos, facturas, órdenes de compra). Las anotaciones se pueden agregar en el momento de la transacción original o actualizar después usando la mutación `updateTransactionMetadata`.

Las anotaciones son compatibles en:

* Depósitos (`depositCashBalance1`)
* Compras de tarjetas de regalo (`purchaseGiftCard`)
* Transferencias de la billetera (`createTransfer`, `transferInternalBalance`)
* Creación de tarjeta virtual (`createVirtualCard`)
  * se excluye `attachment`

***

## Cómo funciona

1. **Opcional:** Si quieres adjuntar un archivo, súbelo primero mediante el endpoint REST de carga. Recibirás un `attachmentId`.
2. Pasa `memo`, `transactionCategory` y/o `attachmentId` en la entrada de tu mutación, ya sea en el momento de la transacción o después mediante `updateTransactionMetadata`.
3. Lee las anotaciones en `getTransactions`, `getUserPurchases` o en la respuesta de la mutación. El campo `attachmentUrl` devuelve una URL firmada de corta duración para acceder al archivo.

***

## Paso 1: Cargar un adjunto (opcional)

> Este es un endpoint REST, no una mutación de GraphQL

### Endpoint

`POST /api/v1/file-upload/transaction-memo-attachment`

### Autenticación

`Authorization: Bearer <YOUR_USER_ACCESS_TOKEN>`

### Solicitud

Envía el archivo como `multipart/form-data` con el nombre de campo `file`.

**Tipos aceptados:** `application/pdf`, `image/png`

> ⚠️ JPEG no es aceptado para adjuntos de transacciones.

### Solicitud de ejemplo

```bash theme={null}
curl -X POST https://transactional-graph.staging.fluzapp.com/api/v1/file-upload/transaction-memo-attachment \
  -H "Authorization: Bearer <YOUR_ACCESS_TOKEN>" \
  -F "file=@receipt.pdf"
```

### Respuesta

```json theme={null}
{
  "attachmentId": "3f2a1b4c-e5d6-7890-abcd-ef1234567890"
}
```

Copia el `attachmentId`; lo pasarás en la entrada de tu mutación en el siguiente paso.

> El `attachmentId` está limitado al alcance de tu cuenta. El sistema verifica que el archivo exista en el almacenamiento de tu cuenta cuando envías la mutación. Se rechazará un ID de una cuenta diferente.

### Errores de carga

| Causa                                       | Estado | Detalles            |
| ------------------------------------------- | ------ | ------------------- |
| No se incluyó archivo en la solicitud       | 400    | Missing file        |
| Tipo de archivo no permitido (p. ej., JPEG) | 400    | `INVALID_ARGUMENTS` |

***

## Paso 2: Anotar la transacción

Puedes proporcionar anotaciones en el momento de la transacción original **o** actualizarlas después.

### Opción A — En el momento de la transacción

Las siguientes mutaciones aceptan `memo`, `transactionCategory` y `attachmentId` como campos opcionales en su entrada:

* `depositCashBalance` → `DepositCashBalanceInput`
* `purchaseGiftCard` → `PurchaseGiftCardInput`
* `createTransfer` → `CreateTransferInput`
* `transferInternalBalance` → `TransferInternalBalanceInput`

#### Campos de anotación

| Campo                 | Tipo   | Descripción                                                                                                                                              |
| --------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `memo`                | String | Nota de texto libre. Máximo 255 caracteres.                                                                                                              |
| `transactionCategory` | String | Etiqueta de categoría. De formato libre: las categorías se crean automáticamente en el primer uso y se reutilizan si se pasa el mismo nombre nuevamente. |
| `attachmentId`        | String | El ID devuelto por el endpoint de carga. El archivo debe cargarse antes de enviar la mutación.                                                           |

#### Ejemplo — Comprar tarjeta de regalo con anotación

```graphql theme={null}
mutation purchaseGiftCard($input: PurchaseGiftCardInput!) {
  purchaseGiftCard(input: $input) {
    purchaseDisplayId
    purchaseAmount
    memo
    transactionCategory
    attachmentUrl
    giftCard {
      giftCardId
      status
    }
  }
}
```

```json theme={null}
{
  "idempotencyKey": "0284be6f-1a69-44f7-9da0-5b5edaf45d19",
  "offerId": "0284be6f-1a69-44f7-9da0-5b5edaf45d19",
  "amount": 50.00,
  "balanceAmount": 50.00,
  "memo": "Team lunch — Q2",
  "transactionCategory": "Meals & Entertainment",
  "attachmentId": "3f2a1b4c-e5d6-7890-abcd-ef1234567890"
}
```

***

### Opción B — Después de la transacción (`updateTransactionMetadata`)

Usa esta mutación para agregar o actualizar anotaciones en cualquier transacción existente.

> **Semántica de actualización parcial:** Solo se actualizan los campos que incluyas. Los campos omitidos quedan sin cambios. Pasa `null` para borrar un campo.

#### Mutación

```graphql theme={null}
mutation updateTransactionMetadata($input: UpdateTransactionMetadataInput!) {
  updateTransactionMetadata(input: $input) {
    record_id
    memo
    transactionCategory
    attachmentUrl
  }
}
```

#### UpdateTransactionMetadataInput

| Campo                 | Tipo   | Obligatorio | Descripción                                                                                        |
| --------------------- | ------ | ----------- | -------------------------------------------------------------------------------------------------- |
| `recordId`            | UUID!  | Sí          | El `record_id` de la transacción a actualizar.                                                     |
| `memo`                | String | No          | Nota de texto libre. Máximo 255 caracteres. Omite para dejar sin cambios; pasa `null` para borrar. |
| `transactionCategory` | String | No          | Etiqueta de categoría. Omite para dejar sin cambios; pasa `null` para borrar.                      |
| `attachmentId`        | String | No          | ID del endpoint de carga. Omite para dejar sin cambios; pasa `null` para borrar.                   |

#### Alcances requeridos

`LIST_PAYMENT` y `LIST_PURCHASES`

#### Ejemplo — Agregar un memo y una categoría

```json theme={null}
{
  "recordId": "550e8400-e29b-41d4-a716-446655440000",
  "memo": "Q1 vendor payment",
  "transactionCategory": "Operating Expenses"
}
```

#### Ejemplo — Adjuntar un archivo a una transacción existente

```json theme={null}
{
  "recordId": "550e8400-e29b-41d4-a716-446655440000",
  "attachmentId": "3f2a1b4c-e5d6-7890-abcd-ef1234567890"
}
```

#### Ejemplo — Borrar un memo

```json theme={null}
{
  "recordId": "550e8400-e29b-41d4-a716-446655440000",
  "memo": null
}
```

#### Respuesta de ejemplo

```json theme={null}
{
  "data": {
    "updateTransactionMetadata": {
      "record_id": "550e8400-e29b-41d4-a716-446655440000",
      "memo": "Q1 vendor payment",
      "transactionCategory": "Operating Expenses",
      "attachmentUrl": "https://storage.googleapis.com/..."
    }
  }
}
```

#### Errores

| Causa                                                                       | Error                                                                          |
| --------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| `recordId` no encontrado o pertenece a una cuenta diferente                 | `INVALID_ARGUMENTS` — transaction not found                                    |
| El tipo de transacción no admite metadatos                                  | `INVALID_ARGUMENTS` — transaction does not support metadata                    |
| `attachmentId` no es un UUID válido                                         | `INVALID_ARGUMENTS` — Invalid attachment ID                                    |
| Archivo no encontrado en el almacenamiento (no cargado o cuenta incorrecta) | `INVALID_ARGUMENTS` — Attachment file not found. Please upload the file first. |

***

## Lectura de anotaciones

Las anotaciones se devuelven en lo siguiente:

| Consulta / Mutación         | Tipo                 | Campos                                         |
| --------------------------- | -------------------- | ---------------------------------------------- |
| `getTransactions`           | `Transaction`        | `memo`, `transactionCategory`, `attachmentUrl` |
| `getUserPurchases`          | `UserPurchase`       | `memo`, `transactionCategory`, `attachmentUrl` |
| `updateTransactionMetadata` | `Transaction`        | `memo`, `transactionCategory`, `attachmentUrl` |
| `depositCashBalance`        | `CashBalanceDeposit` | `attachmentUrl`                                |

> ⚠️ **`attachmentUrl` es una URL firmada.** Expira poco después de ser generada. No la almacenes: vuelve a recuperar la transacción cuando necesites mostrar o acceder al archivo.
