UniRate API currency-exchange integration for Vendure — an injectable UniRateService (live rates, conversion, supported currencies, VAT rates) plus optional unirateConvert / unirateRate / unirateSupportedCurrencies GraphQL queries, with zero runtime dependencies.
npm install unirate-vendure@vendure/core (>=3.0.0), @nestjs/common, @nestjs/graphql, graphql, and reflect-metadata are peer dependencies — your Vendure project already provides them.
Get a free API key at unirateapi.com.
import { VendureConfig } from "@vendure/core";
import { UniRatePlugin } from "unirate-vendure";
export const config: VendureConfig = {
// ...your existing config
plugins: [
UniRatePlugin.init({
apiKey: process.env.UNIRATE_API_KEY!,
defaultBaseCurrency: "USD", // used by getRates() when no base is passed
exposeShopApi: false, // Admin API only by default
}),
],
};UniRateService is a standard NestJS provider, exported by the plugin and available application-wide:
import { Injectable } from "@nestjs/common";
import { UniRateService } from "unirate-vendure";
@Injectable()
export class PricingService {
constructor(private readonly unirate: UniRateService) {}
async priceInEur(usd: number): Promise<number> {
return this.unirate.convert(usd, "USD", "EUR");
}
}The plugin extends the Admin API (and the Shop API when exposeShopApi: true) with:
query {
unirateConvert(from: "USD", to: "EUR", amount: 100) {
from
to
amount
result
}
unirateRate(from: "USD", to: "GBP") {
rate
}
unirateSupportedCurrencies
}By default the queries are rejected on the Shop API to avoid exposing exchange lookups to unauthenticated storefront traffic. Set
exposeShopApi: trueto opt in.
| Method | Returns | Tier |
|---|---|---|
getRate(from, to) |
Promise<number> |
Free |
getRates(base?) |
Promise<Record<string, number>> |
Free |
convert(amount, from, to) |
Promise<number> |
Free |
getSupportedCurrencies() |
Promise<string[]> |
Free |
getVatRates() / getVatRates(country) |
Promise<VATRatesAll | VATRateOne> |
Free |
getHistoricalRate(date, from, to) |
Promise<number> |
Pro |
getTimeSeries(startDate, endDate, base?, currencies?) |
Promise<Record<string, Record<string, number>>> |
Pro |
getHistoricalLimits() |
Promise<HistoricalLimitsResponse> |
Pro |
raw |
UniRateClient |
escape hatch |
Currency and country codes are uppercased automatically before the request.
UniRatePlugin.init({
apiKey: string; // required — your UniRate API key
baseUrl?: string; // default "https://api.unirateapi.com"
timeoutMs?: number; // default 30000
defaultBaseCurrency?: string; // default "USD"
exposeShopApi?: boolean; // default false (Admin API only)
});Every method rejects with a typed error inheriting from UniRateError:
| HTTP | Error | When |
|---|---|---|
| 400 | InvalidRequestError |
Bad parameters |
| 401 | AuthenticationError |
Missing / invalid API key |
| 403 | ProRequiredError |
Endpoint requires a Pro subscription |
| 404 | InvalidCurrencyError |
Unknown currency / no data |
| 429 | RateLimitError |
Rate limit exceeded |
| other / network | UniRateError |
Carries status + body |
import { ProRequiredError } from "unirate-vendure";
try {
await unirate.getHistoricalRate("2020-01-01", "USD", "EUR");
} catch (err) {
if (err instanceof ProRequiredError) {
// historical data needs a UniRate Pro plan
}
}Historical and time-series endpoints are Pro-gated and return 403
(ProRequiredError) on the free tier.
The free tier is rate limited; a 429 surfaces as RateLimitError. Upgrade
at unirateapi.com for higher limits and historical
data.
@unirate/nestjs— the NestJS module this plugin builds onmedusa-plugin-unirate— the same integration for Medusa v2unirate-api— the standalone Node client
MIT © Unirate Team