> ## 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.

# Submitting Transactions

> Submit transactions for real-time monitoring with parties, payment methods, device context, and custom properties. Pay-per-call $0.02 per transaction.

Submit transactions to Didit via the [Create Transaction](/management-api/transactions/create) API. Each transaction includes structured party, payment, and context data that the rules engine evaluates in real time.

<Tip>
  When the transaction originates on an end-user's device - a crypto withdrawal, an in-app payment - consider [SDK transaction submission](/transaction-monitoring/sdk-transaction-submission): a scoped token replaces the API key, device intelligence is collected automatically, and required user actions (wallet-ownership proof, step-up verification) launch on the spot.
</Tip>

## Transaction categories

Every transaction has a `transaction_category` that determines how rules and analytics treat it:

| Category                | Description                                                    |
| ----------------------- | -------------------------------------------------------------- |
| `finance`               | Standard financial transaction (deposit, withdrawal, transfer) |
| `kyc`                   | Identity verification-related event                            |
| `travel_rule`           | Virtual asset transfer requiring travel rule compliance        |
| `user_event`            | Custom platform event (login, profile change, etc.)            |
| `gambling_bet`          | Gambling wager or bet placement                                |
| `gambling_limit_change` | Change to a player's deposit, loss, or wager limit             |
| `gambling_bonus_change` | Bonus grant, redemption, or forfeiture                         |
| `audit_trail_event`     | System or compliance audit event                               |

## Transaction details

The `transaction_details` object carries the financial data:

| Field                  | Type   | Description                                                                                                     |
| ---------------------- | ------ | --------------------------------------------------------------------------------------------------------------- |
| `direction`            | string | `inbound` or `outbound`                                                                                         |
| `amount`               | string | Transaction value as a decimal string (e.g., `"1500.50"`)                                                       |
| `currency`             | string | ISO currency code (e.g., `USD`, `EUR`, `BTC`)                                                                   |
| `currency_kind`        | string | `fiat` or `crypto` — determines whether crypto screening triggers                                               |
| `action_type`          | string | Vendor-defined action label (e.g., `deposit`, `withdrawal`, `purchase`)                                         |
| `payment_details`      | string | Free-text description of the payment (e.g., `"Bank transfer from ABC Corp"`)                                    |
| `payment_reference_id` | string | External payment reference identifier. For post-transfer crypto screening, use the blockchain transaction hash. |

## Subject and counterparty

Each transaction has a **subject** (required) and an optional **counterparty**. Both use the same party model:

| Field           | Type   | Description                                                                                                                                                    |
| --------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `entity_type`   | string | `person` or `company`                                                                                                                                          |
| `vendor_data`   | string | Your identifier for this party — links the transaction to a [user](/management-api/users/list) or [business profile](/business-verification/business-profiles) |
| `full_name`     | string | Full name of the party                                                                                                                                         |
| `first_name`    | string | Given name                                                                                                                                                     |
| `last_name`     | string | Family name                                                                                                                                                    |
| `date_of_birth` | string | ISO date (e.g., `1990-01-15`)                                                                                                                                  |
| `country_code`  | string | ISO 3166-1 alpha-2 country code                                                                                                                                |
| `address`       | object | Structured address with `street`, `city`, `state`, `country`, `postal_code`                                                                                    |

When `vendor_data` matches an existing user or business, Didit automatically links the transaction to that entity's profile, enabling cross-session rule evaluation and velocity checks.
In the response, both parties come back in the `parties` array with roles `APPLICANT` and `COUNTERPARTY`.

## Payment methods

Attach a `payment_method` to each party to describe the instrument on that side:

| Field             | Type   | Description                                                                            |
| ----------------- | ------ | -------------------------------------------------------------------------------------- |
| `method_type`     | string | `bank_card`, `bank_account`, `ewallet`, `crypto_wallet`, `unhosted_wallet`, or `other` |
| `account_id`      | string | Account number, wallet address, or card token                                          |
| `issuing_country` | string | Country that issued the payment instrument                                             |

