Cost Ingestion: Connector Setup

August 31, 2026 · View on GitHub

Cost ingestion learns each connector's actual per-transaction fee (percentage + flat component) from real settlement reports and invoices, at a fine-grained cluster level (connector × card network × card variant × funding × issuer country × currency × interchange category). That fitted cost model is what multi-objective routing ranks gateways on.

Before any report or invoice can be ingested, register the connector account's settlement credentials.

Data Sources

Settlement data reaches Decision Engine through three paths, all feeding the same cost_ingestion pipeline:

SourceHow it worksDocs
Webhook pushThe connector calls Decision Engine when a report is ready. Verified via the stored webhook_secret, then queued.This page
Scheduled pollA background job polls the connector's reporting API for ready reports. No merchant action needed once credentials are set.This page
Manual uploadUpload a report or invoice file directly — useful before webhooks are wired, for backfills, or testing.Uploads

Register Connector Credentials

curl --location "$BASE_URL/merchant-account/merchant_demo/connectors/adyen/credentials" \
  --header "$AUTH_HEADER" \
  --header "Content-Type: application/json" \
  --data '{
    "account": "YOUR_ADYEN_MERCHANT_ACCOUNT_CODE",
    "webhook_secret": "whsec_...",
    "download_auth": "report_user:report_password"
  }'
  • account — the connector-side account (e.g. Adyen's merchantAccountCode).
  • webhook_secret — used to verify inbound webhook signatures for this account.
  • download_auth — credential used to authenticate report downloads for the scheduled poller. Either "user:password" for Basic auth, or a bare API key (sent as X-API-Key).

Response:

{
  "merchant_id": "merchant_demo",
  "connector": "adyen",
  "account": "YOUR_ADYEN_MERCHANT_ACCOUNT_CODE",
  "status": "saved"
}

Secrets are encrypted at rest and never returned by the API — subsequent reads only return masked hints.

List Configured Connectors

curl "$BASE_URL/merchant-account/merchant_demo/connectors" \
  --header "$AUTH_HEADER"
[
  {
    "connector": "adyen",
    "account": "YOUR_ADYEN_MERCHANT_ACCOUNT_CODE",
    "webhook_secret_hint": "••••af31",
    "download_auth_hint": "report_user:••••"
  }
]

Remove Credentials

curl --request DELETE \
  "$BASE_URL/merchant-account/merchant_demo/connectors/adyen/credentials/YOUR_ADYEN_MERCHANT_ACCOUNT_CODE" \
  --header "$AUTH_HEADER"

Returns 204 No Content. Deleting a source that isn't configured also returns success (idempotent).

Settlement Webhook (Connector → Decision Engine)

Once credentials are registered, point the connector's settlement-report notification at:

POST /webhooks/settlement/:merchant_id/:connector

This route is public (no AUTH_HEADER) — the connector authenticates itself via its own signature, which Decision Engine verifies against the webhook_secret stored for that (merchant_id, connector, account) triple. Adyen is the first supported connector (:connector = adyen).

curl --location "$BASE_URL/webhooks/settlement/merchant_demo/adyen" \
  --header "Content-Type: application/json" \
  --data @adyen-settlement-notification.json

The handler ACKs immediately and enqueues the report for background processing — download, parse, and re-fit all happen asynchronously in the ingest worker, so the connector always gets a fast response. A bad signature returns 401; an unrecognized connector or malformed payload returns 400.

The URL carries your `merchant_id` because a connector's notification names only its own account (for Adyen, the `merchantAccountCode`) — never your Decision Engine merchant. Registering another merchant's id gets a caller nowhere without that merchant's signing secret, since the path only selects which stored `webhook_secret` the signature is checked against.

Sharing one connector account between two merchants

Two Decision Engine merchants can ingest from the same connector account — a shared platform account, for example. Register a separate webhook endpoint at the connector for each merchant, pointing at that merchant's own URL:

POST /webhooks/settlement/merchant_a/adyen
POST /webhooks/settlement/merchant_b/adyen

Each merchant stores their own credentials for the shared account, so the endpoints may use different HMAC keys and different report-download users (the same key on both also works). The connector delivers its report-ready event to both endpoints and each merchant gets their own ingestion job.

One endpoint cannot serve two merchants: it points at a single URL naming a single merchant, so only that merchant receives deliveries. The other will show its source as configured with no ingested data.

Notes

  • Manual and webhook/poll-based ingestions share the same pipeline and history — see Uploads for the manual path and ingestion history.
  • Once enough settlement data has been fitted, check Cost Coverage to see what share of volume has a trustworthy cost model.