Calculate a monthly average exchange rate

The average USD/IDR rate for September 2026 was 17,742.56, the mean of 22 daily observations from 17,744.7 on 1 September to 17,891.1 on 30 September. Request the month's daily rates once and average them.

Calculate the average with the API

Use the daily observations for the month you want to average. Add the returned rates and divide by the number of observations, with each observation carrying the same weight. The request uses USD as the base and IDR as the requested currency. Keep that currency pair attached to the result when you use the average in a sheet or an invoice calculation.

  1. Get a key and set the environment variable Get a free key at narwhalapi.com/signup, then put it in the environment variable NARWHAL_API_KEY. The script reads that variable and sends the key in the Authorization header as a Bearer token.
  2. Set the month and currency Use the month's start and end dates with the daily observations endpoint. The request in the script selects IDR for September 2026, with USD as the base. Its limit is large enough for the month's observation rows.
  3. Request the rates and calculate the mean Use the script to request the observations, keep each date beside its rate, and calculate the arithmetic mean. It prints the observation count and average, followed by the first and last dated observations. The calculation reads each rate from rates within its observation and converts it to a number before adding it. It keeps the date alongside that number, so the printed first and last rows retain their dates.
    Python, the September 2026 average
    import os
    import requests
    
    r = requests.get("https://api.narwhalapi.com/v1/fx/rates/USD/observations",
                     params={"currencies": "IDR", "start_date": "2026-09-01", "end_date": "2026-09-30", "limit": 100},
                     headers={"Authorization": f"Bearer {os.environ['NARWHAL_API_KEY']}"}, timeout=10)
    r.raise_for_status()
    days = [(d["date"], float(d["rates"][0]["rate"])) for d in r.json()["observations"]]
    print(len(days), "days, average", round(sum(v for _, v in days) / len(days), 2))
    print("first", days[0], "last", days[-1])
  4. Read the dates alongside the result Read the first and last returned dates alongside the month you requested. Keep those dates and the observation count with the average so the result has a clear period and the daily rows behind it remain identifiable.

A month cannot have more than 100 daily observation rows, so the request limit covers this calculation. For longer ranges, follow next_cursor to retrieve the remaining observations. An average over a longer range needs the observations from that range; the first response alone may contain only part of them.

Calculate the average in a sheet

For a month by hand, paste the daily rates into column B and keep their observation dates beside them. Use the rows for the month you want to average. The September 2026 USD/IDR example has 22 observations, so the rates fit in the range used by this formula:

Average the September 2026 daily rates
=AVERAGE(B2:B23)

The formula takes the simple mean of the rates in that range. Each daily observation contributes equally, just as it does in the Python calculation. Keep the date column when you paste the rates so you can identify the month represented by the cells and the first and last observations included.

For an average per month in a longer list, use AVERAGEIFS. Use the observation dates to select the month whose rates should contribute to each average. This gives you a way to keep a longer list of dated observations together while calculating an average for each month from its own rows.

Which option to use when

SituationBest optionWhy
One month by handThe sheetAVERAGE calculates the mean of the month's daily rates
Many months or currenciesThe script with a loop over start and end datesRepeat the daily-observation calculation for each requested month or currency
An audit-grade policy rateThe rate your accounting policy namesThe required method depends on that policy

The sheet and script calculate a mean of daily observations. A policy rate can require a different method, such as an average of month-end rates or a weighted average. Decide which method your accounts require before using the result as the rate for an invoice.

Should I count weekends in a monthly average?

No. The data contains observation days only, and weekends have no rows. Averaging those observation days is the usual approach. Use the returned row count as the divisor for this arithmetic mean. Counting calendar days instead would change the calculation because the sum contains only the returned daily observations. Keep the mean tied to the dates that actually have a rate.

Which average do my accounts need?

That depends on your accounting policy; ask your accountant which rate and method it names. The arithmetic mean of daily observations is one common choice. Some accounting rules call for an average of month-end rates or a weighted average instead. Those methods use a different selection of rates or different weights, so the daily mean alone does not establish which rate belongs in your accounts.

What if the response starts later than the month I requested?

A history window can move the requested start date up to the window's first day without an error. Free includes the last 12 months, Basic includes 5 years, and Pro includes full history; see plans and limits. Read the first returned date before treating the result as a complete monthly average. If the response starts partway through the month, the returned observations cover only that part.

The API returns 403 plan_upgrade_required when the whole range ends before the plan window, or when you read a single date or period outside it. An earlier start date alone does not cause that error when the range extends into the available window.

Worked example: September 2026 USD/IDR

For September 2026, take the mean of the month's 22 daily USD/IDR observations. The first observation is dated 1 September 2026 and the last is dated 30 September 2026. Add the daily rates, divide by the observation count, and use the resulting average in the invoice calculation.

September 2026 calculationValue
Daily observations22
Rate on 1 September 202617,744.7
Rate on 30 September 202617,891.1
Arithmetic mean of daily observations17,742.56
Invoice amountUSD 8,000
Invoice at the monthly average8,000 × 17,742.56 = 141,940,480 IDR

Published .