> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Transaction Response Schema

> Annotated transaction response: score, rule runs, parties with device and IP enrichment, payment methods, crypto screening, travel rule. Pay-per-call $0.02.

This page documents the full payload returned by `POST /v3/transactions/` and `GET /v3/transactions/{transaction_id}/`. Both endpoints return the same `TransactionDetail` object; the [API reference](/management-api/transactions/get) carries the field-by-field schema and this page walks through it.

## Top-level structure

```json theme={null}
{
  "uuid": "abcdef12-3456-4890-abcd-ef1234567890",
  "environment": "live",
  "transaction_number": 4123,
  "txn_id": "tx-0001",
  "txn_date": "2026-04-16T12:00:00Z",
  "zone_id": "Europe/Madrid",
  "transaction_type": "finance",
  "action_type": "withdrawal",
  "direction": "OUTBOUND",
  "status": "IN_REVIEW",
  "source": "LIVE",
  "amount": "12500",
  "currency": "EUR",
  "currency_type": "fiat",
  "amount_in_default_currency": null,
  "default_currency_code": null,
  "preferred_currency_amount": "13520.75",
  "preferred_currency_code": "USD",
  "payment_details": "Withdrawal to bank account",
  "payment_txn_id": null,
  "score": 65,
  "severity": "MEDIUM",
  "decision_reason_code": "rule_score_threshold",
  "decision_reason_label": "Score above review threshold",
  "vendor_data": "user-42",
  "metadata": { "subject": { ... }, "counterparty": { ... } },
  "props": { "order_id": "ORD-7891" },
  "tags": [ ... ],
  "parties": [ ... ],
  "payment_methods": [ ... ],
  "documents": [ ... ],
  "activities": [ ... ],
  "alerts": [ ... ],
  "rule_runs": [ ... ],
  "provider_results": [ ... ],
  "travel_rule": { ... } | null,
  "network_snapshot": { ... } | null,
  "remediation": { ... } | null,
  "action_required": { ... } | null,
  "cost_breakdown": { ... } | null
}
```

Two identifiers describe the same transaction. `uuid` is the Didit-stable identifier and is what `GET /v3/transactions/{transaction_id}/` expects in its path; `txn_id` is the `transaction_id` you supplied at create time. `transaction_number` is the application-scoped sequential number the console shows.

The subject and counterparty you submitted do not come back as top-level keys. They are the entries of the `parties` array, distinguished by `role`, and `vendor_data` at the top level is a convenience copy of the applicant's `vendor_data`.

## Key fields

### Financial fields

* `amount` / `currency` — transaction amount as submitted. `amount` is a decimal string with trailing zeros stripped (`"1500"`, `"0.5"`), with up to 18 decimal places.
* `currency_type` — `fiat` or `crypto`, as submitted in `currency_kind`; `null` when omitted.
* `amount_in_default_currency` / `default_currency_code` — the pre-converted amount you supplied on the request, echoed back; `null` when you did not send one.
* `preferred_currency_amount` / `preferred_currency_code` — `amount` converted to your application's preferred currency. `null` when no exchange rate is available for `currency` and you did not supply `amount_in_default_currency`.
* `payment_details` / `payment_txn_id` — the free-text payment reference and the external payment reference (for example a blockchain transaction hash) from the request.

### Status fields

