---
title: "Set one currency's exchange-rate source"
description: "Manual rate, or auto-refreshed."
canonical_url: "https://twominutebilling.com/help/developers/api-reference/businesses/set-one-currency-s-exchange-rate-source"
---
# Set one currency's exchange-rate source

> Manual rate, or auto-refreshed.

<api-operation method="PUT" path="/v1/businesses/{biz}/currencies/{currency}">
<template v-slot:docs="">

The **Manage currency** dialog: a currency's rate is either typed in and left alone (`manual`) or refreshed daily from a provider (`auto`).

A per-currency sub-resource on purpose. Switching INR to auto says nothing about EUR, whereas sending a partial `exchange_rates` map on the business patch would be ambiguous between *leave the others* and *delete them*.

`auto` attempts ONE provider fetch inline, so the response carries the rate the screen is about to show. **A failed fetch is still a 200**: the currency is recorded as auto, the previous rate stands, and `last_error` says why it did not move — read `updated_at` and `last_error` to tell a refreshed rate from a kept one. The daily job retries. Rates are reporting-only and never rate or settle a charge, whatever their source.

The business's own default currency is refused (400): it is 1 against itself by definition, and a settable rate for it would invite someone to set it to something else.

## Path parameters

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Required
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        biz
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <strong>
        yes
      </strong>
    </td>
    
    <td>
      Business id (biz_…)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        currency
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <strong>
        yes
      </strong>
    </td>
    
    <td>
      ISO 4217 code (<code>
        INR
      </code>
      
      )
    </td>
  </tr>
</tbody>
</table>

## Headers

<table>
<thead>
  <tr>
    <th>
      Parameter
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Required
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        Idempotency-Key
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      no
    </td>
    
    <td>
      Safely retry writes — repeats return the original response. If a write FAILED after it had already taken effect, that failure is what repeats: the key is spent, and a new attempt needs a new key.
    </td>
  </tr>
</tbody>
</table>

## Response

<table>
<thead>
  <tr>
    <th>
      Field
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        object
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      The object type; always <code>
        currency_rate
      </code>
      
      . One of <code>
        currency_rate
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        currency
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      The currency this rate is for (ISO-4217 code).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        rate
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Units of <code>
        currency
      </code>
      
       per 1 unit of the business's default currency, as a decimal STRING (exactness: see <code>
        Invoice.exchange_rate
      </code>
      
      ). Null = no rate is configured for this currency, which is not 1 — a roll-up cannot convert it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        source
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        manual
      </code>
      
       = maintained by an operator, and nothing will change it. <code>
        auto
      </code>
      
       = refreshed daily from <code>
        provider
      </code>
      
      . A currency configured before provenance existed reads as <code>
        manual
      </code>
      
      , which is what it is. One of <code>
        manual
      </code>
      
      , <code>
        auto
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        updated_at
      </code>
    </td>
    
    <td>
      <code>
        string · ISO-8601
      </code>
    </td>
    
    <td>
      When the rate being held was PUBLISHED by its source — not when we last checked. The ECB publishes on weekdays, so a rate fetched on Sunday legitimately carries Friday's date; reporting the fetch time here would describe our request rather than the rate. Null on an auto currency that has never refreshed successfully.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        provider
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Which source produced an auto rate; null for a manual one. One of <code>
        ecb
      </code>
      
      , <code>
        null
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        last_error
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      Why this currency's last refresh failed, or null. A failed refresh LEAVES THE PREVIOUS RATE STANDING (an absent rate would break the roll-up outright, a stale one is a visible inaccuracy), so without this the failure would be invisible: a rate frozen a week ago looks exactly like one that has not moved.
    </td>
  </tr>
</tbody>
</table>

## Status codes

<table>
<thead>
  <tr>
    <th>
      Status
    </th>
    
    <th>
      Meaning
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        200
      </code>
    </td>
    
    <td>
      Success
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        400
      </code>
    </td>
    
    <td>
      Not a positive rate, a <code>
        rate
      </code>
      
       sent with <code>
        auto
      </code>
      
      , or the business's own default currency
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        404
      </code>
    </td>
    
    <td>
      No such business
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        409
      </code>
    </td>
    
    <td>
      Idempotency-Key conflict — the key is already in flight, or was reused with a different request payload.
    </td>
  </tr>
</tbody>
</table>
</template>

<template v-slot:request="">

```bash [Request]
curl -X PUT "$TMBILLING_URL/v1/businesses/biz_XXXXXXXXXXXX01/currencies/USD" \
  -H "Authorization: Bearer $TMBILLING_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "manual",
    "rate": "0.920000"
  }'
```

</template>

<template v-slot:response="">
<code-group>

```json [200 OK]
{
  "object": "currency_rate",
  "currency": "INR",
  "rate": "0.920000",
  "source": "manual",
  "updated_at": "2026-03-14T09:30:00Z",
  "provider": "ecb",
  "last_error": null
}
```

```json [400 Bad Request]
{
  "error": {
    "type": "invalid_request_error",
    "message": "Not a positive rate, a rate sent with auto, or the business's own default currency"
  }
}
```

```json [404 Not Found]
{
  "error": {
    "type": "invalid_request_error",
    "message": "No such business"
  }
}
```

```json [409 Conflict]
{
  "error": {
    "type": "idempotency_error",
    "message": "Idempotency-Key conflict — the key is already in flight, or was reused with a different request payload."
  }
}
```

</code-group>
</template>
</api-operation>


## Sitemap

See the full [sitemap](https://twominutebilling.com/sitemap.md) for all pages.
