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

# ECB FX Rates Sync

This guide describes how CONA fetches daily FX rates from the ECB and how they are used in DATEV export.

## Source

* API: ECB Data Portal
* Endpoint pattern: `https://data-api.ecb.europa.eu/service/data/EXR/D..EUR.SP00.A?startPeriod=YYYY-MM-DD&endPeriod=YYYY-MM-DD&detail=dataonly&format=jsondata`
* Reference: ECB API docs

## Storage

* Table: `exchange_rates`
* Fields:
  * `base_currency`: `EUR`
  * `quote_currency`: target currency (e.g., `USD`)
  * `rate`: quote per 1 EUR
  * `start_date` (UTC 00:00:00.000)
  * `end_date` (UTC 23:59:59.999)
  * `source`: `ECB`
  * `raw`: minimal JSON fragment with series/observation ids (for traceability)
* Uniqueness: `(base_currency, quote_currency, start_date)`

## Sync

* Core function: `syncEcbFxRates({ date? })`
* Temporal activity: `syncEcbFxRatesActivity`
* Workflows:
  * `dailyFxSyncWorkflow({ dateIso? })` (one-shot)
  * `fxDailySchedulerWorkflow()` (simple daily loop; prefer Temporal Schedules in prod)
* Task queue: `FX_GLOBAL_TASK_QUEUE`

## Consumption

* Helper: `getFxRateForDate({ baseCurrency, quoteCurrency, at })`
* DATEV export: when `WKZ Umsatz` differs from export header WKZ, `Kurs` is populated using FX rate for document date (UTC). Kurs is formatted with comma and 4 decimals.

## Error handling

* Sync returns `ActionResponse`; Temporal activity throws on failure.
* If no rate is available for the exact day, `getFxRateForDate` selects the latest available rate on or before the date; for cross pairs, triangulates via EUR.
* Network/structure errors are logged and surfaced via `error`.

## Notes

* All dates are handled in UTC.
* Use JSON format from the ECB (`format=jsondata`).
