# Fetch a quote collection

Before you can create a payment, you request a **quote collection**: a set of priced quotes for a proposed transfer, one for each payment rail supported for the requested corridor. Each quote locks in an exchange rate, fee breakdown, and validity window so you can review the terms before committing to a payment.

This guide covers:

1. Creating a quote collection, quoting by source or destination amount.
2. Reading and comparing the response across multiple payment rails.
3. Handling quote expiry.
4. Filtering to a specific payment rail.
5. Retrieving a quote collection or individual quote after creation.


For conceptual background, see [Quotes and exchange rates](/products/payments-direct-2/introduction/concepts/quotes).

## Before you begin

To follow this guide, you need:

- Access to the Payments Direct API UAT environment.
- A valid OAuth2 **access token** with the `quote_collections:write` scope. See [Request an access token](/products/payments-direct-2/api-docs/developer-guides/request-an-access-token).
- The source and destination currencies and countries for the proposed payment.
- A `payinCategory` that matches your funding model (`PRE_FUNDING`, `CREDIT_FUNDING`, or `JIT_FUNDING`). See [Funding methods](/products/payments-direct-2/introduction/concepts/funding-methods).


Enablement required
Access to the `/v3/quotes/quote-collection` endpoint requires explicit enablement by Ripple. If you attempt to use this endpoint before enablement is complete, requests will fail. Contact your Ripple representative to confirm your account is configured for V3 quotes before beginning integration.

## Step 1: Create a quote collection

`POST /v3/quotes/quote-collection`

A quote collection request specifies the corridor and amount you want to price. The response contains one quote per payment rail supported for that corridor.

### Request parameters

| Parameter | Required | Description |
|  --- | --- | --- |
| `quoteAmount` | Yes | The amount to quote. |
| `quoteAmountType` | Yes | Whether `quoteAmount` is the send amount (`SOURCE_AMOUNT`) or the receive amount (`DESTINATION_AMOUNT`). |
| `sourceCurrency` | Yes | The currency you are sending (ISO 4217, 3–5 characters). |
| `destinationCurrency` | Yes | The currency the beneficiary receives (ISO 4217, 3–5 characters). |
| `payinCategory` | Yes | Your funding model: `PRE_FUNDING`, `CREDIT_FUNDING`, or `JIT_FUNDING`. |
| `sourceCountry` | No | The sender country (ISO 3166-1 alpha-2). |
| `destinationCountry` | No | The beneficiary country (ISO 3166-1 alpha-2). |
| `paymentRail` | No | Filter quotes to a specific rail. When omitted, all supported rails are returned. |


Quote by source amount
Use `SOURCE_AMOUNT` when you control how much you want to send. The API calculates how much the beneficiary receives after applying the exchange rate and fees.

In this example, the sender wants to send **1,000 USD** to a beneficiary in Germany who receives EUR.


```bash
curl -i -X POST \
  https://api.test.ripple.com/v3/quotes/quote-collection \
  -H "Authorization: Bearer <YOUR_JWT_HERE>" \
  -H "Content-Type: application/json" \
  -d '{
    "quoteAmount": 1000.00,
    "quoteAmountType": "SOURCE_AMOUNT",
    "sourceCurrency": "USD",
    "destinationCurrency": "EUR",
    "sourceCountry": "US",
    "destinationCountry": "DE",
    "payinCategory": "PRE_FUNDING"
  }'
```

Quote by destination amount
Use `DESTINATION_AMOUNT` when the beneficiary must receive a precise amount, for example when paying a foreign-currency invoice. The API calculates how much you need to send to cover the exchange and fees.

In this example, the beneficiary must receive exactly **20,000 MXN**.


```bash
curl -i -X POST \
  https://api.test.ripple.com/v3/quotes/quote-collection \
  -H "Authorization: Bearer <YOUR_JWT_HERE>" \
  -H "Content-Type: application/json" \
  -d '{
    "quoteAmount": 20000.00,
    "quoteAmountType": "DESTINATION_AMOUNT",
    "sourceCurrency": "USD",
    "destinationCurrency": "MXN",
    "sourceCountry": "US",
    "destinationCountry": "MX",
    "payinCategory": "PRE_FUNDING"
  }'
```

## Step 2: Review the response

A successful request returns HTTP `201` with a quote collection. The top-level `quoteCollectionId` identifies the collection; the `quotes` array contains one entry per supported payment rail.


