# Event Metadata File — Format Specification

The **event metadata file** is a single JSON document describing every event type your platform sends to OnAim: fields, data types, known value sets, and (optionally) **computed-field rules**. OnAim imports it to generate the inputs its Admin Panel uses for building promotion rules — dropdowns, filters, aggregation targets.

- Deliver it to your OnAim contact (OnAim imports it via its Admin Panel).
- **Re-imports are idempotent** — rules and definitions are upserted, so you can iterate and re-deliver.
- Validate against [`schemas/event-metadata.schema.json`](schemas/event-metadata.schema.json).
- Working examples: [`examples/example-events.json`](examples/example-events.json), [`examples/example-events.withRules.json`](examples/example-events.withRules.json).

## Top-level structure

```json
{
  "events":         [ ... ],   // required: one entry per event type
  "values":         [ ... ],   // optional: known value sets for dropdowns
  "computedFields": [ ... ]    // optional: global rules (see Computed fields)
}
```

## `events[]`

One entry per `eventType` you send (Task 1 payloads):

```json
{
  "code": "Bet",              // must exactly match the eventType you send
  "label": "Bet Placed",      // display name in the Admin Panel
  "fields": [
    { "code": "amount",   "label": "Bet Amount", "type": "decimal", "isAggregateable": true },
    { "code": "currency", "label": "Currency",   "type": "string",  "isAggregateable": false }
  ],
  "computedFields": [ ... ]   // optional: rules scoped to this event
}
```

### `fields[]`

| Property | Required | Meaning |
|---|---|---|
| `code` | yes | **Exactly** the JSON key as it appears in your event payloads (case-sensitive). |
| `label` | yes | Human-readable name shown in the Admin Panel. |
| `type` | yes | One of `string`, `int`, `decimal`, `dateTime`, `stringArray`, `intArray`. |
| `isAggregateable` | yes | `true` only for numeric fields that promotion rules may aggregate (sum, count thresholds) — amounts, values. `false` for everything else. |

Rules:

- Cover **every** field you send on that event. Undeclared fields are still ingested but can't be used in Admin rule-building.
- If a computed rule produces a new field (e.g. `usdAmount`, `gameType`), **declare the output field in `fields[]` too** so the Admin Panel can use it — see the with-rules example.

## `values[]`

Declares known value sets for enumerable fields; the Admin Panel renders them as dropdowns:

```json
{
  "eventCode": "Bet",
  "fieldCode": "transaction_status",
  "stringValues": [
    { "code": "success", "label": "Success" },
    { "code": "failed",  "label": "Failed" }
  ]
}
```

- Use `stringValues` for `string` fields, `intValues` for `int` fields (int codes are still written as strings: `{ "code": "1", "label": "Web" }`).
- `code` = the raw value as sent on events; `label` = what admins see.

## Computed fields (rules)

Computed-field rules derive **new fields** on your events inside OnAim, so promotion rules can target clean, normalized values even when your raw events don't carry them. Rules can be declared:

- **per event** — inside an event's `computedFields` (applies to that event only), or
- **top level** — applies to all events, optionally restricted with `"eventTypes": ["Bet", "Spin"]`.

Two rule types exist:

### `Lookup` — classify by mapping table

Derives a field from a key built out of one or more source fields. Typical use: derive `gameType` (`slot` / `crash` / …) from `game_code` + `vendor_code`.

```json
{
  "name": "Bet game type",
  "outputField": "gameType",
  "type": "Lookup",
  "sourceFields": ["game_code", "vendor_code"],
  "keySeparator": "|",
  "overwriteExisting": false
}
```

| Property | Required | Meaning |
|---|---|---|
| `outputField` | yes | Field written onto the event (declare it in `fields[]` too). |
| `type` | yes | `"Lookup"` |
| `sourceFields` | yes | Ordered fields composing the lookup key (`game_code|vendor_code`). |
| `keySeparator` | no | Default `"|"`. |
| `overwriteExisting` | no | Default `false` — skip if the event already carries the field. |
| `name` | no | Display name for the rule. |

The key→value **mapping table itself lives in OnAim's Admin Panel** and can be updated by OnAim admins at any time — no client-side change needed when new games/vendors appear.

### `CurrencyConversion` — normalized amounts

Derives a converted amount using OnAim's maintained FX rates (USD-based, refreshed automatically):

```json
{
  "name": "Bet amount in USD",
  "outputField": "usdAmount",
  "type": "CurrencyConversion",
  "amountField": "amount",
  "currencyField": "currency",
  "targetCurrency": "USD",
  "roundingDecimals": 2
}
```

| Property | Required | Meaning |
|---|---|---|
| `outputField` | yes | e.g. `usdAmount`, `eurAmount` (declare in `fields[]`, `isAggregateable: true`). |
| `type` | yes | `"CurrencyConversion"` |
| `amountField` | yes | Numeric source field on the event. |
| `currencyField` | yes | Field carrying the **source** currency code — the event must actually send it. |
| `targetCurrency` | yes | Output currency, e.g. `"USD"`, `"EUR"`. |
| `roundingDecimals` | no | Default `2`. |
| `name` | no | Display name for the rule. |

Notes:

- Supported source/target currencies: **USD, EUR, GBP, JPY, CAD, AUD, CHF** (others on request).
- If an event arrives with an unsupported or missing currency, the converted field is skipped — the event itself is still processed.
- Common pitfall: declaring a `CurrencyConversion` rule for events that don't carry a currency field. Add the currency field to the event payload (and to `fields[]`) first.

## Authoring checklist

- [ ] Every `eventType` sent → an `events[]` entry; every payload key → a `fields[]` entry with exact `code` match.
- [ ] Numeric aggregation targets marked `isAggregateable: true`.
- [ ] Enumerable fields covered in `values[]`.
- [ ] Monetary events: currency field present + `CurrencyConversion` rule for at least `usdAmount`.
- [ ] Game events without a clean type field: `Lookup` rule from `game_code`/`vendor_code` (or equivalents).
- [ ] Every computed `outputField` also declared in `fields[]`.
- [ ] File validates against `schemas/event-metadata.schema.json`.
