DEV Community

Cover image for Australian Exchange Rates: A Free Currency Converter API for Developers
Mathias Ahlgren
Mathias Ahlgren

Posted on

Australian Exchange Rates: A Free Currency Converter API for Developers

If you build software for Australian businesses, exchange rates are rarely “just another data point.”

They affect invoice calculations, cross-border e-commerce, tax reporting, accounting workflows, financial reconciliation, and audit trails. For many use cases, you need a reliable source of official Australian exchange rate data, not a scraped webpage or an undocumented feed that could change without warning.

Exchange Rates API provides developer-friendly access to official Reserve Bank of Australia (RBA) exchange rates through simple REST endpoints, historical data, currency conversion, and webhook notifications.

This article explains how to retrieve Australian exchange rates, convert currencies, and avoid inefficient REST polling by using webhooks to be notified when the day’s rates are ready.

Why official RBA exchange-rate data matters

The RBA publishes daily exchange-rate data that is useful for Australian businesses dealing with international currencies. However, accessing that source data directly can be inconvenient because it is published as RSS/XML feeds, and Excel files.

That creates avoidable engineering work:

  • Scraping HTML is fragile.
  • Parsing XML and RDF namespaces is cumbersome.
  • Spreadsheet-based workflows are difficult to automate.
  • Handling historical data consistently takes time.
  • Monitoring for the day’s newly published rates adds more complexity.

Exchange Rates API turns that data into clean JSON endpoints built for applications.

The service provides:

  • Official RBA-sourced currency exchange data
  • AUD as the base currency
  • Daily updated rates
  • Historical data from 2018 onwards
  • More than 30,000 historical data points
  • A free starting tier with 300 one-time trial requests and no credit card required
  • REST API endpoints plus webhooks for eligible plans

Exchange Rates API sources data from the Reserve Bank of Australia, but it is not affiliated with or endorsed by the RBA.

Get your first Australian exchange rate

After getting an API key from the Exchange Rates API dashboard, request the latest rates with the /latest endpoint.

curl https://api.exchangeratesapi.com.au/latest \
  -H "Authorization: Bearer your_api_key_here"
Enter fullscreen mode Exit fullscreen mode

A successful response looks like this:

{
  "success": true,
  "timestamp": 1725080400,
  "base": "AUD",
  "date": "2025-08-31",
  "rates": {
    "USD": 0.643512,
    "EUR": 0.562934,
    "GBP": 0.487421,
    "JPY": 96.8321,
    "NZD": 1.0942,
    "TWI": 60.5
  }
}
Enter fullscreen mode Exit fullscreen mode

If the response contains:

{
  "USD": 0.643512
}
Enter fullscreen mode Exit fullscreen mode

Then 1 AUD equals 0.643512 USD.

Use the API in JavaScript

Here is a minimal JavaScript example using fetch.

const response = await fetch("https://api.exchangeratesapi.com.au/latest", {
  headers: {
    Authorization: `Bearer ${process.env.EXCHANGE_RATES_API_KEY}`
  }
});

if (!response.ok) {
  throw new Error(`Exchange Rates API error: ${response.status}`);
}

const data = await response.json();

console.log(`Rate date: ${data.date}`);
console.log(`1 AUD = ${data.rates.USD} USD`);
console.log(`1 AUD = ${data.rates.EUR} EUR`);
Enter fullscreen mode Exit fullscreen mode

In production, keep your API key in an environment variable or secret manager. Do not put it in browser-side code.

Convert AUD to another currency

A simple conversion is multiplication when the rate is quoted relative to AUD.

For example, to convert an Australian invoice total into USD:

const audAmount = 250;
const usdRate = data.rates.USD;

const usdAmount = audAmount * usdRate;

console.log(`A$${audAmount} = US$${usdAmount.toFixed(2)}`);
Enter fullscreen mode Exit fullscreen mode

If 1 AUD equals 0.643512 USD, then A$250 equals approximately US$160.88.

Depending on your product and reporting obligations, decide explicitly how and when to round monetary values. It is also good practice to retain the original rate, source date, converted amount, and rounding rule alongside every transaction.

That makes later reconciliation and audit work much easier.

Supported currencies

Exchange Rates API supports the currencies published by the RBA, including major currencies and key Asia-Pacific trading currencies:

  • USD, US dollar
  • EUR, euro
  • GBP, British pound sterling
  • JPY, Japanese yen
  • CHF, Swiss franc
  • CAD, Canadian dollar
  • CNY, Chinese renminbi
  • KRW, South Korean won
  • SGD, Singapore dollar
  • NZD, New Zealand dollar
  • HKD, Hong Kong dollar
  • INR, Indian rupee
  • THB, Thai baht
  • MYR, Malaysian ringgit
  • IDR, Indonesian rupiah
  • VND, Vietnamese dong
  • PHP, Philippine peso