```json
{
  "quoteCollectionId": "11111111-aaaa-2222-bbbb-222222222222",
  "quotes": [
    {
      "quoteId": "7ea3399c-1234-5678-8d8f-d320ea406630",
      "quoteStatus": "ACTIVE",
      "quoteAmountType": "SOURCE_AMOUNT",
      "sourceAmount": 1000.00,
      "destinationAmount": 921.45,
      "sourceCurrency": "USD",
      "destinationCurrency": "EUR",
      "destinationCountry": "DE",
      "payinCategory": "PRE_FUNDING",
      "paymentRail": "SEPA_INSTANT",
      "adjustedExchangeRate": {
        "adjustedRate": 0.9238
      },
      "fees": [
        {
          "totalFee": 8.50,
          "feeCurrency": "USD",
          "feeBreakdown": [
            {
              "calculatedFee": 0.50,
              "feeName": "Fixed service fee",
              "feeDescription": "Fixed service fee for payment rail SEPA_INSTANT.",
              "paymentRail": "SEPA_INSTANT"
            },
            {
              "calculatedFee": 8.00,
              "feeName": "Variable service fee",
              "feeDescription": "Variable service fee for payment rail SEPA_INSTANT.",
              "paymentRail": "SEPA_INSTANT"
            }
          ]
        }
      ],
      "createdAt": "2025-11-02T18:26:00.000Z",
      "expiresAt": "2025-11-02T18:41:00.000Z"
    },
    {
      "quoteId": "9fb4500d-2345-6789-ae9f-e431fb517741",
      "quoteStatus": "ACTIVE",
      "quoteAmountType": "SOURCE_AMOUNT",
      "sourceAmount": 1000.00,
      "destinationAmount": 921.45,
      "sourceCurrency": "USD",
      "destinationCurrency": "EUR",
      "destinationCountry": "DE",
      "payinCategory": "PRE_FUNDING",
      "paymentRail": "SEPA_STANDARD",
      "adjustedExchangeRate": {
        "adjustedRate": 0.9238
      },
      "fees": [
        {
          "totalFee": 5.25,
          "feeCurrency": "USD",
          "feeBreakdown": [
            {
              "calculatedFee": 0.25,
              "feeName": "Fixed service fee",
              "feeDescription": "Fixed service fee for payment rail SEPA_STANDARD.",
              "paymentRail": "SEPA_STANDARD"
            },
            {
              "calculatedFee": 5.00,
              "feeName": "Variable service fee",
              "feeDescription": "Variable service fee for payment rail SEPA_STANDARD.",
              "paymentRail": "SEPA_STANDARD"
            }
          ]
        }
      ],
      "createdAt": "2025-11-02T18:26:00.000Z",
      "expiresAt": "2025-11-02T18:41:00.000Z"
    }
  ]
}
```

### Key fields

| Field | Description |
|  --- | --- |
| `quoteCollectionId` | The ID of this collection. Use it to retrieve the collection later with `GET /v3/quotes/quote-collection/{quote-collection-id}`. |
| `quoteId` | The ID of an individual quote. Use the `quoteId` you select to create a payment. |
| `quoteStatus` | `ACTIVE` means the quote can be used. `EXPIRED` means the validity window has passed and a new quote collection is required. |
| `paymentRail` | The payment network for this quote (for example, `SEPA_INSTANT`, `SEPA_STANDARD`, `SPEI`, `US_ACH`). Each rail in the collection has its own quote. |
| `adjustedExchangeRate.adjustedRate` | The FX rate Ripple will apply. This rate is locked for the duration of the quote's validity window. |
| `fees[].totalFee` / `feeBreakdown` | Total service fee and a line-item breakdown. Fees vary by rail. |
| `taxes` | Applicable consumption taxes on Ripple's fees (VAT, GST, and so on). Absent when no taxes apply. |
| `createdAt` / `expiresAt` | The quote's validity window. By default, quotes are valid for 15 minutes. |


### Comparing quotes across rails

When a corridor supports multiple rails, the quotes share the same exchange rate but typically differ in fees and processing speed. Use the `totalFee` and `paymentRail` values to select the quote that best fits your needs.

In the example above:

| Rail | Total fee | Speed |
|  --- | --- | --- |
| `SEPA_INSTANT` | $8.50 USD | Seconds |
| `SEPA_STANDARD` | $5.25 USD | 1 business day |


Select the `quoteId` for the rail you want to use and pass it to the Create payment operation.

quoteId and paymentId
The `quoteId` you select becomes the `paymentId` when you create the payment. Store it before moving to the next step.

## Step 3: Handle quote expiry

Quotes are valid for a limited time (15 minutes by default). Before creating a payment, check that `quoteStatus` is `ACTIVE`.

