Overview

Every commission line moves through the same pipeline regardless of how it arrived:

Statement Import → Raw lines (normalized) → Reconciliation → Commission Event → Settlement

An import (a CSV upload or an API pull) creates one Statement Import covering a supply partner and a date range. Each row in the source file/response becomes one Raw Statement Line, normalized to a common shape. Reconciliation then tries to attribute each line to a demand-side organisation/container and compute its commission split — lines it can't confidently attribute are flagged as anomalies instead of silently guessing.

Import statusMeaning
pendingReceived, not yet processed
ingestingWorker is parsing the file / API response
ingestedLines extracted, not yet reconciled
reconcilingMatching against demand partners in progress
reconciledAll lines matched (or flagged as anomalies)
failedHard error during processing — check the import's error message
cancelledManually cancelled by an ops user

Importing data

There are two ways to get commission data in, and every supply partner uses exactly one depending on its connector type.

A. CSV / Excel upload

On the Imports page, click Upload Statement, pick the supply partner, set the period the file covers, and drop a .csv or .xlsx file (max 50MB). The file is parsed using that partner's configured field mapping — a dictionary of raw column name → normalized field set up when the partner's connector was configured. Supported normalized fields:

Normalized fieldRequired?Notes
transaction_dateYesAccepts YYYY-MM-DD, DD/MM/YYYY, MM/DD/YYYY, DD-MM-YYYY, or either of those with a THH:MM:SS/ HH:MM:SS time suffix
click_dateNoSame accepted formats as transaction_date
external_transaction_idRecommendedMissing it is flagged as an anomaly — it's also half of the idempotency key, so duplicate-upload protection is weaker without it
external_order_idNoThe merchant/order reference, if the network provides one
gross_amountYesDecimal string, e.g. "12.50" — never pre-multiplied into minor units
commission_amountYesDecimal string, same rule as gross_amount
currencyYesISO 4217 code (EUR, USD, …)
container_idYes*The affiliate-network identifier that maps to a demand partner. *Or derived from a combined sub-id column — see below
tracking_org_idNoSecondary attribution field, or derived from the same combined sub-id column
merchant_nameNoAdvertiser / program display name
product_categoryNoFree text
statusNoWhatever status string the source uses (approved/pending/declined/…) — passed through as-is

Combined sub-id columns: some networks put both the container and tracking-org reference in a single column (e.g. "container123|org456"). Set sub_id_separator (default |), container_index and org_index in that partner's connector config instead of mapping separate columns.

B. API pull

Supply partners with an API-type connector (Awin, Impact.com, Commission Junction, TravelPayouts, Tapfiliate, Rakuten, or a custom REST API) fetch directly — no file involved. Credentials must be saved first via Configure API on the Supply Partners page, then either trigger a one-off pull with Fetch Now (pick a date range) or let the scheduled daily job handle it automatically. Use Test Connection after saving credentials to confirm they're valid before the first real fetch.

ConnectorRequired credentials
Awin APIPublisher ID, API Key
Impact.com APIAccount SID, Auth Token (HTTP Basic)
Commission Junction APIPersonal Access Token, Publisher CID — optionally Advertiser IDs to scope a per-merchant partner to one advertiser instead of the whole account feed
TravelPayouts APIAPI Token (sent as X-Access-Token)
Tapfiliate APIAPI Key
Rakuten APIAPI Token, Publisher ID
Custom APIBase URL, API Key

Fields marked as secret in the Configure API modal (tokens/keys) are stored write-only — the form shows a placeholder, not the saved value, and leaving it blank on save keeps the existing credential.

Defining new supply partners

On Supply Partners, click + New Partner and fill in:

FieldRequired?Notes
NameYesDisplay name shown throughout the UI
SlugYesUnique, stable identifier — used in idempotency keys, so avoid changing it once imports exist
Legal NameNoUsed on invoices/credit notes if different from Name
Affiliate NetworkNoInformational grouping (Awin, Impact, Commission Junction, …) — doesn't affect processing
Connector TypeYesDetermines whether this partner imports via CSV upload or API pull, and which fields Configure API asks for
CurrencyYesDefault currency assumed when a file/response doesn't specify one
Country CodeYesISO 2-letter code, used for VAT treatment
Payment Terms (days)NoDefaults to 30 — informational, used for AR aging

