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

# USDC Inventory

> USDC Inventory lets the MSB contract FX in advance, locking rate and volume in an Inventory Lot, and use that volume later in withdrawals. When contracting, the MSB takes on a payment promise in USDC.

> [!NOTE]
>
> The mode must be enabled for your account; otherwise the API returns `FUNDING_MODE_NOT_ENABLED`.

## 1. Quote with usage = INVENTORY

Request the quote in `POST /v1/fx/quotes` with `usage = INVENTORY` and exactly one of `sourceAmount` (USD) or `destinationAmount` (BRL). The response has two dates: `expiresAt` is the validity of the quote itself; `inventoryExpiresAt` is the validity the lot will have if you create it.

```http POST /v1/fx/quotes · request theme={null}
POST /v1/fx/quotes
Idempotency-Key: 7f1c2a9e-inv-quote
```

```json Request body theme={null}
{
  "fromCurrency": "USD",
  "toCurrency": "BRL",
  "sourceAmount": "100000.00",
  "usage": "INVENTORY"
}
```

```json 201 · FxQuote theme={null}
{
  "quoteId": "qt_01JA1X",
  "status": "AVAILABLE",
  "usage": "INVENTORY",
  "fromCurrency": "USD",
  "toCurrency": "BRL",
  "source": {
    "currency": "USD",
    "amount": "100000.00"
  },
  "destination": {
    "currency": "BRL",
    "amount": "540000.00"
  },
  "referenceRate": "5.46558704",
  "rate": "5.40000000",
  "spread": {
    "percentage": "1.2",
    "amount": {
      "currency": "USD",
      "amount": "1200.00"
    }
  },
  "expiresAt": "2026-11-04T14:05:00Z",
  "inventoryExpiresAt": "2026-11-10T23:59:59Z",
  "inventoryId": null,
  "createdAt": "2026-11-04T14:00:00Z"
}
```

## 2. Create the lot

Call `POST /v1/inventories` with the `quoteId`. This call is the acceptance: in one operation LB Pay closes rate and volume with you, creates the USDC payment promise and creates the lot, which starts `ACTIVE`. The quote becomes `USED` and records the `inventoryId`. Each call creates a new, independent lot; lots are never aggregated. A lot can exist without any withdrawal.

```http POST /v1/inventories · request theme={null}
POST /v1/inventories
Idempotency-Key: 7f1c2a9e-inv-create
```

```json Request body theme={null}
{
  "quoteId": "qt_01JA1X",
  "externalId": "inventory-2026-11-04-001"
}
```

```json 201 · Inventory theme={null}
{
  "inventoryId": "inv_01JA2B",
  "externalId": "inventory-2026-11-04-001",
  "quoteId": "qt_01JA1X",
  "status": "ACTIVE",
  "fromCurrency": "USD",
  "toCurrency": "BRL",
  "referenceRate": "5.46558704",
  "rate": "5.40000000",
  "spread": {
    "percentage": "1.2",
    "amount": {
      "currency": "USD",
      "amount": "1200.00"
    }
  },
  "total": {
    "source": { "currency": "USD", "amount": "100000.00" },
    "destination": { "currency": "BRL", "amount": "540000.00" }
  },
  "available": {
    "source": { "currency": "USD", "amount": "100000.00" },
    "destination": { "currency": "BRL", "amount": "540000.00" }
  },
  "reserved": {
    "source": { "currency": "USD", "amount": "0.00" },
    "destination": { "currency": "BRL", "amount": "0.00" }
  },
  "used": {
    "source": { "currency": "USD", "amount": "0.00" },
    "destination": { "currency": "BRL", "amount": "0.00" }
  },
  "pendingSettlement": null,
  "settlementId": null,
  "expiresAt": "2026-11-10T23:59:59Z",
  "createdAt": "2026-11-04T14:01:12Z",
  "updatedAt": "2026-11-04T14:01:12Z"
}
```

## 3. Check balances

`GET /v1/inventories/{inventoryId}` returns rate, validity and balances. Every balance is shown in BRL and USD. Control is in BRL; USD is calculated at the lot rate.

| Field | Meaning |
| - | - |
| `total` | Contracted volume |
| `available` | Volume available for new withdrawals |
| `reserved` | Volume reserved by withdrawals in progress |
| `used` | Volume already used by withdrawals |

> [!NOTE]
>
> `total = available + reserved + used`, always.

Example: a lot of USD 100,000.00 at 5.40000000 is BRL 540,000.00. A withdrawal of BRL 10,000.00 reserves USD 1,851.85 (10,000 ÷ 5.40).

| Moment | available | reserved | used |
| - | - | - | - |
| Lot created | BRL 540,000.00 · USD 100,000.00 | 0 | 0 |
| Withdrawal reserved | BRL 530,000.00 · USD 98,148.15 | BRL 10,000.00 · USD 1,851.85 | 0 |
| Volume used | BRL 530,000.00 · USD 98,148.15 | 0 | BRL 10,000.00 · USD 1,851.85 |
| Withdrawal `REJECTED` | BRL 540,000.00 · USD 100,000.00 | 0 | 0 |

### Lot status

| Status | Meaning |
| - | - |
| `ACTIVE` | Within validity, with available volume. |
| `DEPLETED` | No available volume (all reserved or used). Returns to `ACTIVE` if a reservation is released within validity. |
| `EXPIRED` | Past `expiresAt`. Does not accept new withdrawals. |