* `status` — `APPROVED`, `IN_REVIEW`, `DECLINED`, `AWAITING_USER`. Transactions are created `APPROVED`; rules may flip them synchronously.
* `score` — integer risk score accumulated by rules. Higher is riskier.
* `severity` — `UNKNOWN`, `LOW`, `MEDIUM`, `HIGH`, `CRITICAL`, or `null` until a rule or provider sets it.
* `decision_reason_code` / `decision_reason_label` — structured + human reason for the current status.
* `environment` - `live` or `sandbox`, from the application that owns the transaction. A `sandbox` transaction is stored but never evaluated, so its empty `rule_runs` means "not evaluated" rather than "nothing matched". See [Transaction Monitoring in sandbox](/integration/sandbox-testing#transaction-monitoring-in-sandbox).
* `source` - `LIVE` for transactions submitted through the API or SDK, `IMPORTED` for transactions loaded through the console CSV import.

### Parties

Every party on the transaction is an entry in `parties`. The create endpoint records the subject as `APPLICANT` and the optional counterparty as `COUNTERPARTY`; the `role` enum also includes `REMITTER` and `BENEFICIARY`. All entries share one shape.

```json theme={null}
"parties": [
  {
    "uuid": "b1111111-2222-4333-8444-555555555555",
    "role": "APPLICANT",
    "entity_type": "individual",
    "kind": "USER",
    "vendor_data": "user-42",
    "full_name": "John Doe",
    "first_name": "John",
    "last_name": "Doe",
    "country_code": "USA",
    "dob": "1990-01-01",
    "address": { "line_1": "...", "city": "...", "country": "USA" },
    "institution_info": { "name": "...", "country_code": "..." },
    "device": {
      "fingerprint": "...",
      "persistent_device_id": "...",
      "user_agent": "...",
      "browser_family": "Chrome",
      "browser_version": "131.0",
      "platform": "web",
      "os_family": "Windows",
      "os_version": "10.0",
      "accept_language": "en-US,en;q=0.9",
      "session_id": "...",
      "session_age_ms": 84000,
      "metadata": {
        "accept_language": "en-US,en;q=0.9",
        "session_id": "...",
        "session_age_ms": 84000
      },
      "network_context": {
        "ip_address": "203.0.113.5",
        "ip_country": "United States",
        "ip_country_code": "US",
        "ip_state": "California",
        "ip_city": "San Francisco",
        "latitude": 37.7749,
        "longitude": -122.4194,
        "isp": "Example ISP",
        "organization": "Example Org",
        "is_vpn_or_tor": false,
        "is_data_center": false,
        "time_zone": "America/Los_Angeles",
        "time_zone_offset": "-0700",
        "asn_number": 64496,
        "asn_organization": "Example ISP",
        "connection_type": "isp",
        "carrier": null,
        "proxy_type": null
      }
    },
    "external_party_snapshot": null
  },
  {
    "uuid": "c2222222-3333-4444-8555-666666666666",
    "role": "COUNTERPARTY",
    "entity_type": "company",
    "kind": "EXTERNAL",
    "vendor_data": null,
    "full_name": "Acme Supplier",
    "first_name": null,
    "last_name": null,
    "country_code": "GBR",
    "dob": null,
    "address": {},
    "institution_info": {},
    "device": {},
    "external_party_snapshot": { "full_name": "Acme Supplier", "country": "GBR", "...": "..." }
  }
]
```

* `role` — `APPLICANT`, `COUNTERPARTY`, `REMITTER`, `BENEFICIARY`. Filter on it to find the subject.
* `entity_type` — `individual`, `company`, `external`, `unhostedWallet`, as submitted.
* `kind` — `USER` or `BUSINESS` when the party links to a Didit user or business through `vendor_data`; `EXTERNAL` otherwise.
* `country_code` / `dob` — from the submitted `address.country` and `date_of_birth`.
* `address` / `institution_info` — the objects as submitted; `{}` when omitted.
* `external_party_snapshot` — frozen copy of the party data for `EXTERNAL` parties; `null` while the party is linked to a Didit user or business.

#### `device`

`device` is the `device_context` you submitted for that party, normalized to snake\_case, plus server-side IP enrichment. It is `{}` when the request carried no device context, so always treat every key as optional.

| Key | Description |
| - | - |
| `fingerprint`, `persistent_device_id` | Device identifiers as submitted. |
| `user_agent`, `browser_family`, `browser_version`, `platform`, `os_family`, `os_version` | Browser and OS attributes as submitted. `browser_family` and `platform` are never derived from `user_agent`. |
| `accept_language`, `session_id`, `session_age_ms` | Session attributes as submitted. They are also mirrored into `device.metadata` under the same names, which is where the SDK path stores them. |
| `metadata` | Present when the request carried a `metadata` object or any of the three session attributes. |
| `network_context` | Network context, see below. Absent when no IP or network data was submitted. |

There is no separate enrichment object. When the party carried a public `network_context.ip_address`, Didit resolves it inline and writes the [enriched fields](/transaction-monitoring/ip-enrichment#enriched-fields) into the same `network_context` object, filling only the keys you did not supply. Keys the resolver returned empty are omitted, so a fully enriched `network_context` holds the four submitted keys (`ip_address`, `ip_country_code`, `latitude`, `longitude`) plus whichever of `ip_country`, `ip_state`, `ip_city`, `isp`, `organization`, `is_vpn_or_tor`, `is_data_center`, `time_zone`, `time_zone_offset`, `asn_number`, `asn_organization`, `connection_type`, `carrier` and `proxy_type` were resolved. `is_vpn_or_tor` and `is_data_center` are always present after a successful resolution.

Enrichment is skipped, and `network_context` is returned exactly as submitted, when the IP is missing or non-routable, when the application is in sandbox, or when resolution failed. `ip_country_code` is an ISO 3166-1 alpha-2 code when Didit resolved it and whatever you submitted otherwise; rule conditions normalize both forms before comparing.

### Payment methods

```json theme={null}
"payment_methods": [
  {
    "uuid": "...",
    "payment_method_type": "bank_account",
    "label": null,
    "fingerprint": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
    "account_id": "DE89370400440532013000",
    "issuing_country": "DE",
    "owner_kind": "USER",
    "vendor_data": "user-42",
    "owner_name": "John Doe",
    "institution_info": {},
    "details": { "method_type": "bank_account", "account_id": "DE89370400440532013000", "issuing_country": "DE" },
    "external_owner_snapshot": null,
    "role": "SOURCE"
  }
]
```

* `role` — `SOURCE`, `DESTINATION`, `FUNDING`, `BENEFICIARY`. The create endpoint assigns `SOURCE` / `DESTINATION` from `direction`: on an outbound transaction the subject's method is the `SOURCE` and the counterparty's the `DESTINATION`; inbound is the reverse.
* `payment_method_type` — `bank_card`, `bank_account`, `e_wallet`, `crypto_wallet`, `unhosted_wallet`, `other`.
* `fingerprint` — SHA-256 over `type:account_id:issuing_country`, stable across transactions so you can correlate reuse of the same instrument. `null` when no `account_id` was submitted.
* `owner_kind` / `vendor_data` / `owner_name` — who owns the instrument, following the same `USER` / `BUSINESS` / `EXTERNAL` convention as parties.
* `details` — the raw `payment_method` object as submitted.

### Rule runs

```json theme={null}
"rule_runs": [
  {
    "uuid": "...",
    "rule": "f6a7b8c9-0123-4def-b012-3456789abcde",
    "rule_title": "High-value outbound",
    "rule_description": null,
    "rule_category": "finance",
    "matched": true,
    "is_test": false,
    "mode": "ACTIVE",
    "severity": "MEDIUM",
    "score_delta": 30,
    "status_target": null,
    "action_summary": "score +30",
    "metadata": {
      "scope_match": true,
      "conditions": [
        {
          "field": "amount",
          "operator": "gt",
          "expected_value": "10000",
          "current_value": "12500",
          "matched": true,
          "group_index": null,
          "group_logic": "AND",
          "field_source": null
        }
      ],
      "aggregations": []
    },
    "created_at": "2026-04-16T12:00:01Z"
  },
  {
    "uuid": "...",
    "rule": "...",
    "rule_title": "High-risk jurisdiction counterparty",
    "rule_description": null,
    "rule_category": "finance",
    "matched": true,
    "is_test": false,
    "mode": "ACTIVE",
    "severity": "HIGH",
    "score_delta": 35,
    "status_target": "IN_REVIEW",
    "action_summary": "score +35; change_status:IN_REVIEW; add_tag:high_risk_country",
    "metadata": { "scope_match": true, "conditions": [ ... ], "aggregations": [] },
    "created_at": "2026-04-16T12:00:01Z"
  }
]
```

* `rule` — UUID of the rule that ran; `rule_title`, `rule_description`, `rule_category` are copied from it.
* `matched` — a run is recorded only when the rule's conditions matched, so live evaluations always carry `matched: true`. Rules that evaluated without matching leave no entry. Demo data can include `matched: false` rows.
* `is_test` / `mode` — `true` and `TEST` when the rule ran in test mode; a test run is recorded but has no effect on `status`, `score` or `severity`.
* `score_delta` / `status_target` / `severity` — what this run contributed. `status_target` is set when a `change_status` action ran, or when the added score crossed a [threshold](/transaction-monitoring/risk-scoring).
* `action_summary` — a string summary of the actions the rule executed, joined with `; ` (`score +30`, `change_status:IN_REVIEW`, `add_tag:<name>`, `add_note`, `add_to_list`, `open_case`); `null` when the rule executed no action.
* `metadata` — the evaluation detail: `scope_match`, plus `conditions[]` and `aggregations[]`. The two lists use different value keys:
  * `conditions[]` — one entry per condition with `field`, `operator`, `expected_value`, the `current_value` that was read from the transaction, `matched`, `group_index` and `group_logic`. `field_source` is always `null` on transaction rule runs; it is only classified for [monitoring events](/transaction-monitoring/events).
  * `aggregations[]` — one entry per velocity / count / sum aggregation with `metric`, `field`, `operator`, `expected_value`, the `computed_value` that the aggregate evaluated to, `window`, `filters`, `matched` and `sample_references`. Aggregations that could only be computed asynchronously carry `computed_value: null` and `deferred: true`.

### Alerts

```json theme={null}
"alerts": [
  {
    "uuid": "...",
    "title": "High-value + high-risk jurisdiction",
    "description": null,
    "severity": "HIGH",
    "status": "OPEN",
    "source": "RULE",
    "metadata": {},
    "created_at": "2026-04-16T12:00:01Z",
    "due_at": null
  }
]
```

`status`: `OPEN`, `INVESTIGATING`, `AWAITING_USER`, `PENDING_SAR`, `SAR_FILED`, `RESOLVED`, `DISMISSED`. `source`: `RULE`, `PROVIDER`, `MANUAL`. See [Alerts](/transaction-monitoring/alerts).

### Activities

The transaction's activity log: creation, notes, manual reviews and status changes.

```json theme={null}
"activities": [
  {
    "uuid": "...",
    "activity_type": "TRANSACTION_CREATED",
    "source": "TRANSACTION",
    "status": "APPROVED",
    "title": "withdrawal",
    "description": null,
    "metadata": { "action_type": "withdrawal", "direction": "OUTBOUND", "amount": "12500", "currency": "EUR" },
    "occurred_at": "2026-04-16T12:00:00Z"
  }
]
```

Analyst notes appear here as `TRANSACTION_NOTE_ADDED` entries; there is no separate `notes` array.

### Documents

Files attached to the transaction from the console. `[]` when none.

```json theme={null}
"documents": [
  {
    "uuid": "...",
    "label": "Invoice",
    "note": null,
    "uploaded_by": "...",
    "created_at": "2026-04-16T12:05:00Z",
    "files": [
      { "uuid": "...", "file_url": "https://...", "original_filename": "invoice.pdf", "file_size": 48213 }
    ]
  }
]
```

`file_url` is a short-lived signed URL; fetch it when you need it rather than storing it.

### Provider results

External provider outputs (transaction hash screening, wallet screening, fiat monitoring, sanctions screening).

```json theme={null}
"provider_results": [
  {
    "uuid": "...",
    "result_type": "TRANSACTION_SCREENING",
    "provider": "merklescience",
    "status": "SCREENED",
    "severity": "HIGH",
    "score": 82,
    "summary": "Merkle Science risk: High (4/5). Dominant risk: stolen_funds. Driven by: 50% direct incoming exposure to Theft / Hack (Stolen Funds)",
    "payload": {
      "provider": "merklescience",
      "screening_type": "TRANSACTION_SCREENING",
      "transaction_hash": "0x...",
      "wallet_address": null,
      "blockchain": "ETH",
      "block_timestamp": "2026-04-01T00:07:11Z",
      "total_value_usd": 2942.31,
      "fee_usd": 0.09,
      "transaction_flows": [
        {
          "flow_type": "token",
          "from_address": "0x...",
          "to_address": "0x...",
          "amount": 72.83039728,
          "amount_usd": 235.97,
          "currency": "UNI",
          "token_name": "Uniswap",
          "token_address": "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984",
          "transaction_hash": "0x...",
          "block_timestamp": "2026-04-01T00:07:11Z",
          "index": 460,
          "success": true,
          "metadata": {
            "provider": "blockscout",
            "token_type": "ERC-20",
            "token_icon_url": "https://...",
            "token_reputation": "ok",
            "token_holders_count": "410093",
            "from": {
              "label": "ravaga.eth",
              "tags": [{ "name": "Beacon Depositor", "type": "generic" }]
            },
            "to": {
              "label": "AirSwap: Spender",
              "is_contract": true,
              "is_verified": true
            }
          }
        }
      ],
      "source_of_funds": [
        {
          "category": "stolen_funds",
          "entity_name": "Stolen Funds",
          "entity_type": "Theft",
          "entity_subtype": "Hack",
          "exposure_direction": "incoming",
          "exposure_type": "direct",
          "is_direct": true,
          "amount_usd": 1471.16,
          "percentage": 50,
          "country": ""
        }
      ],
      "destination_of_funds": [],
      "counterparty_connections": [],
      "sanctions_hit": false,
      "risk_factors": [
        {
          "source": "exposure",
          "category": "stolen_funds",
          "label": "Theft / Hack",
          "entity_name": "Stolen Funds",
          "direction": "incoming",
          "exposure_type": "direct",
          "amount_usd": 1471.16,
          "percentage": 50,
          "is_high_risk": true,
          "description": "50% direct incoming exposure to Theft / Hack (Stolen Funds)"
        }
      ],
      "raw_response": { "...": "provider-specific details" }
    },
    "created_at": "2026-04-16T12:00:02Z"
  }
]
```

`result_type`: `FIAT_MONITORING`, `WALLET_SCREENING`, `TRANSACTION_SCREENING`, `TRAVEL_RULE`, `NETWORK_GRAPH`, `CUSTOM`.

`payload.risk_factors` is the ranked explanation of `score` — what produced the verdict, high-risk drivers first and then by value moved. A high `score` with no `is_high_risk` entry means the provider graded the entity on its own exposure model without reporting a sanctions or attributed-entity match; `summary` says so explicitly. Field-by-field reference: [Risk factors](/transaction-monitoring/wallet-screening#risk-factors). Results screened before this field existed omit the key.

For crypto transaction-hash screening, `transaction_flows` is populated when on-chain enrichment is available. It normalizes chain activity so the console can render both the transaction overview and visualization graph from the same response payload.

Supported enrichment sources:

* EVM chains use Blockscout to normalize the main transaction, internal calls, and token transfers.
* Bitcoin uses mempool.space to normalize transaction inputs and outputs.
* Solana uses Helius to normalize native SOL transfers, SPL token transfers, and available NFT event context.

Each `transaction_flows[]` item includes stable normalized fields (`flow_type`, `from_address`, `to_address`, `amount`, `amount_usd`, `currency`, `token_name`, `token_address`, `transaction_hash`, `block_timestamp`, `index`, `success`) plus provider-specific `metadata`.

Common `metadata` examples:

```json theme={null}
{
  "provider": "blockscout",
  "decoded_method_call": "swap(string aggregatorId, address tokenFrom, uint256 amount, bytes data)",
  "block_number": 23141214,
  "gas_used": "171843",
  "fee_native": 0.000342317619518133,
  "token_icon_url": "https://...",
  "token_reputation": "ok"
}
```

```json theme={null}
{
  "provider": "mempool",
  "role": "input",
  "previous_txid": "4c0c...",
  "previous_vout": 0,
  "scriptpubkey_type": "v0_p2wpkh",
  "fee_btc": 0.00000322,
  "block_height": 943130
}
```

```json theme={null}
{
  "provider": "helius",
  "source": "MAGIC_EDEN",
  "type": "NFT_BID",
  "description": "Wallet bid 2.5 SOL on an NFT.",
  "slot": 136658192,
  "fee_sol": 0.000005,
  "nft_event": {
    "type": "NFT_BID",
    "source": "MAGIC_EDEN",
    "nft_mints": ["3bUW..."]
  }
}
```

`metadata` is additive and provider-specific. Do not build critical integrations that require every key to be present for every chain.

### Travel rule

`null` when the transaction has no Travel Rule transfer or check. It is populated when you submit `travel_rule_details`, and also when [Travel Rule](/transaction-monitoring/travel-rule) is enabled for the application and the transaction was created with `transaction_category: "travelRule"`: Didit then initiates the exchange itself, with or without `travel_rule_details`, and reports its `status` here. Read this field rather than the request you sent.

```json theme={null}
"travel_rule": {
  "uuid": "...",
  "status": "COMPLIANT",
  "required": true,
  "protocol": "TRP",
  "obligations_count": 2,
  "originator_data": { "name": "...", "wallet_address": "..." },
  "beneficiary_data": { "name": "...", "wallet_address": "..." },
  "metadata": {}
}
```

See [Travel rule](/transaction-monitoring/travel-rule).

### Network snapshot

The stored graph itself, not a reference to it. It comes from either source:

* a `network_snapshot` you submitted with the transaction, or
* the graph Didit builds when [AML wallet screening](/transaction-monitoring/aml-screening) succeeds for a crypto transaction, even if the request carried no `network_snapshot`. A screening-built graph replaces a submitted one, and an asynchronous re-screen refreshes it.

`null` when neither exists:

```json theme={null}
"network_snapshot": {
  "uuid": "...",
  "nodes": [ ... ],
  "edges": [ ... ],
  "metrics": { }
}
```

The console transaction detail page renders the same graph.

### Tags, metadata, props

* `tags[]` — attached tags (either by rule action or by analyst): `{ "uuid", "name", "color", "description", "source" }`, where `source` is `didit` for a preset tag and `custom` for one of yours.
* `metadata` — a snapshot of the `subject` and `counterparty` payloads exactly as you submitted them at create time, under those two keys.
* `props` — the `custom_properties` you supplied at create time. Each key is addressable in rule conditions as `custom_values.<key>`.

### Remediation

When a rule triggers `AWAITING_USER`, Didit creates the linked verification session and returns it in two fields:

* `remediation` — the linked session: `{ "session_id", "session_token", "url", "status" }`. Stays populated for the life of the transaction, so you can always see how the user action ended.
* `action_required` — the action the user must take right now, or `null` once nothing is pending: `{ "type": "verification_session", "url", "session_id", "session_token", "status" }`. Redirect the user to `url`, or feed `session_token` to a Didit SDK. Travel Rule wallet-ownership actions use `{ "type": "wallet_ownership", "url", "widget_session_id", "expires_at" }` and take precedence when both could apply.

The same two fields ride on the `transaction.created` and `transaction.status.updated` webhook payloads (`action_required`) - see [webhooks](/transaction-monitoring/webhooks).

### Cost breakdown

`null` until a billable feature ran for the transaction. Otherwise `{ "total_price", "items": [ { "usage_type", "price", "details" } ] }`, one item per metered feature (screening, enrichment, and so on).

## Currency conversion

`preferred_currency_amount` is `amount` converted to your application's preferred currency at mid-market rates, unless you supplied `amount_in_default_currency`, in which case that pre-converted value is used as is. Rule conditions on `amount` compare the native amount; use `preferred_currency_amount` in conditions when you need one threshold across currencies.

## Next steps

<CardGroup cols={3}>
  <Card title="Submit transactions" icon="arrow-right-to-bracket" href="/transaction-monitoring/transactions">
    Full request schema.
  </Card>

  <Card title="Statuses" icon="list-check" href="/transaction-monitoring/statuses">
    What each status means.
  </Card>

  <Card title="Risk scoring" icon="gauge" href="/transaction-monitoring/risk-scoring">
    How score is computed.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.