On `travelRule` transactions, a counterparty payment method with `payment_method_type: "unhosted_wallet"` declares the destination as a self-hosted wallet and routes the transfer straight to the ownership-proof flow - see [Declared self-hosted wallets](/transaction-monitoring/travel-rule#declared-self-hosted-wallets).

For crypto transactions, include wallet addresses in `account_id` and set `currency_kind` to `crypto` so blockchain screening can run automatically. Direction controls which wallet is screened: inbound pre-transfer screening uses the sender wallet in `counterparty.payment_method.account_id`; outbound screening uses the destination wallet in `counterparty.payment_method.account_id`. If you send a blockchain hash in `transaction_details.payment_reference_id`, inbound transaction screening requires your service deposit address in `subject.payment_method.account_id`, while outbound transaction screening requires the destination wallet in `counterparty.payment_method.account_id`.

## Crypto screening override

Use `include_crypto_screening` at the top level of the request to override the default configured in **Transactions** > **Settings** in the Console:

| Value             | Description                                 |
| ----------------- | ------------------------------------------- |
| `true`            | Force crypto screening for this transaction |
| `false`           | Skip crypto screening for this transaction  |
| omitted or `null` | Use the application-level default           |

## Device context

Include device information on the subject party to power device intelligence rules:

| Field                                    | Type   | Description                      |
| ---------------------------------------- | ------ | -------------------------------- |
| `device.fingerprint`                     | string | Unique device fingerprint        |
| `device.user_agent`                      | string | Browser or app user agent string |
| `device.network_context.ip_address`      | string | Client IP address                |
| `device.network_context.ip_country_code` | string | Geo-resolved country of the IP   |

Device context enables rules like multi-accounting detection (same fingerprint across different subjects) and location-based risk scoring.

## Custom properties

Add any additional key-value pairs in the `custom_properties` object. Rules can reference these fields in their conditions — useful for passing business-specific context like product category, merchant ID, or channel.

```json theme={null}
"custom_properties": {
  "product_category": "electronics",
  "merchant_id": "MER456",
  "channel": "mobile_app"
}
```

In rule conditions, reference each key with the field path `custom_values.<key>` — for example, the payload above matches `custom_values.product_category eq "electronics"`. In the Console rule builder, keys seen on recently ingested transactions appear in the condition field selector under **Custom Properties**, and **Enter custom property** in the same group lets you type any key manually (case-sensitive). See [Rules & scoring](/transaction-monitoring/rules#referencing-custom-properties) for details.

## Example request

```bash theme={null}
curl -X POST https://verification.didit.me/v3/transactions/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "transaction_id": "TXN-20260410-001",
    "transaction_at": "2026-04-10T15:30:00Z",
    "transaction_category": "finance",
    "transaction_details": {
      "direction": "outbound",
      "amount": "1500.50",
      "currency": "EUR",
      "currency_kind": "fiat",
      "action_type": "withdrawal"
    },
    "subject": {
      "entity_type": "person",
      "vendor_data": "user-123",
      "full_name": "John Doe",
      "country_code": "US",
      "payment_method": {
        "method_type": "bank_account",
        "account_id": "DE89370400440532013000",
        "issuing_country": "DE"
      }
    },
    "counterparty": {
      "entity_type": "company",
      "full_name": "John Doe",
      "country_code": "GB"
    },
    "custom_properties": {
      "order_id": "ORD-7891"
    }
  }'
```

## Response

The API returns the created transaction with its initial evaluation results:

| Field                   | Type   | Description                                                             |
| ----------------------- | ------ | ----------------------------------------------------------------------- |
| `uuid`                  | string | Didit's unique transaction identifier                                   |
| `txn_id`                | string | Your provided transaction ID                                            |
| `status`                | string | `APPROVED`, `IN_REVIEW`, `DECLINED`, or `AWAITING_USER`                 |
| `score`                 | number | Cumulative risk score from all matched rules                            |
| `severity`              | string | Highest severity of matched rules (`LOW`, `MEDIUM`, `HIGH`, `CRITICAL`) |
| `decision_reason_code`  | string | Machine-readable reason for the status decision                         |
| `decision_reason_label` | string | Human-readable description of the decision                              |

See the [API Reference](/management-api/transactions/create) for the full request and response schema, and the dedicated [response schema reference](/transaction-monitoring/response-schema) for an annotated payload walkthrough.

## Idempotency

`txn_id` is unique per application. Re-submitting the same `txn_id` returns the existing transaction rather than creating a duplicate — effectively idempotent for retries. Always generate `txn_id` on your side (e.g. your own transaction DB ID, UUID, or deterministic hash).

## Historical backfill

Pass `txn_date` in the past to ingest historical transactions. Rules still evaluate by default — use the console CSV import with dry-ingest mode if you want to skip rule evaluation during bulk historical loads. See [integration guide](/transaction-monitoring/integration-guide#historical-ingestion).

## Next steps

<CardGroup cols={3}>
  <Card title="Rules & scoring" icon="scale-balanced" href="/transaction-monitoring/rules">
    How submitted transactions are evaluated against rules.
  </Card>

  <Card title="Response schema" icon="file-lines" href="/transaction-monitoring/response-schema">
    Full annotated response payload.
  </Card>

  <Card title="Crypto screening" icon="link" href="/transaction-monitoring/aml-screening">
    Automatic wallet and transaction screening for crypto transactions.
  </Card>

  <Card title="Travel rule" icon="globe" href="/transaction-monitoring/travel-rule">
    Attach travel rule compliance data to virtual asset transfers.
  </Card>

  <Card title="IP enrichment" icon="globe-pointer" href="/transaction-monitoring/ip-enrichment">
    IP-derived context available to rules.
  </Card>

  <Card title="API reference" icon="code" href="/management-api/transactions/create">
    Full request schema for the Create Transaction endpoint.
  </Card>
</CardGroup>