You can retrieve the latest exchange rates, request historical rates, look up rates for a particular currency, or use the currency conversion endpoint.

The problem with polling for daily rates

A common integration pattern is polling: repeatedly requesting /latest until the day’s rate arrives.

For example:

setInterval(async () => {
  const response = await fetch(
    "https://api.exchangeratesapi.com.au/latest",
    {
      headers: {
        Authorization: `Bearer ${process.env.EXCHANGE_RATES_API_KEY}`
      }
    }
  );

  const data = await response.json();

  if (data.date === new Date().toISOString().slice(0, 10)) {
    console.log("Today's rates are available.");
  }
}, 15 * 60 * 1000);
Enter fullscreen mode Exit fullscreen mode

This works, but it is not ideal.

The RBA targets publication around 4:00 PM Australian Eastern Time on business days. In practice, publication can drift, often landing between 4:00 PM and 5:00 PM, and sometimes later. Rates are not published on weekends or NSW public holidays.

That uncertainty encourages frequent polling. If you poll every 15 minutes over a typical business day, your application can make dozens of requests simply to discover whether a new daily data set exists.

Polling creates several issues:

  • Wasted API requests: Most calls return data you already have.
  • Higher quota usage: Repeated calls consume your request allowance.
  • Delayed processing: Your application only notices a new rate at the next scheduled interval.
  • More operational complexity: You need schedules, holiday handling, retries, and time-zone logic.
  • Extra infrastructure work: Background workers and cron jobs run even when no new rates have been published.

For a workflow based on a single daily event, there is a better approach: webhooks.

Use webhooks to get notified instead

A webhook reverses the flow of control.

Instead of your application repeatedly asking, “Are today’s rates ready yet?”, Exchange Rates API notifies your application when it detects that the RBA has published new rates.

You register an HTTPS endpoint, and the API sends a signed HTTP POST request to that URL. This normally happens within ten minutes of publication.

With polling, the flow looks like this:

  1. Your app asks the API whether rates are ready.
  2. The API returns the currently available data.
  3. Your app waits for a scheduled interval.
  4. Your app asks again.
  5. This repeats until the latest daily rates are available.

With a webhook, the flow is simpler:

  1. The RBA publishes new daily rates.
  2. Exchange Rates API detects the new data.
  3. Exchange Rates API sends your application a signed HTTP POST request.
  4. Your application receives and processes the rates immediately.

Webhooks are available on Professional plans and above. REST endpoints remain available, so webhooks are an addition to REST, not a replacement.

A strong implementation uses both:

  • Webhooks for prompt, event-driven rate updates.
  • REST endpoints for historical queries, backfills, reconciliation, manual refreshes, and recovery workflows.

What a rate-published webhook looks like

When new rates are available, Exchange Rates API sends JSON to your registered endpoint.

The request includes headers such as:

Content-Type: application/json
X-ExchangeRates-Event: rates.published
X-ExchangeRates-Signature: sha256=<hmac>
X-ExchangeRates-Delivery: <unique-delivery-uuid>
User-Agent: ExchangeRatesAPI-Webhook/1.0
Enter fullscreen mode Exit fullscreen mode

Example webhook payload:

{
  "event": "rates.published",
  "date": "2026-06-23",
  "base": "AUD",
  "rates": {
    "USD": 0.7004,
    "JPY": 113.25
  },
  "delivery_id": "0b9d8f60-a5c3-e1d9-b2f4-a6c83f9c4e2a",
  "timestamp": 1782086400
}
Enter fullscreen mode Exit fullscreen mode

Depending on your subscription configuration, the rates object contains every supported currency or only the currencies you selected.

Once received, your system can immediately:

  • Store the day’s official rates in a database.
  • Recalculate customer-facing prices.
  • Create accounting conversion records.
  • Update internal dashboards.
  • Trigger import or export settlement workflows.
  • Notify finance teams that rates are ready.
  • Start an end-of-day reconciliation process.

Your endpoint should return any 2xx response to acknowledge that it received the delivery.

Verify webhook signatures, always

Never trust an incoming webhook simply because it reaches your endpoint.

Every Exchange Rates API webhook includes an X-ExchangeRates-Signature header. The signature is an HMAC-SHA256 calculated using the raw request body and your subscription signing secret.

The important detail is that you must verify the exact raw bytes received.

Do not parse the JSON and then serialize it again before calculating the signature. Whitespace or key-order changes can produce a different signature, causing verification to fail.

Here is an Express example that preserves the raw request body:

import express from "express";
import crypto from "node:crypto";

const app = express();

