PHPackages                             brightcreations/exchange-rates - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. brightcreations/exchange-rates

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

brightcreations/exchange-rates
==============================

A Laravel package for fetching exchange rates from various sources.

v0.9.2(3w ago)19.2k↓32.1%1MITPHPPHP &gt;=8.1CI passing

Since May 22Pushed 1w agoCompare

[ Source](https://github.com/BrightCreations/exchange-rates)[ Packagist](https://packagist.org/packages/brightcreations/exchange-rates)[ RSS](/packages/brightcreations-exchange-rates/feed)WikiDiscussions main Synced 2w ago

READMEChangelog (1)Dependencies (44)Versions (45)Used By (1)

Exchange Rates Library
======================

[](#exchange-rates-library)

[![Downloads](https://camo.githubusercontent.com/147c4b1fc2deae1934d0a1efa6c0ff6750e4f811facf5ce8f589617fb41a6f79/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f646f776e6c6f6164732f4272696768744372656174696f6e732f65786368616e67652d72617465732f746f74616c)](https://camo.githubusercontent.com/147c4b1fc2deae1934d0a1efa6c0ff6750e4f811facf5ce8f589617fb41a6f79/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f646f776e6c6f6164732f4272696768744372656174696f6e732f65786368616e67652d72617465732f746f74616c)[![License](https://camo.githubusercontent.com/be2c119c24c74c27913cab28d6ea0de217c8db56c2a9fa1d78182966afd1294b/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f4272696768744372656174696f6e732f65786368616e67652d7261746573)](https://camo.githubusercontent.com/be2c119c24c74c27913cab28d6ea0de217c8db56c2a9fa1d78182966afd1294b/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f4272696768744372656174696f6e732f65786368616e67652d7261746573)[![Last Commit](https://camo.githubusercontent.com/f3641f7b1910b494d86c0cd6a0950f0a466927bab42ee69064fe15123a8b8c97/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f4272696768744372656174696f6e732f65786368616e67652d7261746573)](https://camo.githubusercontent.com/f3641f7b1910b494d86c0cd6a0950f0a466927bab42ee69064fe15123a8b8c97/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f4272696768744372656174696f6e732f65786368616e67652d7261746573)[![Stars](https://camo.githubusercontent.com/37018fbb8976abf6c068059a1ff6f78cd1595e28b811e47409d5771acb013185/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f73746172732f4272696768744372656174696f6e732f65786368616e67652d72617465733f7374796c653d736f6369616c)](https://camo.githubusercontent.com/37018fbb8976abf6c068059a1ff6f78cd1595e28b811e47409d5771acb013185/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f73746172732f4272696768744372656174696f6e732f65786368616e67652d72617465733f7374796c653d736f6369616c)[![Tests](https://camo.githubusercontent.com/24b811c404e991eb9273a3a0d7c762f66008616e1dce4dcf9f8fc694422da138/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f4272696768744372656174696f6e732f65786368616e67652d72617465732f74657374732e796d6c3f6c6162656c3d7465737473)](https://camo.githubusercontent.com/24b811c404e991eb9273a3a0d7c762f66008616e1dce4dcf9f8fc694422da138/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f4272696768744372656174696f6e732f65786368616e67652d72617465732f74657374732e796d6c3f6c6162656c3d7465737473)

A comprehensive Laravel package for fetching, storing, and managing exchange rates from various external APIs. This library provides a clean, extensible architecture for handling currency exchange rates with support for both current and historical data.

🚀 Features
----------

[](#-features)

- **Multiple API Support**: Built-in support for Exchange Rate API, Open Exchange Rates, and World Bank
- **Automatic Fallback**: Intelligent fallback mechanism that tries services in order until one succeeds
- **Historical Data**: Store and retrieve historical exchange rates
- **Bulk Operations**: Efficient bulk operations for multiple currencies
- **Database Storage**: Automatic storage and caching of exchange rates
- **Smart Caching**: Automatic caching for World Bank yearly data
- **Extensible Architecture**: Easy to add new exchange rate providers
- **DTO Pattern**: Clean data transfer objects for type-safe operations
- **Repository Pattern**: Clean separation between data access and business logic
- **Built-in REST Endpoints**: Ready-to-use read-only HTTP endpoints with normal and reversed lookup modes

---

📦 Installation
--------------

[](#-installation)

### 1. Install via Composer

[](#1-install-via-composer)

```
composer require brightcreations/exchange-rates
```

### 2. Publish Configuration and Migrations

[](#2-publish-configuration-and-migrations)

```
# Publish configuration file
php artisan vendor:publish --tag=exchange-rates-config

# Publish migrations
php artisan vendor:publish --tag=exchange-rate-migrations

# Run migrations
php artisan migrate
```

### 3. Configure Environment Variables

[](#3-configure-environment-variables)

Add the following to your `.env` file:

```
# Exchange Rate API
EXCHANGE_RATE_API_TOKEN=your_api_token_here
EXCHANGE_RATE_API_VERSION=v6
EXCHANGE_RATE_API_BASE_URL=https://v6.exchangerate-api.com/v6/

# Open Exchange Rates
OPEN_EXCHANGE_RATE_BASE_URL=https://openexchangerates.org/api/
OPEN_EXCHANGE_RATE_APP_ID=your_app_id_here

# World Bank (No API key required - Free fallback service)
WORLD_BANK_EXCHANGE_RATE_BASE_URL=https://api.worldbank.org/v2
```

---

🏗️ Architecture Overview
------------------------

[](#️-architecture-overview)

This library follows a clean, layered architecture:

- **Services**: Handle API communication and business logic
- **Repositories**: Manage database operations
- **DTOs**: Type-safe data transfer objects
- **Contracts**: Define interfaces for extensibility
- **Models**: Eloquent models for database entities

---

Historical rate provider capabilities
-------------------------------------

[](#historical-rate-provider-capabilities)

When consuming historical rates (e.g. via [brightcreations/money-converter](https://github.com/BrightCreations/money-converter) `fetchOnFail()`, `interpolate()`, or `extrapolate()`), provider behaviour varies:

ProviderAuto-fetch on `getHistoricalExchangeRate` missGranularityNotes`OpenExchangeRateService`YesDailyFetches and stores on `ModelNotFoundException``ExchangeRateApiService`YesDailySame as Open Exchange Rates`WorldBankExchangeRateApiService`No (DB only)YearlyPre-populate with `php artisan exchange-rates:backfill``FallbackExchangeRateService`Delegates to fallback orderPer providerFirst successful provider in `fallback_order` winsSee [money-converter historical conversion docs](https://github.com/BrightCreations/money-converter#historical-conversion) for how `fetchOnFail`, `interpolate()`, and `extrapolate()` use these capabilities.

Programmatic check:

```
use BrightCreations\ExchangeRates\Facades\ExchangeRate;

ExchangeRate::supportsHistoricalApiFetch(); // true when provider auto-fetches on historical miss
ExchangeRate::isSupportHistoricalExchangeRate(); // true when historical DB reads are available
```

---

Consuming with money-converter
------------------------------

[](#consuming-with-money-converter)

[brightcreations/money-converter](https://github.com/BrightCreations/money-converter) is the recommended package for **currency conversion** in Laravel apps that use this library.

1. Install both packages: `composer require brightcreations/money-converter brightcreations/exchange-rates`
2. Follow the [money-converter integration guide](https://github.com/BrightCreations/money-converter#integration-guide) to publish configs, migrate, and populate rates
3. money-converter's default PDO provider reads the same `currency_exchange_rates` tables this package writes

**Version requirement:** money-converter `^0.6.0` requires exchange-rates `^0.8.0` for bounding-rate repository methods used by interpolation and extrapolation.

---

📚 Documentation
---------------

[](#-documentation)

- **[Installation &amp; Configuration](docs/installation.md)** - Detailed setup instructions
- **[Services &amp; Contracts](docs/services.md)** - Understanding the service layer and contracts
- **[Repository Pattern](docs/repository.md)** - Database operations and DTO usage
- **[DTOs Guide](docs/dtos.md)** - Data Transfer Objects explained
- **[API Reference](docs/api-reference.md)** - Complete method documentation
- **[Examples](docs/examples.md)** - Practical usage examples

---

🔧 Quick Start
-------------

[](#-quick-start)

### Basic Usage

[](#basic-usage)

```
use BrightCreations\ExchangeRates\Facades\ExchangeRate;

class CurrencyController extends Controller
{
    public function getRates(string $currency = 'USD')
    {
        // Fetch from provider, store, and return current exchange rates
        $rates = ExchangeRate::storeExchangeRates($currency);

        return response()->json($rates);
    }
}
```

### Historical Data

[](#historical-data)

```
use BrightCreations\ExchangeRates\Facades\HistoricalExchangeRate;
use Carbon\Carbon;

class HistoricalController extends Controller
{
    public function getHistoricalRates(string $currency, string $date)
    {
        $dateTime = Carbon::parse($date);

        $rates = HistoricalExchangeRate::getHistoricalExchangeRates($currency, $dateTime);

        return response()->json($rates);
    }
}
```

### Repository Usage

[](#repository-usage)

```
use BrightCreations\ExchangeRates\Facades\ExchangeRateRepository;

$rate = ExchangeRateRepository::getExchangeRate('USD', 'EUR');
```

> **Note:** You can also use Laravel's `resolve()` or `app()` helpers to access the services directly:
>
> ```
> $service = resolve(ExchangeRateServiceInterface::class);
> $service = app(ExchangeRateServiceInterface::class);
> ```
>
>
>
> The facades are the recommended and most convenient way for most use cases.

---

🌐 Built-in HTTP Endpoints
-------------------------

[](#-built-in-http-endpoints)

The package ships with a default read-only REST endpoint that returns exchange rates already stored in the database. It does **not** call any external provider — use `storeExchangeRates(...)` (via Artisan commands or your own code) to populate data first.

### Route Configuration

[](#route-configuration)

Routes are **enabled by default**. Publish the config to customise or disable them:

```
// config/exchange-rates.php
'routes' => [
    'enabled'    => true,
    'prefix'     => 'exchange-rates', // segment appended after 'api/'
    'middleware' => ['api'],
],
```

The final URL is always `api/{prefix}/...`, so the default resolves to `/api/exchange-rates/{currency}`.

---

### Normal Mode — rates from a base currency

[](#normal-mode--rates-from-a-base-currency)

```
GET /api/exchange-rates/{currency}

```

`{currency}` is the **base** currency. Returns all stored target currencies and their rates.

ParameterLocationRequiredDescription`currency`pathyesISO 4217 base currency code (3 letters, e.g. `USD`). Case-insensitive.`currencies`query stringnoComma-separated target currency codes to filter by (e.g. `EUR,GBP,SAR`). If omitted, all stored targets are returned.#### Example — all targets

[](#example--all-targets)

```
GET /api/exchange-rates/USD

```

```
{
    "data": {
        "base_currency": "USD",
        "rates": [
            { "target_currency": "EUR", "rate": "0.9200000000", "last_updated": "2026-03-09T00:00:00.000000Z" },
            { "target_currency": "GBP", "rate": "0.7800000000", "last_updated": "2026-03-09T00:00:00.000000Z" },
            { "target_currency": "SAR", "rate": "3.7500000000", "last_updated": "2026-03-09T00:00:00.000000Z" }
        ]
    }
}
```

#### Example — filtered

[](#example--filtered)

```
GET /api/exchange-rates/USD?currencies=EUR,SAR

```

```
{
    "data": {
        "base_currency": "USD",
        "rates": [
            { "target_currency": "EUR", "rate": "0.9200000000", "last_updated": "2026-03-09T00:00:00.000000Z" },
            { "target_currency": "SAR", "rate": "3.7500000000", "last_updated": "2026-03-09T00:00:00.000000Z" }
        ]
    }
}
```

---

### Reversed Mode — rates into a target currency

[](#reversed-mode--rates-into-a-target-currency)

```
GET /api/exchange-rates/{currency}?reversed=true

```

`{currency}` becomes the **target** currency. Returns all stored source currencies that have a rate pointing to this target. Each `rate` is the stored **source → target** value (same direction as `source_currency` → `target_currency`).

ParameterLocationRequiredDescription`currency`pathyesISO 4217 target currency code (3 letters, e.g. `EUR`). Case-insensitive.`reversed`query stringyesMust be `true` (or `1`) to activate this mode.`currencies`query stringnoComma-separated source currency codes to filter by (e.g. `USD,GBP`). If omitted, all stored sources are returned.#### Example — all sources

[](#example--all-sources)

```
GET /api/exchange-rates/EUR?reversed=true

```

```
{
    "data": {
        "target_currency": "EUR",
        "rates": [
            { "source_currency": "USD", "rate": "0.9200000000", "last_updated": "2026-03-09T00:00:00.000000Z" },
            { "source_currency": "GBP", "rate": "1.1800000000", "last_updated": "2026-03-09T00:00:00.000000Z" },
            { "source_currency": "SAR", "rate": "0.2453000000", "last_updated": "2026-03-09T00:00:00.000000Z" }
        ]
    }
}
```

#### Example — filtered

[](#example--filtered-1)

```
GET /api/exchange-rates/EUR?reversed=true&currencies=USD,SAR

```

```
{
    "data": {
        "target_currency": "EUR",
        "rates": [
            { "source_currency": "USD", "rate": "0.9200000000", "last_updated": "2026-03-09T00:00:00.000000Z" },
            { "source_currency": "SAR", "rate": "0.2453000000", "last_updated": "2026-03-09T00:00:00.000000Z" }
        ]
    }
}
```

#### Example — reciprocal pair lookup

[](#example--reciprocal-pair-lookup)

Equivalent to `GET /api/exchange-rates/GBP?currencies=USD` when a `GBP→USD` row is stored:

```
GET /api/exchange-rates/USD?reversed=true&currencies=GBP

```

```
{
    "data": {
        "target_currency": "USD",
        "rates": [
            { "source_currency": "GBP", "rate": "1.3352310000", "last_updated": "2026-03-09T00:00:00.000000Z" }
        ]
    }
}
```

---

### HTTP Responses

[](#http-responses)

StatusMeaning200Success. `rates` is an empty array when no data is stored for that currency.422Validation error — invalid currency code format.---

🔌 Supported APIs
----------------

[](#-supported-apis)

The library uses an intelligent fallback mechanism. By default, it tries services in this order:

1. **Open Exchange Rates** (primary)
2. **Exchange Rate API** (secondary)
3. **World Bank** (tertiary fallback)

### Exchange Rate API

[](#exchange-rate-api)

- **Provider**: [Exchange Rate API](https://www.exchangerate-api.com/)
- **Features**: Current and historical rates, real-time updates
- **Requires**: API Token
- **Cost**: Free tier available

### Open Exchange Rates

[](#open-exchange-rates)

- **Provider**: [Open Exchange Rates](https://openexchangerates.org/)
- **Features**: Current and historical rates, real-time updates
- **Requires**: App ID
- **Cost**: Free tier available

### World Bank Exchange Rate API

[](#world-bank-exchange-rate-api)

- **Provider**: [World Bank Open Data](https://api.worldbank.org/)
- **Features**: Historical yearly average rates
- **Requires**: No API key (free and open)
- **Cost**: Free
- **Data**: Yearly averages (less precise than real-time services)
- **Coverage**: ~160+ currencies mapped from country data
- **Caching**: 24-hour cache for efficiency

> **Note on World Bank Data**: The World Bank service provides yearly average exchange rates based on country-level data. While less precise than real-time APIs, it serves as an excellent free fallback option. Exchange rates are computed by:
>
> 1. Fetching LCU (Local Currency Unit) per USD rates by country
> 2. Mapping countries to currencies using [pragmarx/countries](https://github.com/antonioribeiro/countries)
> 3. Computing cross-currency rates from USD-anchored values
>
> **Limitations**:
>
> - Yearly averages only (not daily/real-time)
> - Some currencies may not be available if country mapping fails
> - Aggregate regions (like "Euro Area") are filtered out automatically

---

🔄 Fallback Configuration
------------------------

[](#-fallback-configuration)

You can customise the fallback order in `config/exchange-rates.php`:

```
'fallback_order' => [
    OpenExchangeRateService::class,
    ExchangeRateApiService::class,
    WorldBankExchangeRateApiService::class,
],
```

Or use a specific service directly:

```
use BrightCreations\ExchangeRates\Concretes\WorldBankExchangeRateApiService;

$worldBankService = app(WorldBankExchangeRateApiService::class);
$rates = $worldBankService->storeExchangeRates('EUR');
```

---

🤝 Contributing
--------------

[](#-contributing)

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

---

📄 License
---------

[](#-license)

This project is licensed under the MIT License — see the [LICENSE](LICENSE) file for details.

🆘 Support
---------

[](#-support)

For support, please contact:

- **Email**:
- **Developer at**: DAZU DPN
- **Company**: Bright Creations

---

**Made with ❤️ by Bright Creations**

###  Health Score

49

—

FairBetter than 94% of packages

Maintenance97

Actively maintained with recent releases

Popularity27

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 70.6% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~11 days

Recently: every ~6 days

Total

40

Last Release

21d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/b3ecbef0a371010403e945b0daa79fffba250d0753dbbadabc01d7b54b04cb5e?d=identicon)[kareemshaaban-bc](/maintainers/kareemshaaban-bc)

---

Top Contributors

[![kareemshaaban221](https://avatars.githubusercontent.com/u/53887143?v=4)](https://github.com/kareemshaaban221 "kareemshaaban221 (101 commits)")[![kareemshaaban-bc](https://avatars.githubusercontent.com/u/212358009?v=4)](https://github.com/kareemshaaban-bc "kareemshaaban-bc (35 commits)")[![Zohair22](https://avatars.githubusercontent.com/u/64865439?v=4)](https://github.com/Zohair22 "Zohair22 (7 commits)")

---

Tags

laravelexchange ratescurrency conversion

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/brightcreations-exchange-rates/health.svg)

```
[![Health](https://phpackages.com/badges/brightcreations-exchange-rates/health.svg)](https://phpackages.com/packages/brightcreations-exchange-rates)
```

###  Alternatives

[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

265.2k](/packages/aedart-athenaeum)[forjedio/inertia-table

Backend-driven dynamic tables for Laravel + Inertia.js

272.0k](/packages/forjedio-inertia-table)[psalm/plugin-laravel

Psalm plugin for Laravel

3345.4M354](/packages/psalm-plugin-laravel)[mike-bronner/laravel-model-caching

Automatic caching for Eloquent models.

2.4k161.4k2](/packages/mike-bronner-laravel-model-caching)[simplestats-io/laravel-client

Server-side analytics for Laravel that follows the full funnel from visit to registration to payment, attributed to the channel that drove it. Revenue, MRR, churn and ad-spend profit (ROAS/CAC) per channel. GDPR compliant, ad-blocker proof.

5226.7k](/packages/simplestats-io-laravel-client)[api-platform/laravel

API Platform support for Laravel

58190.1k21](/packages/api-platform-laravel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
