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

# Retrieve rates

> Get current exchange rates for NGN to USDC/USDT conversions

## Overview

Request firm FX quotes with guaranteed exchange rates. Each rate has a \~30-minute validity window and is identified by a unique `rate_id`.

## Authentication

<ParamField header="X-Api-Key" type="string" required>
  Your merchant API key

  ```
  X-Api-Key: YOUR_API_KEY
  ```
</ParamField>

## Query Parameters

<ParamField query="from" type="string" required>
  Source currency. Currently only `NGN` is supported.

  **Allowed values:** `NGN`
</ParamField>

<ParamField query="to" type="string" required>
  Destination currency.

  **Allowed values:** `USDC`, `USDT`, `USD`

  <Note>
    `USD` is treated as equivalent to USDC/USDT in v0.1. Depeg scenarios are not handled.
  </Note>
</ParamField>

<ParamField query="side" type="string" required>
  Rate side. Determines whether the quote is for buying or selling crypto.

  **Allowed values:** `BUY`, `SELL`

  * `BUY` — Merchant is buying crypto (NGN deposits → stablecoin). Use for NGN funding accounts that settle onchain.
  * `SELL` — Merchant is selling crypto (stablecoin → NGN). Use for crypto funding accounts that settle to an NGN bank account.
</ParamField>

## Request Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl --request GET \
    --url 'https://api.daya.co/v1/rates?from=NGN&to=USDC&side=BUY' \
    --header 'X-Api-Key: YOUR_API_KEY'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://api.daya.co/v1/rates?from=NGN&to=USDC&side=BUY',
    {
      headers: {
        'X-Api-Key': 'YOUR_API_KEY'
      }
    }
  );
  const rate = await response.json();
  console.log(rate);
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      'https://api.daya.co/v1/rates',
      params={'from': 'NGN', 'to': 'USDC', 'side': 'BUY'},
      headers={'X-Api-Key': 'YOUR_API_KEY'}
  )
  rate = response.json()
  print(rate)
  ```

  ```go Go theme={null}
  package main

  import (
      "fmt"
      "io"
      "net/http"
  )

  func main() {
      url := "https://api.daya.co/v1/rates?from=NGN&to=USDC&side=BUY"
      
      req, _ := http.NewRequest("GET", url, nil)
      req.Header.Add("X-Api-Key", "YOUR_API_KEY")
      
      res, _ := http.DefaultClient.Do(req)
      defer res.Body.Close()
      
      body, _ := io.ReadAll(res.Body)
      fmt.Println(string(body))
  }
  ```
</CodeGroup>

## Response

<ResponseField name="rate_id" type="string" required>
  Unique identifier for this rate snapshot. Use this when creating funding accounts that need a quoted conversion.

  **Example:** `rate_8x7k2mq9p`
</ResponseField>

<ResponseField name="from" type="string" required>
  Source currency

  **Example:** `NGN`
</ResponseField>

<ResponseField name="to" type="string" required>
  Destination currency

  **Example:** `USDC`
</ResponseField>

<ResponseField name="side" type="string" required>
  Rate side — `BUY` or `SELL`

  **Example:** `BUY`
</ResponseField>

<ResponseField name="rate" type="number" required>
  Conversion rate from source to destination (e.g., 1 USDC = X NGN)

  **Example:** `1545.50`

  <Info>
    This rate already includes Daya's spread/fee. You don't need to calculate fees separately.
  </Info>
</ResponseField>

<ResponseField name="inverse_rate" type="number" required>
  Inverse conversion rate (e.g., 1 NGN = X USDC)

  **Example:** `0.000647`
</ResponseField>

<ResponseField name="fee_bps" type="integer">
  Fee in basis points (1 bps = 0.01%)

  **Example:** `50` (0.5%)
</ResponseField>

<ResponseField name="min_deposit_ngn" type="number" required>
  Minimum NGN deposit amount for this rate

  **Example:** `1500.00` (\~\$1.00)

  <Note>
    Deposits below this amount will be rejected with status `FAILED`.
  </Note>
</ResponseField>

<ResponseField name="created_at" type="string" required>
  When this rate was generated (ISO 8601 timestamp)

  **Example:** `2026-01-14T15:05:00Z`
</ResponseField>

<ResponseField name="expires_at" type="string" required>
  When this rate becomes invalid (ISO 8601 timestamp)

  **Example:** `2026-01-14T15:35:00Z`

  <Warning>
    Always check this before using `rate_id` to create a funding account. Expired rates will be rejected.
  </Warning>
</ResponseField>

### Success Response

<ResponseExample>
  ```json 200 OK theme={null}
  {
    "rate_id": "rate_8x7k2mq9p",
    "from": "NGN",
    "to": "USDC",
    "side": "BUY",
    "rate": 1545.50,
    "inverse_rate": 0.000647,
    "fee_bps": 50,
    "min_deposit_ngn": 1500.00,
    "created_at": "2026-01-14T15:05:00Z",
    "expires_at": "2026-01-14T15:35:00Z"
  }
  ```
</ResponseExample>

## Error Responses

<ResponseExample>
  ```json 400 Bad Request - Missing from parameter theme={null}
  {
    "error": {
      "code": "missing_parameter",
      "message": "Required parameter 'from' is missing",
      "details": "Query parameter 'from' must be provided"
    }
  }
  ```

  ```json 400 Bad Request - Invalid currency theme={null}
  {
    "error": {
      "code": "invalid_currency",
      "message": "Invalid currency specified",
      "details": "Only NGN is supported for 'from' parameter"
    }
  }
  ```

  ```json 503 Service Unavailable - No rates available theme={null}
  {
    "error": {
      "code": "rate_unavailable",
      "message": "No valid exchange rates available at this time",
      "details": "Please try again in a few minutes"
    }
  }
  ```

  ```json 401 Unauthorized theme={null}
  {
    "error": {
      "code": "unauthorized",
      "message": "Invalid or missing API key"
    }
  }
  ```
</ResponseExample>

## Rate Lifecycle

New rates are generated approximately **every 10 minutes** and expire after **\~30 minutes**.

```
Time    Rate ID         Valid Until
─────────────────────────────────────
15:05   rate_abc123     15:35
15:15   rate_def456     15:45
15:25   rate_ghi789     15:55
15:35   rate_jkl012     16:05
```

<Tip>
  Request a fresh rate immediately before creating each temporary funding account that uses a quoted conversion.
</Tip>

## Usage Notes

### Rate Guarantee

For **temporary funding accounts** with a quoted settlement destination, the rate is guaranteed for deposits within the validity window:

* Funding account created with `rate_id` at 15:10
* Rate expires at 15:35
* Deposit at 15:20 → Uses guaranteed rate ✅
* Deposit at 15:40 → Flagged (expired) ❌

### Caching Rates

You can cache rates client-side but must respect `expires_at`:

```javascript theme={null}
class RateCache {
  constructor() {
    this.rate = null;
  }
  