app.post(
  "/webhooks/exchange-rates",
  express.raw({ type: "application/json" }),
  async (req, res) => {
    const signature = req.get("X-ExchangeRates-Signature");
    const signingSecret = process.env.EXCHANGE_RATES_WEBHOOK_SECRET;

    const expectedSignature =
      "sha256=" +
      crypto
        .createHmac("sha256", signingSecret)
        .update(req.body)
        .digest("hex");

    const received = Buffer.from(signature || "");
    const expected = Buffer.from(expectedSignature);

    const isValid =
      received.length === expected.length &&
      crypto.timingSafeEqual(received, expected);

    if (!isValid) {
      return res.status(401).json({
        error: "Invalid webhook signature"
      });
    }

    const event = JSON.parse(req.body.toString("utf8"));

    if (event.event === "rates.published") {
      console.log(`Received rates for ${event.date}`);
      console.log(`1 AUD = ${event.rates.USD} USD`);

      // Save rates, enqueue downstream work, or trigger a business workflow.
    }

    return res.status(200).json({ received: true });
  }
);

app.listen(3000, () => {
  console.log("Webhook receiver listening on port 3000");
});
Enter fullscreen mode Exit fullscreen mode

Use a constant-time comparison function, such as Node.js crypto.timingSafeEqual, when comparing signatures.

Design your webhook receiver for production

A webhook endpoint should be secure, fast, and idempotent.

Return a 2xx response quickly

Your receiver should acknowledge a delivery promptly. If processing is slow, such as recalculating prices across a large catalogue, add the work to a queue and process it asynchronously.

await queue.add("process-exchange-rates", event);

return res.status(202).json({
  queued: true
});
Enter fullscreen mode Exit fullscreen mode

Deduplicate deliveries

Webhooks can be retried if your endpoint does not return a 2xx response. Store and check the delivery_id before processing so a duplicate delivery does not create duplicate records or trigger a workflow twice.

const alreadyProcessed = await deliveries.exists(event.delivery_id);

if (alreadyProcessed) {
  return res.status(200).json({
    received: true,
    duplicate: true
  });
}

await deliveries.save(event.delivery_id);
Enter fullscreen mode Exit fullscreen mode

Store the rate date

The webhook payload includes a date field. Store that date with the exchange-rate data rather than assuming it is the same as your server’s current date.

This matters for:

  • Historical reporting
  • Financial audits
  • Time-zone differences
  • Delayed deliveries
  • Reconciliation after downtime

Expect retries

If your endpoint does not return a 2xx response, Exchange Rates API retries the delivery with backoff.

Deliveries that never succeed are dropped after the retry budget is exhausted. If a subscription fails on seven consecutive publications, it is automatically deactivated.

Monitor your webhook receiver and alert on failures. If a subscription becomes inactive, fix the endpoint and re-create the subscription once it is healthy.

Keep a REST fallback

Webhooks are ideal for immediate notification, but a resilient application should still have a recovery path.

For example, an overnight reconciliation job can call /latest or a date-specific endpoint and confirm that the expected daily rate record exists.

This helps protect your workflow against:

  • Downtime in your own infrastructure
  • Missed deliveries
  • Incorrect endpoint configuration
  • Temporary networking failures
  • Operational mistakes

Test before waiting for the next rate publication

You should not need to wait until the next business day to validate your webhook endpoint.

Exchange Rates API provides a test endpoint that sends a signed rates.test delivery. The payload is signed exactly like a production webhook, which makes it useful for verifying that:

  • Your public endpoint is reachable.
  • You retain and verify the raw request body.
  • Your signing secret is correct.
  • Your endpoint returns a 2xx response.
  • Your event-processing pipeline works.
  • Your logs and alerts are configured correctly.

Treat test events as non-production data and do not apply them to live financial records.

A practical architecture for AUD exchange-rate workflows

A typical Australian accounting or e-commerce workflow might look like this:

  1. Register a webhook endpoint.
  2. Verify the HMAC signature using the raw request body.
  3. Deduplicate deliveries using delivery_id.
  4. Persist the official AUD base rates and supplied date.
  5. Queue downstream calculations, notifications, or reporting tasks.
  6. Return a fast 2xx response.
  7. Run a periodic REST reconciliation job as a safety net.
  8. Use historical REST endpoints for reports, corrections, and backfills.

This approach gives you timely daily updates without repeatedly calling an endpoint all afternoon.

Start building

If your application needs official Australian exchange-rate data, Exchange Rates API provides a practical route from RBA-published rates to usable application data.

Start with the REST API for current rates, historical data, and currency conversion. When your workflow depends on knowing precisely when daily rates are available, use webhooks and let the update come to you.

Top comments (0)