Skip to main content
A reference of common Transaction Monitoring issues, with symptom, cause, and fix.

Duplicate txn_id error

Symptom. Submitting a transaction returns the existing record instead of an error — and your code doesn’t realize it’s a duplicate. Cause. txn_id is unique per application. Re-submitting the same txn_id returns the existing transaction (idempotent). Fix.
  • Generate txn_id deterministically on your side (e.g. use your own transaction DB ID).
  • Compare the response’s transaction_id with what you expect; if the response’s created_at doesn’t match “now”, you hit an existing record.

Rule not firing

Symptom. You created a rule that should match, but no transactions are showing it in rule_runs[] with matched: true. Causes and fixes.
  • Rule mode is DISABLED or TEST — check Rules → [rule] → Mode. Only ACTIVE rules contribute to scoring; TEST rules evaluate but don’t affect status.
  • Scope filter excludes the transaction — e.g. scope set to transaction_type = finance won’t match travelRule transactions.
  • Aggregation window is shorter than needed — a “20 transactions in 30 days” rule won’t match after only 15 transactions.
  • Condition field is null — e.g. your rule checks counterparty.country_code but you didn’t send a counterparty.
  • Currency conversion — the rule thresholds on amount_in_default_currency; if your application’s default currency differs from the transaction currency, the converted amount may be below threshold.
Use the Rules → [rule] → Backtest feature to replay a past transaction and see why the rule did / didn’t fire.

Rule firing on everything

Symptom. A rule fires on 90%+ of transactions — your review queue is flooded. Cause. Conditions are too broad, or thresholds are too low. Fix.
  • Add scope filters to narrow applicability (e.g. only outbound, only certain transaction types).
  • Raise thresholds (amounts, velocity counts).
  • Put the rule in TEST mode for a week — analyze the rule_runs to see the match rate and tighten conditions before re-enabling.

AML screening timed out

Symptom. Transaction completed with status: APPROVED but the provider_results[] array shows status: FAILED for a wallet or AML provider. Causes.
  • Provider API was briefly unavailable.
  • Query timed out (typically ~10s).
Fix.
  • Transactions never fail because of provider issues — enrichment is best-effort.
  • If a specific provider fails repeatedly, check its status page or open a support ticket.
  • Consider configuring provider preferences in Settings → Transaction Monitoring → Providers to route to alternative providers.

IP enrichment missing

Symptom. A transaction’s applicant.ip_enrichment is absent or partial. Causes.
  • No applicant.device.ip in the submission.
  • IP is private / reserved (not routable).
  • All enrichment providers were temporarily unavailable.
Fix.
  • Capture the submitter’s IP in your client/server and pass it on every transaction.
  • Use only routable IPs — Didit silently skips private ranges.
  • Check Settings → Status in the console for provider health.

Webhook signature mismatch

Symptom. Your endpoint rejects events because the signature doesn’t match. Causes.
  • Raw body was modified (JSON re-stringified with different whitespace).
  • Wrong secret.
  • Multiple destinations with the same URL — signatures differ per destination.
Fix.
  • Sign over the raw request body, not the parsed JSON. Many frameworks expose a raw-body middleware.
  • Rotate the secret if compromised: Webhook destinations → [destination] → Rotate secret.
  • Keep one destination per URL to avoid secret confusion.

Webhook not arriving

Symptom. Transactions are being created but webhooks never arrive. Causes.
  • Destination enabled is false.
  • URL not publicly reachable.
  • Destination auto-disabled after repeated failures.
  • Event not in subscribed_events.
Fix.
  • Send a test event: Webhook destinations → [destination] → Send test.
  • Check recent deliveries: Webhooks → [destination] → Deliveries. See 4xx/5xx responses with body/headers.
  • Re-enable disabled destinations.

Currency conversion looks wrong

Symptom. amount_in_default_currency doesn’t match your expected rate. Causes.
  • FX rate is the mid-market rate at txn_date.
  • Backdated transactions use the historical rate at that date.
  • Some currencies (exotic FX) have coarser update intervals.
Fix.
  • Use amount and currency (native) for display.
  • Use amount_in_default_currency only for internal rule thresholding.
  • For audit, the transaction record pins the conversion rate used at evaluation time.

Counterparty not matching my blocklist

Symptom. You blocklisted a business by vendor_data, but a transaction with that counterparty still went through. Causes.
  • Counterparty in the transaction payload has no vendor_data — stored as external snapshot.
  • vendor_data casing differs.
Fix.
  • Always pass counterparty.vendor_data when the counterparty is an entity on your platform.
  • Use the same casing everywhere — vendor_data is case-sensitive.

AWAITING_USER transactions stuck

Symptom. Transactions are stuck in AWAITING_USER because the user never completes the remediation session. Causes.
  • User didn’t open the remediation session URL.
  • Remediation session expired.
Fix.
  • The transaction response’s remediation_session_url is the link to deliver. Re-deliver to the user.
  • Remediation sessions follow the same KYC quickstart pattern — subscribe to completion webhooks.
  • Set a timeout in your own system to expire stale transactions if remediation never completes.

Rate limit on create

Symptom. 429 Too Many Requests during high-volume bursts. Fix.
  • Respect the Retry-After header.
  • Throttle client-side for burst traffic.
  • Contact support for higher limits on proven production volume.
See rate limiting.

Next steps

Integration guide

Full integration patterns.

Rules

How rule evaluation works.

Webhooks

Webhook mechanics.