Didit Transactions API
The Transactions API from Didit — 6 operation(s) for transactions.
The Transactions API from Didit — 6 operation(s) for transactions.
openapi: 3.0.0
info:
version: 3.0.0
title: Didit Verification Billing Transactions API
description: Identity verification API. Authenticate with x-api-key header.
servers:
- url: https://verification.didit.me
tags:
- name: Transactions
paths:
/v3/wallet-screening/:
post:
summary: Screen a wallet address
description: Run on-demand AML screening for a single crypto wallet/address without creating a transaction. Resolves your application's configured blockchain analytics provider (Merkle Science or Crystal), screens the address synchronously, and returns the normalised risk result. Nothing is written to the transactions table. One AML monitoring usage is billed per successful screening (sandbox applications are not billed).
operationId: screenWallet
tags:
- Transactions
security:
- ApiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- wallet_address
- blockchain
properties:
wallet_address:
type: string
description: 'The crypto address to screen. Must match the format of the selected blockchain (e.g. a `0x`-prefixed 40-hex-char address for EVM chains). Alias: `address`.'
example: '0x28c6c06298d514db089934071355e5743bf21d60'
blockchain:
type: string
description: 'Asset / chain identifier. One of: BTC, ETH, LTC, XRP, BCH, DOGE, TRX, SOL, MATIC, BNB, USDT, USDC. Alias: `currency`.'
enum:
- BTC
- ETH
- LTC
- XRP
- BCH
- DOGE
- TRX
- SOL
- MATIC
- BNB
- USDT
- USDC
example: ETH
direction:
type: string
description: Optional. Whether the address is being screened as an inbound (deposit) or outbound (withdrawal) counterparty. Accepts `inbound`, `outbound`, `deposit`, or `withdrawal`. Defaults to a neutral pre-transfer screen when omitted.
enum:
- inbound
- outbound
- deposit
- withdrawal
x-codeSamples:
- lang: curl
label: curl
source: "curl -X POST 'https://verification.didit.me/v3/wallet-screening/' \\\n -H 'x-api-key: YOUR_API_KEY' \\\n -H 'Content-Type: application/json' \\\n -d '{\n \"wallet_address\": \"0x28c6c06298d514db089934071355e5743bf21d60\",\n \"blockchain\": \"ETH\"\n }'"
- lang: python
label: Python
source: "import os\n\nimport requests\n\nresp = requests.post(\n 'https://verification.didit.me/v3/wallet-screening/',\n headers={'x-api-key': os.environ['DIDIT_API_KEY']},\n json={\n 'wallet_address': '0x28c6c06298d514db089934071355e5743bf21d60',\n 'blockchain': 'ETH',\n },\n timeout=20,\n)\nresp.raise_for_status()\nresult = resp.json()\nprint(result['risk_score'], result['severity'], result['sanctions_hit'])"
- lang: javascript
label: JavaScript
source: "const result = await fetch('https://verification.didit.me/v3/wallet-screening/', {\n method: 'POST',\n headers: {\n 'x-api-key': process.env.DIDIT_API_KEY,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n wallet_address: '0x28c6c06298d514db089934071355e5743bf21d60',\n blockchain: 'ETH',\n }),\n}).then((r) => r.json());\nconsole.log(result.risk_score, result.severity, result.sanctions_hit);"
responses:
'200':
description: The normalised wallet screening result.
content:
application/json:
schema:
type: object
properties:
provider:
type: string
description: Provider that performed the screening (e.g. `merklescience`, `crystal`).
screening_type:
type: string
enum:
- WALLET_SCREENING
description: Always `WALLET_SCREENING` for this endpoint.
risk_score:
type: integer
description: Normalised 0-100 risk score. Higher means greater exposure to risky entities.
severity:
type: string
enum:
- UNKNOWN
- LOW
- MEDIUM
- HIGH
- CRITICAL
description: Severity bucket derived from `risk_score`.
status:
type: string
enum:
- SCREENED
- PENDING
- ERROR
description: Screening outcome status.
summary:
type: string
description: Human-readable summary of the screening result.
wallet_address:
type: string
description: The screened address, echoed back.
blockchain:
type: string
description: The blockchain that was screened.
sanctions_hit:
type: boolean
description: True if the address has direct or indirect sanctions exposure.
dominant_risk_category:
type: string
nullable: true
description: Highest-weighted high-risk category, or `null` when none is dominant (e.g. `sanctioned`, `mixer`, `stolen_funds`).
source_of_funds:
type: array
description: Where the address received funds from, attributed by entity. Each entry is an exposure breakdown.
items:
type: object
properties:
category:
type: string
description: Normalised risk category, e.g. `exchange_licensed`, `dex`, `defi`, `payment_processor`, `mixer`, `darknet_market`, `sanctioned`, `stolen_funds`, `high_risk_exchange`.
entity_name:
type: string
description: Name of the attributed entity (e.g. `Binance.com`, `Tornado Cash`).
entity_type:
type: string
description: Provider entity type (e.g. `Exchange`, `Mixer`, `DeFi`, `Sanctions`, `Theft`).
entity_subtype:
type: string
description: More granular subtype (e.g. `Mandatory KYC and AML`, `OFAC SDN`, `Yield Aggregator`).
exposure_direction:
type: string
enum:
- incoming
- outgoing
- connected
description: Whether the funds came from (`incoming`) or went to (`outgoing`) this entity.
exposure_type:
type: string
enum:
- direct
- indirect
description: '`direct` (1 hop) or `indirect` (multi-hop) exposure.'
is_direct:
type: boolean
description: True when the exposure is direct (0 hops).
amount_usd:
type: number
description: USD value attributed to this entity.
percentage:
type: number
description: Share of the direction's total exposure, 0-100.
hops:
type: integer
description: Number of hops to the entity (0 for direct exposure).
risk_level:
type: string
enum:
- UNKNOWN
- LOW
- MEDIUM
- HIGH
- CRITICAL
description: Risk level of the entity.
country:
type: string
description: Primary ISO 3166-1 alpha-2 country of the entity, when known.
destination_of_funds:
type: array
description: Where the address sent funds to, attributed by entity. Same item shape as `source_of_funds` with `exposure_direction` = `outgoing`.
items:
type: object
properties:
category:
type: string
entity_name:
type: string
entity_type:
type: string
entity_subtype:
type: string
exposure_direction:
type: string
enum:
- incoming
- outgoing
- connected
exposure_type:
type: string
enum:
- direct
- indirect
is_direct:
type: boolean
amount_usd:
type: number
percentage:
type: number
hops:
type: integer
risk_level:
type: string
enum:
- UNKNOWN
- LOW
- MEDIUM
- HIGH
- CRITICAL
country:
type: string
counterparty_connections:
type: array
description: Direct and indirect counterparty entities with received/sent amounts and risk levels.
items:
type: object
properties:
entity_name:
type: string
description: Counterparty entity name.
entity_type:
type: string
description: Counterparty entity type.
entity_subtype:
type: string
description: Counterparty entity subtype.
risk_level:
type: string
enum:
- UNKNOWN
- LOW
- MEDIUM
- HIGH
- CRITICAL
categories:
type: array
items:
type: string
description: Risk categories attributed to the counterparty.
received_usd:
type: number
description: USD received from the counterparty.
sent_usd:
type: number
description: USD sent to the counterparty.
received_hops:
type: integer
sent_hops:
type: integer
percentage:
type: number
is_direct:
type: boolean
country:
type: string
example:
provider: merklescience
screening_type: WALLET_SCREENING
risk_score: 72
severity: HIGH
status: SCREENED
summary: 'Merkle Science risk: High (4/5). Dominant risk: mixer'
wallet_address: '0x28c6c06298d514db089934071355e5743bf21d60'
blockchain: ETH
sanctions_hit: true
dominant_risk_category: mixer
source_of_funds:
- category: exchange_licensed
entity_name: Binance.com
entity_type: Exchange
entity_subtype: Mandatory KYC and AML
exposure_direction: incoming
exposure_type: direct
is_direct: true
amount_usd: 18420.55
percentage: 61.4
hops: 0
risk_level: LOW
country: SC
- category: mixer
entity_name: Tornado Cash
entity_type: Mixer
entity_subtype: OFAC SDN
exposure_direction: incoming
exposure_type: indirect
is_direct: false
amount_usd: 11580.2
percentage: 38.6
hops: 2
risk_level: CRITICAL
country: RU
destination_of_funds:
- category: exchange_licensed
entity_name: Coinbase
entity_type: Exchange
entity_subtype: Mandatory KYC and AML
exposure_direction: outgoing
exposure_type: direct
is_direct: true
amount_usd: 30000.75
percentage: 100
hops: 0
risk_level: LOW
country: US
counterparty_connections:
- entity_name: Tornado Cash
entity_type: Mixer
entity_subtype: OFAC SDN
risk_level: CRITICAL
categories:
- mixer
received_usd: 11580.2
sent_usd: 0
received_hops: 2
sent_hops: 0
percentage: 38.6
is_direct: false
country: RU
'400':
description: Validation error — malformed wallet address, missing `wallet_address`, or unsupported `blockchain`.
'401':
description: Missing or invalid `x-api-key`.
'409':
description: No AML provider is configured for the application, or the configured provider does not support wallet screening yet. Configure transaction monitoring first.
'502':
description: The AML provider could not complete the screening. Retry later.
/v3/transactions/:
get:
summary: List transactions
description: Paginated list of monitored transactions, newest first (`txn_date` desc). `count` is capped at 100; use `total_transactions` for the true row count. This endpoint does not support filtering or search parameters.
operationId: listTransactions
tags:
- Transactions
parameters:
- name: limit
in: query
schema:
type: integer
default: 50
minimum: 1
description: Page size. Defaults to 50 when omitted. There is no enforced maximum, but keep pages small for latency.
- name: offset
in: query
schema:
type: integer
default: 0
minimum: 0
description: Zero-based offset of the first record to return. Prefer following the `next` URL from the previous page.
x-codeSamples:
- lang: curl
label: curl
source: "curl -X GET 'https://verification.didit.me/v3/transactions/?limit=50' \\\n -H 'x-api-key: YOUR_API_KEY'"
- lang: python
label: Python
source: "import os\n\nimport requests\n\nresp = requests.get(\n 'https://verification.didit.me/v3/transactions/',\n headers={'x-api-key': os.environ['DIDIT_API_KEY']},\n params={'limit': 50},\n timeout=10,\n)\nresp.raise_for_status()\npage = resp.json()\nfor tx in page['results']:\n print(\n tx['transaction_number'],\n tx['status'],\n tx['severity'],\n f\"{tx['amount']} {tx['currency']}\",\n tx.get('subject_name') or tx.get('subject_vendor_data'),\n )"
- lang: javascript
label: JavaScript
source: "const url = new URL('https://verification.didit.me/v3/transactions/');\nurl.searchParams.set('limit', '50');\nconst page = await fetch(url, {\n headers: { 'x-api-key': process.env.DIDIT_API_KEY },\n}).then((r) => r.json());\nfor (const tx of page.results) {\n console.log(tx.transaction_number, tx.status, tx.severity, tx.amount, tx.currency);\n}"
responses:
'200':
description: Paginated list of transaction summaries, newest first.
content:
application/json:
schema:
type: object
properties:
count:
type: integer
description: Capped count of matching transactions (exact up to 100, capped thereafter). Use `total_transactions` for the true count when paginating.
next:
type: string
nullable: true
description: Absolute URL of the next page, or `null` on the last page.
previous:
type: string
nullable: true
description: Absolute URL of the previous page, or `null` on the first page.
total_transactions:
type: integer
description: Exact total count of (non-deleted) transactions for the application. Present on paginated responses.
results:
type: array
items:
type: object
properties:
uuid:
type: string
format: uuid
description: Stable Didit transaction identifier. Use as `{transaction_id}` in detail/notes/related calls.
transaction_number:
type: integer
description: Application-scoped sequential transaction number shown in Console (e.g. `4123`).
txn_id:
type: string
description: Customer-provided identifier from the create call (max 128 chars). Unique per application.
transaction_type:
type: string
description: 'Top-level category as stored: `finance`, `kyc`, `travelRule`, `userPlatformEvent`, `gamblingBet`, `gamblingLimitChange`, `gamblingBonusChange`, `auditTrailEvent`. Note multi-word values are echoed back in camelCase even when submitted in snake_case.'
action_type:
type: string
description: Sub-type within the category (e.g. `deposit`, `withdrawal`, `transfer`).
status:
type: string
enum:
- APPROVED
- IN_REVIEW
- DECLINED
- AWAITING_USER
description: Current monitoring verdict.
direction:
type: string
enum:
- INBOUND
- OUTBOUND
description: Direction relative to the subject. Stored uppercase regardless of the casing submitted.
amount:
type: string
description: Transaction amount as a decimal string with trailing zeros stripped (e.g. `"1500"`, `"0.5"`, `"0.123456789012345678"`). Up to 18 decimal places.
currency:
type: string
description: Currency code of `amount` (e.g. `EUR`, `USD`, `BTC`).
preferred_currency_amount:
type: string
nullable: true
description: '`amount` converted to the application''s preferred currency, when available.'
preferred_currency_code:
type: string
nullable: true
description: Preferred currency code used for `preferred_currency_amount`.
payment_details:
type: string
nullable: true
description: Free-text payment reference or memo from the submission.
score:
type: integer
description: Risk score (typically 0–100). Higher = riskier.
severity:
type: string
nullable: true
enum:
- UNKNOWN
- LOW
- MEDIUM
- HIGH
- CRITICAL
description: Categorical risk severity set by rules/providers (`UNKNOWN`, `LOW`, `MEDIUM`, `HIGH`, `CRITICAL`). `null` until something sets it.
subject_name:
type: string
nullable: true
description: Full name of the `APPLICANT` party.
subject_vendor_data:
type: string
nullable: true
description: Your internal user/business identifier for the applicant.
subject_country:
type: string
nullable: true
description: Country code of the applicant, from the submitted `address.country` (typically ISO 3166-1 alpha-3).
counterparty_name:
type: string
nullable: true
description: Full name of the `COUNTERPARTY` party, if any.
counterparty_vendor_data:
type: string
nullable: true
description: Your internal identifier for the counterparty.
counterparty_country:
type: string
nullable: true
description: Country code of the counterparty, from the submitted `address.country`.
tags:
type: array
description: Tags attached to the transaction (manually or by rules).
items:
type: object
properties:
uuid:
type: string
format: uuid
name:
type: string
color:
type: string
description:
type: string
nullable: true
source:
type: string
enum:
- didit
- custom
description: Whether the tag is a Didit preset or a custom tag.
txn_date:
type: string
format: date-time
description: When the transaction occurred (from `transaction_at` at create time).
created_at:
type: string
format: date-time
description: When Didit recorded the submission.
decision_reason_code:
type: string
nullable: true
description: Machine-readable reason for the current `status` (e.g. `WALLET_HIGH_RISK`).
decision_reason_label:
type: string
nullable: true
description: Human-readable label for `decision_reason_code`.
assigned_to_name:
type: string
nullable: true
description: Display name of the Console reviewer assigned to this transaction.
examples:
Single transaction:
value:
count: 1
next: null
previous: null
total_transactions: 1
results:
- uuid: abcdef12-3456-4890-abcd-ef1234567890
transaction_number: 4123
txn_id: your-txn-2026-05-17-001
transaction_type: finance
action_type: withdrawal
status: IN_REVIEW
direction: OUTBOUND
amount: '1500'
currency: EUR
preferred_currency_amount: '1620.45'
preferred_currency_code: USD
payment_details: Withdrawal to crypto wallet
txn_date: '2026-05-17T08:42:00Z'
created_at: '2026-05-17T08:42:11Z'
score: 78
severity: HIGH
decision_reason_code: WALLET_HIGH_RISK
decision_reason_label: Destination wallet flagged as high risk
tags:
- uuid: 9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d
name: Manual review
color: '#F59E0B'
description: null
source: custom
subject_name: Maria Garcia
subject_vendor_data: user-12345
counterparty_name: null
counterparty_vendor_data: null
counterparty_country: null
subject_country: null
assigned_to_name: Alex Reviewer
'403':
description: Missing, invalid, or revoked API key, or the key cannot list transactions for this application. This endpoint returns `403` (never `401`) for authentication failures, including requests with no credentials at all.
content:
application/json:
examples:
Forbidden:
value:
detail: You do not have permission to perform this action.
'429':
description: Rate limit exceeded; back off and retry after the interval indicated in `Retry-After`.
content:
application/json:
examples:
Throttled:
value:
detail: Request was throttled. Expected available in 30 seconds.
security:
- ApiKeyAuth: []
post:
summary: Create transaction
description: Submit a transaction for synchronous AML/risk monitoring. The transaction is created `APPROVED`, then your rules (and crypto screening, when applicable) run inline and may flip the returned `status` to `IN_REVIEW` or `DECLINED`. **`transaction_id` is your idempotency key** (max 128 chars, unique per app); reusing it returns 400. A `transaction.created` webhook is dispatched on success (sandbox applications are not billed and do not emit webhooks).
operationId: createTransaction
tags:
- Transactions
x-codeSamples:
- lang: curl
label: curl
source: "curl -X POST 'https://verification.didit.me/v3/transactions/' \\\n -H 'x-api-key: YOUR_API_KEY' \\\n -H 'Content-Type: application/json' \\\n -d '{\n \"transaction_id\": \"your-txn-2026-05-17-001\",\n \"transaction_category\": \"finance\",\n \"transaction_details\": {\n \"direction\": \"outbound\",\n \"amount\": 1500,\n \"currency\": \"EUR\",\n \"action_type\": \"withdrawal\"\n },\n \"subject\": {\n \"entity_type\": \"individual\",\n \"vendor_data\": \"user-12345\",\n \"full_name\": \"Maria Garcia\"\n }\n }'"
- lang: python
label: Python
source: "import os\n\nimport requests\n\nresp = requests.post(\n 'https://verification.didit.me/v3/transactions/',\n headers={\n 'x-api-key': os.environ['DIDIT_API_KEY'],\n 'Content-Type': 'application/json',\n },\n json={\n 'transaction_id': 'your-txn-2026-05-17-001',\n 'transaction_category': 'finance',\n 'transaction_details': {\n 'direction': 'outbound',\n 'amount': 1500,\n 'currency': 'EUR',\n 'action_type': 'withdrawal',\n },\n 'subject': {\n 'entity_type': 'individual',\n 'vendor_data': 'user-12345',\n 'full_name': 'Maria Garcia',\n },\n },\n timeout=15,\n)\nresp.raise_for_status()\ntx = resp.json()\nprint(tx['txn_id'], '->', tx['status'], tx['severity'])"
- lang: javascript
label: JavaScript
source: "const resp = await fetch('https://verification.didit.me/v3/transactions/', {\n method: 'POST',\n headers: {\n 'x-api-key': process.env.DIDIT_API_KEY,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n transaction_id: 'your-txn-2026-05-17-001',\n transaction_category: 'finance',\n transaction_details: {\n direction: 'outbound',\n amount: 1500,\n currency: 'EUR',\n action_type: 'withdrawal',\n },\n subject: {\n entity_type: 'individual',\n vendor_data: 'user-12345',\n full_name: 'Maria Garcia',\n },\n }),\n});\nif (!resp.ok) throw new Error(await resp.text());\nconst tx = await resp.json();\nconsole.log(tx.txn_id, tx.status, tx.severity);"
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
transaction_id:
type: string
description: Your unique identifier for this transaction (max 128 characters).
example: your-txn-2026-05-17-001
transaction_at:
type: string
format: date-time
description: When the transaction occurred. Defaults to now if omitted.
time_zone:
type: string
description: IANA time zone identifier, e.g. `Europe/Madrid`.
transaction_category:
type: string
description: Category of the transaction. CamelCase aliases (`travelRule`, `userPlatformEvent`, `gamblingBet`, …) are also accepted; the stored/echoed value is camelCase for multi-word categories.
example: finance
enum:
- finance
- kyc
- travel_rule
- user_event
- audit_trail_event
- gambling_bet
- gambling_limit_change
- gambling_bonus_change
- travelRule
transaction_details:
type: object
description: Core financial details of the transaction.
required:
- direction
- amount
-
# --- truncated at 32 KB (100 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/didit/refs/heads/main/openapi/didit-transactions-api-openapi.yml