Returning.AIDevelopers
v1

Guides / Broker Integrations

.md

Trading volume and rewards

Build trading rewards from immutable source facts, a stable customer mapping, and an approved calculation. This page uses synthetic data to show one trader with two accounts, separate FX and metals units, and a separately defined comparable USD turnover input.

Trading facts to a visible reward

The aggregate is formed before additive delivery, and each asynchronous checkpoint is verified separately.

  1. Read complete history for the approved UTC window and retain account, symbol, volume, event time, and source record ID.

  2. Map accounts to one customer

    Broker identity owner

    Resolve ACCOUNT_2001 and ACCOUNT_2002 to canonical CUSTOMER_1001 without using an email as the dedupe boundary.

  3. Create one delivery row with separate FX and metals totals, comparable turnover, source lineage, and a versioned aggregate ID.

  4. Send the approved aggregate using the configured SQS, Event Ingest, file, or other provisioned path.

  5. Process the configured reward

    Returning.AI workflow owner

    Check eligibility and apply the approved rule once. Do not credit both raw facts and their derived aggregate.

  6. Read back and refresh

    Returning.AI and portal owners

    Check workflow and user-update results, read the authoritative value, then refresh the widget for the same canonical user.

Canonical user and account lineage

A trading account is not the loyalty user. Use a durable account key made from platform, server, and account login, then map each account to the canonical broker customer and its enrolled Returning.AI user.CUSTOMER_1001 is the broker's external identifier, not the platform user ID returned by enrollment. Keep both IDs and the mapping version and effective dates when ownership can change. See the enrollment guide.

Canonical customerTrading account keyAccount sourceLineage to retain
CUSTOMER_1001mt5 / broker-live-1 / ACCOUNT_2001Broker account mapMapping version, account status, source event IDs
mt5 / broker-live-1 / ACCOUNT_2002Broker account mapMapping version, account status, source event IDs

Hold an unmapped account without awarding points. Resolve the mapping and replay through the approved process. Do not merge users because an email or display name happens to match.

Processing model

This worked example chooses raw close-deal activity as the source model and a user/window aggregate as the delivery model. The collector first stores the raw facts, then groups all eligible rows for one canonical user and UTC window before sending one aggregate row. A field such asaggregate_id keeps the derived row tied to its source set.

Choose one credit boundary

Do not send raw deals and the derived aggregate into the same additive reward workflow unless one path is explicitly non-crediting lineage. A source fact and its aggregate are two representations of one activity, not two rewards.

Worked input: two accounts and two asset classes

Every row below is individual closed-deal activity in the UTC window from 2026-09-07T00:00:00Z inclusive to2026-09-08T00:00:00Z exclusive. Adjacent windows share no boundary event. The USD amount is a separately defined comparable turnover input for this example. It is not a conversion of the FX and metals lot columns, and it is not used by the illustrative lot-rate calculation below.

Source event IDAccountSymbol and classRaw close activityClose time (UTC)Comparable turnover inputEligible?
deal-2001-fx-001ACCOUNT_2001EURUSD.a / FX1.20 standard lots2026-09-07 10:15100,000 USDYes, closed and mapped
deal-2002-fx-002ACCOUNT_2002EURUSD.a / FX0.80 standard lots2026-09-07 11:2075,000 USDYes, closed and mapped
deal-2001-metals-003ACCOUNT_2001XAUUSD.a / metals0.50 metal lots2026-09-07 12:0575,000 USDYes, closed and mapped
Total separately defined comparable turnover250,000 USDComparable input only

The two FX rows total 2.00 standard lots. The metals row totals 0.50 metal lots. Do not report one combined lot total: the units and contract rules are different. The USD turnover total is valid here only because it was separately defined as a comparable USD measure and supplied for every included row. Eachsource_event_id is the stable replay identity for its raw row; the aggregate has its own stable aggregate_id.

One canonical-user and window aggregate

Retain the full account list, class totals, source IDs, and aggregate version in one canonical-user/window row. The exact field names below are a synthetic mapping for the example. The configured workflow decides the actual payload contract.