  async getValidRate() {
    if (!this.rate || new Date() >= new Date(this.rate.expires_at)) {
      const response = await fetch('https://api.daya.co/v1/rates?from=NGN');
      this.rate = await response.json();
    }
    return this.rate;
  }
}
```

### Checking Time Remaining

Calculate remaining validity time:

```javascript theme={null}
function getSecondsRemaining(expiresAt) {
  const now = new Date();
  const expiry = new Date(expiresAt);
  return Math.max(0, (expiry - now) / 1000);
}

const rate = await getRates();
const remaining = getSecondsRemaining(rate.expires_at);
console.log(`Rate valid for ${remaining} seconds`);
```

## Rate Calculation

The displayed rate includes Daya's fee:

```
Displayed Rate = Market Rate × (1 - fee_bps / 10000)
```

**Example:**

* Market rate: 1550 NGN/USDC
* Fee: 50 bps (0.5%)
* Displayed rate: 1550 × (1 - 0.005) = **1545.50 NGN/USDC**

## Common Patterns

<AccordionGroup>
  <Accordion title="Get rate before funding account creation">
    **Recommended flow:**

    1. Call `GET /v1/rates`
    2. Display rate to user
    3. User confirms
    4. Call `POST /v1/funding-accounts` with `rate_id`

    ```javascript theme={null}
    async function createFundingAccountWithRate(customerId, destinationAddress) {
      // Step 1: Get current rate
      const rate = await getRates();
      
      // Step 2: Show to user (await confirmation)
      await showRateToUser(rate);
      
      // Step 3: Create funding account with rate_id
      const fundingAccount = await createFundingAccount({
        type: 'TEMPORARY',
        rail: 'NGN_VIRTUAL_ACCOUNT',
        customer: { customer_id: customerId },
        currency: 'NGN',
        amount: 50000,
        settlement_destination: {
          type: 'ONCHAIN',
          rate_id: rate.rate_id,
          destination_asset: 'USDC',
          destination_chain: 'BASE',
          destination_address: destinationAddress
        }
      });
      
      return fundingAccount;
    }
    ```
  </Accordion>

  <Accordion title="Handle rate unavailability">
    If FX venue is down, gracefully handle `rate_unavailable` error:

    ```javascript theme={null}
    async function getRatesWithRetry(maxRetries = 3) {
      for (let i = 0; i < maxRetries; i++) {
        try {
          const response = await fetch('https://api.daya.co/v1/rates?from=NGN');
          if (response.status === 503) {
            await new Promise(resolve => setTimeout(resolve, 5000)); // Wait 5s
            continue;
          }
          return await response.json();
        } catch (error) {
          if (i === maxRetries - 1) throw error;
        }
      }
      throw new Error('Rates unavailable after retries');
    }
    ```
  </Accordion>
</AccordionGroup>

## Rate Limits

* **100 requests per minute** per API key
* No specific rate limit on this endpoint (non-mutating)

## Next Steps

<CardGroup cols={2}>
  <Card title="Create Funding Account" icon="upload" href="/api-reference/funding-accounts/create-funding-account">
    Use the rate\_id to create a funding account
  </Card>

  <Card title="Rates Concept" icon="book" href="/concepts/rates-and-settlement">
    Learn more about rate semantics
  </Card>
</CardGroup>