## 4. Create the withdrawal

Create the withdrawal with `funding.mode = INVENTORY`, `funding.inventoryId`, `destinationAmount` (the BRL the beneficiary receives) and `senderQuote`. Do not send `quoteId`. Amounts and rate come from the lot. LB Pay checks that the lot exists in your account, is within validity and has enough available BRL, applies the usual [withdrawal](https://developers.javalibridge.com/en/guides/withdrawal.md) checks and reserves the volume atomically. Another lot is never used automatically.

| Field | PREFUNDED / CREDIT | INVENTORY |
| - | - | - |
| `quoteId` | Required | Not accepted |
| `funding.inventoryId` | Not accepted | Required |
| `destinationAmount` (BRL) | Not accepted | Required |
| `senderQuote` | Optional | Required |

> [!NOTE]
>
> A violation returns `VALIDATION_ERROR` (400), with the field in `details`.

`senderQuote` holds the data of the FX operation between the MSB and the sender: rate, USD and BRL amounts, quote time and your reference. It is recorded as received and used to formalize the operation. It does not change the remittance amounts or the lot rate. Its structure may receive new fields.

```http POST /v1/remittances/withdrawals · request theme={null}
POST /v1/remittances/withdrawals
Idempotency-Key: 7f1c2a9e-wd-125
```

```json Request body theme={null}
{
  "senderId": "snd_789",
  "externalId": "remittance-125",
  "destinationAmount": "10000.00",
  "funding": {
    "mode": "INVENTORY",
    "inventoryId": "inv_01JA2B"
  },
  "beneficiaryId": "ben_125",
  "purpose": "FAMILY_MAINTENANCE",
  "senderRelationship": "FAMILY",
  "senderQuote": {
    "rate": "5.55000000",
    "source": {
      "currency": "USD",
      "amount": "1801.80"
    },
    "destination": {
      "currency": "BRL",
      "amount": "10000.00"
    },
    "quotedAt": "2026-11-04T14:00:00Z",
    "reference": "msb-quote-8812"
  }
}
```

```json 201 · WithdrawalResponse theme={null}
{
  "remittanceId": "rem_01JA3C",
  "type": "WITHDRAWAL",
  "quoteId": null,
  "inventoryId": "inv_01JA2B",
  "senderId": "snd_789",
  "externalId": "remittance-125",
  "status": "PROCESSING",
  "fundingMode": "INVENTORY",
  "message": "Remessa criada; câmbio e Pix ainda não confirmados."
}
```

```json 422 · ApiError theme={null}
{
  "code": "INSUFFICIENT_INVENTORY_BALANCE",
  "message": "Volume disponível no inventory inv_01JA2B é menor que destinationAmount.",
  "requestId": "req_9b1e",
  "retryable": false,
  "details": [
    {
      "field": "destinationAmount",
      "reason": "available BRL 4000.00"
    }
  ]
}
```

## 5. Track and reconcile

* `inventory.created`: lot created. `inventory.status_changed`: `ACTIVE` ↔ `DEPLETED`, or `EXPIRED`. In both, `data.object` is the Inventory.
* Remittances funded by a lot follow the `remittance.*` events.
* Balance changes without a status change do not send an event. Check the balance in `GET /v1/inventories/{inventoryId}`.
* List the remittances of a lot with `GET /v1/remittances?inventoryId=`.
* In an `INVENTORY` remittance, `quoteId` is null, `inventoryId` identifies the lot and `fx.rate` is the lot rate. `fx.status = CONTRACTED` only after the execution is confirmed. In `REJECTED`, the reserved volume returns to the lot.

## Errors

| Code | HTTP | Cause | What you do |
| - | - | - | - |
| `QUOTE_USAGE_MISMATCH` | 422 | Quote used in the wrong operation: `INVENTORY` in a withdrawal, or `REMITTANCE` in `POST /v1/inventories`. | Request a new quote with the right `usage`. |
| `DUPLICATE_INVENTORY_EXTERNAL_ID` | 409 | `externalId` already used by another lot in your account. | Use a new `externalId`, or find the existing lot with `GET /v1/inventories?externalId=`. |
| `INVENTORY_NOT_FOUND` | 422 | The lot in `funding.inventoryId` does not exist in your account. | Check the `inventoryId`. A lot from another account returns the same error. |
| `INVENTORY_EXPIRED` | 422 | The lot is `EXPIRED`. | Use another `ACTIVE` lot or contract a new one. |
| `INSUFFICIENT_INVENTORY_BALANCE` | 422 | Available volume in the lot is lower than `destinationAmount`. | Check the balance in `GET /v1/inventories/{inventoryId}` before retrying. Another lot is never used automatically. |
| `FUNDING_MODE_NOT_ENABLED` | 422 | `INVENTORY` is not enabled for your account. Applies to lot creation and to the withdrawal. | Contact LB Pay to enable the mode. |

> [!TIP]
>
> **Good practices**
>
> * Always inform the lot explicitly. LB Pay never uses another lot automatically.
> * Handle `INSUFFICIENT_INVENTORY_BALANCE` by checking the balance before trying again.
> * Send an `Idempotency-Key` when creating the lot and the withdrawal.
> * Send in `senderQuote` the real values of the operation with the sender.

## In definition

> [!WARNING]
>
> Validity and expiration of unused volume, lot cancellation and collection of the USDC obligation are still being defined. These rules will be communicated before general availability.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.