customer-window-aggregate.json
{
  "aggregate_id": "agg:CUSTOMER_1001:2026-09-07:v1",
  "canonical_customer_id": "CUSTOMER_1001",
  "window_start": "2026-09-07T00:00:00Z",
  "window_end": "2026-09-08T00:00:00Z",
  "accounts": [
    { "platform": "mt5", "server": "broker-live-1", "account_login": "ACCOUNT_2001" },
    { "platform": "mt5", "server": "broker-live-1", "account_login": "ACCOUNT_2002" }
  ],
  "volumes": [
    {
      "asset_class": "fx",
      "normalized_volume": 2.0,
      "volume_unit": "standard_lot",
      "source_event_ids": ["deal-2001-fx-001", "deal-2002-fx-002"]
    },
    {
      "asset_class": "metals",
      "normalized_volume": 0.5,
      "volume_unit": "metal_lot",
      "source_event_ids": ["deal-2001-metals-003"]
    }
  ],
  "comparable_turnover_usd": 250000,
  "aggregation_version": "trading-aggregate-v1"
}
Asset classAccount contributionsAggregateSource IDs retained
FXACCOUNT_2001: 1.20 + ACCOUNT_2002: 0.80 standard lots2.00 standard lotsdeal-2001-fx-001, deal-2002-fx-002
MetalsACCOUNT_2001: 0.50 metal lots0.50 metal lotsdeal-2001-metals-003
Comparable turnover100,000 + 75,000 + 75,000 USD250,000 USDSame three source rows

Illustrative points calculation

Assume the approved example configuration says 10 points per FX standard lot and 20 points per metal lot. Round half-up to the nearest whole point after each class calculation. These rates are synthetic and do not claim a Returning.AI or client default.

ClassVolumeIllustrative rateCalculationClass points
FX2.00 standard lots10 points / lot2.00 × 1020
Metals0.50 metal lots20 points / lot0.50 × 2010
Total points20 + 10 = 30

Trading volume is a measurement. Points are an illustrative reward output. Coins, XP, points, and a custom volume field are separate destinations; a configured workflow must say which one is written. The 250,000 USD turnover input is also separate and must not be silently converted into points or combined with lot totals.

Eligibility, launch cutoff, and history

Use the close time and the approved UTC launch cutoff, not the time a poller happened to see a row. In this synthetic example the cutoff is2026-09-07T00:00:00Z; the integration owner must replace it with the approved value for the real campaign.

CaseSafe handling before reward deliveryOwner to resolve
First-ever tradeCheck complete accessible history. The first row observed after the extractor starts is not proof of the trader's first trade.Broker data owner and reward owner
Before enrollmentExclude or hold unless the approved rule grants retroactive credit. Define whether eligibility starts at broker registration or Returning.AI enrollment; do not infer one from the other.Identity and campaign owners
Before launch cutoffQuarantine or exclude with a recorded reason unless the approved campaign explicitly backfills it.Campaign owner
Unknown symbolHold without reward until the asset-class mapping and conversion are approved.Broker and reward owners
Unmapped accountHold without reward. Do not guess the canonical customer or use an email merge.Identity owner
Late dataApply the documented late-window and correction policy. Do not assume automatic retroactive credit.Data and reward owners
Open positionKeep it out of a closed-deal reward model unless the approved rule explicitly includes open exposure.Reward owner

Snapshot or delta

Decide whether the delivery represents a complete snapshot or a new delta before choosing retry behavior. Do not alternate between them for the same aggregate identity.

ModelMeaningReplay and correction concern
Window snapshotThe row contains the complete approved value for one customer and window.Requires a configured overwrite or reconciliation path. Do not assume an additive workflow replaces it safely.
Window deltaThe row contains new contribution since the previous checkpoint.Needs a stable aggregate or source identity before retry; replay can add the points twice.

Partial success, corrections, and readback

  1. Record the baseline authoritative value, aggregate ID, source count, and expected class totals before delivery.
  2. Check transport acceptance, Event Ingest persistence, and workflow execution as separate checkpoints. A queue acknowledgement is not a reward result.
  3. If a queued user update has per-row results, preserve successful users and retry only failed users through the approved path. Do not replay the whole additive batch to repair one failure.
  4. Read back the authoritative field, points, coins, or ledger value using the operation and permission supplied for the environment. Then compare it with the expected aggregate and source lineage.
  5. Replay the same aggregate identity and verify that it does not add a second reward when the configured contract promises that behavior.
  6. For a changed fact, pause and use the approved correction or compensation flow. A new batch or aggregate ID alone is not a safe financial correction.
  7. Refresh the widget for CUSTOMER_1001 only after the saved state is authoritative. A stale widget does not prove the workflow failed.

Next step

Use the SQS data feed guide to package bounded JSON messages or review a provisioned file contract. Use the workflow webhook guidefor registration, KYC, and other lifecycle events. Once enrollment and readback are complete, open the widget quickstart.

For onboarding progress, connect custom fields and milestones. Before enabling real rewards, complete the launch checklist.