- If `quoteStatus` is `ACTIVE`, the quote can be used to create a payment.
- If `quoteStatus` is `EXPIRED`, the quote can no longer be used. Request a new quote collection, which will reflect the current exchange rate and fees.


Use `expiresAt` to implement client-side refresh logic, for example, prompting a user to confirm before the quote lapses, or automatically re-quoting when the remaining time falls below a threshold.


```
remainingSeconds = expiresAt - now()
if remainingSeconds <= 0:
    request a new quote collection
```

Each quote in a collection shares the same `expiresAt`. Re-quoting generates a new `quoteCollectionId` and new `quoteId` values.

## Step 4: Filter to a specific payment rail

If you already know which rail you want to use, include `paymentRail` in the request to receive a single-item collection. This simplifies response handling when rail selection is fixed by your integration.


```bash
curl -i -X POST \
  https://api.test.ripple.com/v3/quotes/quote-collection \
  -H "Authorization: Bearer <YOUR_JWT_HERE>" \
  -H "Content-Type: application/json" \
  -d '{
    "quoteAmount": 10000,
    "quoteAmountType": "SOURCE_AMOUNT",
    "sourceCurrency": "USD",
    "destinationCurrency": "MXN",
    "sourceCountry": "US",
    "destinationCountry": "MX",
    "payinCategory": "PRE_FUNDING",
    "paymentRail": "SPEI"
  }'
```

The response contains a `quotes` array with a single entry for the `SPEI` rail. If the specified rail is not supported for the requested corridor, the API returns a `CFG_` error.

For a full list of valid `paymentRail` values, see [Payment rail reference](/products/payments-direct-2/api-docs/integration-resources/payment-rail-reference).

## Step 5: Retrieve a quote collection

`GET /v3/quotes/quote-collection/{quote-collection-id}`

Use this endpoint to retrieve a quote collection you created earlier, for example in an async flow where you stored the `quoteCollectionId` and are checking quote status before initiating a payment.


```bash
curl -i -X GET \
  https://api.test.ripple.com/v3/quotes/quote-collection/11111111-aaaa-2222-bbbb-222222222222 \
  -H "Authorization: Bearer <YOUR_JWT_HERE>"
```

The response schema is identical to the `POST` response. Check each quote's `quoteStatus` before proceeding; any quotes in the collection may have expired since they were created.

## Step 6: Retrieve an individual quote

`GET /v3/quotes/{quote-id}`

Use this endpoint to retrieve a specific quote by ID.


```bash
curl -i -X GET \
  https://api.test.ripple.com/v3/quotes/7ea3399c-1234-5678-8d8f-d320ea406630 \
  -H "Authorization: Bearer <YOUR_JWT_HERE>"
```

The response contains the same fields as a single entry from the `quotes` array, without the `quoteCollectionId` wrapper.

## Error handling

Quote errors return a structured response with a `status` and an `errors` array. Each error includes `code`, `title`, `type`, `description`, and `timestamp`.

Error codes use three prefixes:

| Prefix | Category | Common causes |
|  --- | --- | --- |
| `USR_` | Validation error | Missing required fields, invalid currency codes, amounts outside the allowed range (1–100,000,000), or deprecated `payinCategory` values. |
| `CFG_` | Configuration error | Unsupported corridor, missing tenant configuration, or a `paymentRail` value not supported for the requested corridor. |
| `SYS_` | System error | Internal or upstream FX pricing failure. Retry the request; contact support if the error persists. |


### Common validation errors

**Deprecated `payinCategory` values**: The v3 endpoint does not accept `FUNDED` or `T_PLUS_ONE`. Use `PRE_FUNDING` in place of `FUNDED`, and `CREDIT_FUNDING` in place of `T_PLUS_ONE`.

**Invalid currency or country codes**: `sourceCurrency` and `destinationCurrency` must be 3–5 alphabetic characters. `sourceCountry` and `destinationCountry` must be ISO 3166-1 alpha-2 codes (exactly 2 characters).

**Unsupported corridor**: If the currency pair is not configured for your tenant, the API returns a `CFG_` error. Verify the corridor is listed in the [Payment rail reference](/products/payments-direct-2/api-docs/integration-resources/payment-rail-reference) and contact your Ripple representative if the error persists.

## What's next

Once you have an `ACTIVE` quote and have selected a `quoteId`, you are ready to create a payment.

See [Create a payment](/products/payments-direct-2/api-docs/developer-guides/create-a-payment) for a complete walkthrough of the payment creation step, including how to pass the `quoteId` alongside beneficiary identity and financial instrument IDs.