> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wiseyield.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Currency model

> EUR-denominated billing with adaptive checkout, per-farm display currency, and row-level FX conversion in financial endpoints.

WiseYield has **two distinct currency concerns**:

1. **Billing currency** — what the user pays for their subscription. EUR-denominated, displayed in the buyer's local currency at checkout.
2. **Operational currency** — what gets stored on every financial row (expenses, sales, invoices, etc.) and how aggregations roll up to a single per-farm display currency.

## Billing currency

Each pricing tier has a **single EUR-denominated product** in Dodo Payments. At checkout, **Dodo Adaptive Currency** renders the EUR amount in the user's local currency based on the `billing.country` passed during checkout-session creation. There is no manual currency selector.

| Concept                      | Value                                               |
| ---------------------------- | --------------------------------------------------- |
| Authoritative product price  | EUR                                                 |
| Display at checkout          | Buyer's local currency (auto-detected from country) |
| Supported display currencies | 12 groups (auto-detected)                           |
| FX cache TTL                 | 24 hours                                            |
| Rate sources                 | ECB primary, open.er-api.com canary fallback        |

The pricing page mirrors the same EUR-to-local conversion so the dashboard price and the checkout price match.

## Operational currency

Every financial row in the platform carries a `currency` column (`crop_expenses`, `crop_sales`, `farm_expenses`, `farm_income`, `farmer_invoices`, etc.) with `USD` as the schema-level default. A farm has an optional `currency` override and a `country` for fallback inference.

### Display currency precedence

When the API rolls aggregations up to a single per-farm "base" currency, it resolves in this order:

1. **`farms.currency`** (explicit override set in farm settings).
2. **Country-derived default** via the country → currency map.
3. **`USD`** as final fallback.

This guarantees a coherent total even when a farm was misconfigured or rows were imported with free-form currency codes.

### Row-level conversion

Aggregations **do not sum raw amounts across different currencies**. They convert each row individually using today's spot rate (EUR-bridged via the rate map), then sum the converted values.

A financial endpoint response carries three fields that make the aggregation transparent:

```json theme={null}
{
  "baseCurrency": "EUR",
  "total": 12345.67,
  "byCurrency": {
    "EUR": { "original": 8000.00, "converted": 8000.00, "rate": 1 },
    "USD": { "original": 4500.00, "converted": 4140.50, "rate": 0.92011 },
    "EGP": { "original": 9000.00, "converted": 205.17, "rate": 0.022797 }
  },
  "unconvertedCurrencies": []
}
```

* `total` — sum of every `byCurrency[*].converted`, in the resolved base currency.
* `byCurrency` — per-original-currency breakdown with the rate that was applied. `original` is the raw sum; `converted` is the base-currency value.
* `unconvertedCurrencies` — any free-form currency strings (e.g. `"eg pounds"`) that didn't match a known code. Their amounts are summed at rate=1; surface this list in your UI so the user knows the total under-represents reality.

### What "today's spot rate" means

* Rates are EUR-base, refreshed daily from ECB.
* All conversions use the same snapshot for the whole request, so two reads at the same moment return the same total.
* Historical row-date rates are not yet applied — a row from six months ago is converted at today's rate. This is acceptable for live P\&L; historical accounting exports should be computed at the time of export and stored separately.

## Currency in API payloads

Operational endpoints expect and return `currency` as an ISO 4217 code (`USD`, `EUR`, `EGP`, `GBP`, …). Free-form strings will round-trip but won't participate in aggregation correctly — always pass canonical codes when creating financial rows via the API.

## See also

* [Subscription tiers](/concepts/tier-ladder) — what billing currency applies to
* [Currency conversion guide](/guides/currency) — practical usage in financial endpoints
