Skip to main content
POST
Save Transactions
Stores one or more transactions for AML transaction-risk monitoring. Send a JSON array of records, or an object with a transactions array. Ingest is idempotent on client_txn_id: re-posting the same id never creates a second record. It does, however, replace that record rather than patching it — any field you omit is cleared, not carried over from the previous version. Always send the complete transaction on a re-post, not just the fields that changed. Nothing is lost: the previous values are preserved in the record’s revision history, and a revision entry is appended only when a field actually changed. Subjects are auto-provisioned and enrolled in monitoring on first sight — you do not need to register a customer before sending their transactions. A counterparty is stored as a data field for rule evaluation and is never enrolled as a monitored user.
Field names are documented in snake_case, and responses always use snake_case. Requests also accept camelCase (client_txn_id or clientTxnId), so either convention works.The one exception is metadata: its keys are yours and are stored and returned exactly as you send them, never case-converted. { "someKey": 1 } stays someKey.
Always inspect the response body. A well-formed request always returns 200, even when individual records were rejected or stored with warnings. A record can be stored and still be unmonitored or unscreenable — for example when your organization has no running transaction-risk bot, or when a subject has no name. A client that checks only the HTTP status will silently under-detect.

Request

Limits

Whichever limit is reached first applies. Over 500 records returns 400 with code BATCH_TOO_LARGE; over 5 MB returns 413. In both cases split the batch into smaller requests.

Headers

Body parameters

Transaction record

We perform no FX conversion. When a transaction’s currency already matches your organization’s base currency, normalized_amount is inferred. Otherwise supply it yourself — if you don’t, the record is still stored but amount-threshold rules will skip it and you receive a NORMALIZED_AMOUNT_MISSING warning.
Currency codes are ISO 4217 and country codes ISO 3166-1 alpha-2. A well-formed but unrecognized code is rejected rather than stored, since bad reference data produces false alerts later.

geography fields

ip_address and ip_country are optional and drive no detection. They are retained as context for risk adjudication and analyst review — no rule reads either one. In particular, the high-risk-geography rule matches on origin_country, destination_country and the counterparty’s country only: IP geolocation is routinely a VPN or proxy exit, so treating it as a jurisdiction signal would manufacture false alerts.ip_address must be a valid IPv4 or IPv6 address (203.0.113.42, 2001:db8::1). A malformed value rejects that record only, with FIELD_INVALID on geography.ip_address — it never fails the batch.

Example request

Response

200 — Success

Each entry in results:

Warning codes

A warning means the record was stored but something needs your attention. Request-scope warnings appear on every stored record. Subject-scope warnings appear only on the records belonging to the affected subject, so you can find the specific customer to fix.

Error responses

429 — Quota exceeded

Quota is reserved atomically before anything is written, so a 429 always means nothing landed. The response tells you exactly where you stand:
Retry after resets_at, or contact support to raise your monthly quota.

Sandbox

With a sandbox API key this endpoint performs full validation and returns realistic per-record results, but stores nothing — no transactions, no subject provisioning, and no quota consumption. Use it to verify your integration end to end before sending live data.

Coming next

Endpoints to read stored transactions and retrieve monitoring alerts are in development.