Picking an API connector type immediately opens Configure API so credentials can be entered right away. For a CSV connector, set up the field mapping via PUT /api/v1/admin/supply-partners/{id}/connector-config (see API Docs) before the first upload — the mapping isn't editable from this UI yet.

Assigning tracking hashes

A tracking hash is whatever per-container tracking value a connector carries through from the affiliate link/widget — the platform's own MD5-style hash, or a network-specific equivalent (CJ's websiteId, Impact's SubId1, TravelPayouts' sub_id). Every connector that supports one resolves it the same way, in this order:

  1. Tracking hash cache — a mirror of the platform's own product_tracking_hashes table, kept fresh automatically. This is the primary source and always wins when present.
  2. Manual assignment — hashes ops has assigned by hand in this UI. Used only when the cache has no entry.
  3. Default fallback — unattributed lines fall back to the Ancillarate-Playground org/container so they're never silently dropped, and get flagged unresolved_hash instead.

The Tracking Hashes page lists every hash currently falling through to the fallback — supply partner, how many lines it's affected, when it was first seen, and an example amount. Click Assign, pick the organisation (optionally a product ID), and confirm — this resolves every current and future line carrying that hash automatically, not just the ones already imported. The same assignment flow is also reachable per-line from the Import Issues page.

Resolving import issues

After ingestion, reconciliation flags any line it can't confidently process instead of guessing. Flagged lines show up on that import's Import Issues page (reachable from the Imports list) with one or more of these anomaly types:

AnomalyMeaningHow to resolve
missing_mapping No demand partner found for this line's container ID Click Assign Partner and pick the correct organisation — resolves just this line
unresolved_hash The line's tracking hash isn't in the cache or a manual assignment Click Assign Hash — see Assigning tracking hashes above; resolves this and every future line with the same hash
duplicate A line with the same idempotency key (supply partner + external transaction ID + date) already exists Informational — the line was already imported once, no action needed
amount_outlier Commission amount is unusually large relative to this partner's history Review manually before approving the settlement that includes it — could be correct, could be a source-file error
negative_amount Negative commission — typically a reversal or clawback Expected behavior for corrections; verify it nets against the original line
unknown_currency Currency code isn't a recognised ISO 4217 code Check the source file's currency column, or the connector's default_currency config
missing_transaction_id No external transaction ID on the line Check the source file / field mapping — without it, duplicate-import protection is weaker for that line

Data structure reference

Whatever the source (CSV or API), every line is normalized to the same shape before reconciliation ever sees it. If you're setting up a new CSV field mapping or debugging why a connector's data isn't matching, this is the target shape:

FieldTypeNotes
idempotency_keystringDeterministic: sha256(supply_partner_id + ":" + external_transaction_id + ":" + transaction_date) — same inputs always produce the same key, which is what makes re-uploading the same file a no-op instead of double-counting
raw_container_id / raw_tracking_org_idstring | nullMatched against demand partners during reconciliation — a miss here is a missing_mapping anomaly
gross_amount_minor / commission_amount_minorintegerAlways minor units (pence/cents), never a float — a source value of "12.50" becomes 1250
currencystringISO 4217. Zero-decimal currencies (JPY, KRW, VND) and three-decimal currencies (KWD, BHD, OMR) are converted correctly, not just ×100
transaction_datedateRequired — the booking/action date, used for period grouping and FX rate lookup
tracking_hash / product_id / experiment_id / variant_keystring | nullPopulated by connectors that resolve a tracking hash — see Assigning tracking hashes
is_default_attributionbooleantrue when a line fell through to the default org/container rather than a real match
statusstring | nullPassed through from the source as-is (network status vocabularies differ — not normalized to a fixed set)