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_iddeterministically on your side (e.g. use your own transaction DB ID). - Compare the response’s
transaction_idwith what you expect; if the response’screated_atdoesn’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 inrule_runs[] with matched: true.
Causes and fixes.
- Rule mode is
DISABLEDorTEST— check Rules → [rule] → Mode. OnlyACTIVErules contribute to scoring;TESTrules evaluate but don’t affect status. - Scope filter excludes the transaction — e.g. scope set to
transaction_type = financewon’t matchtravelRuletransactions. - 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_codebut 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.
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
scopefilters to narrow applicability (e.g. only outbound, only certain transaction types). - Raise thresholds (amounts, velocity counts).
- Put the rule in
TESTmode for a week — analyze therule_runsto see the match rate and tighten conditions before re-enabling.
AML screening timed out
Symptom. Transaction completed withstatus: 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).
- 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’sapplicant.ip_enrichment is absent or partial.
Causes.
- No
applicant.device.ipin the submission. - IP is private / reserved (not routable).
- All enrichment providers were temporarily unavailable.
- 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.
- 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
enabledisfalse. - URL not publicly reachable.
- Destination auto-disabled after repeated failures.
- Event not in
subscribed_events.
- 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.
- Use
amountandcurrency(native) for display. - Use
amount_in_default_currencyonly 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 byvendor_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_datacasing differs.
- Always pass
counterparty.vendor_datawhen the counterparty is an entity on your platform. - Use the same casing everywhere —
vendor_datais case-sensitive.
AWAITING_USER transactions stuck
Symptom. Transactions are stuck inAWAITING_USER because the user never completes the remediation session.
Causes.
- User didn’t open the remediation session URL.
- Remediation session expired.
- The transaction response’s
remediation_session_urlis 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-Afterheader. - Throttle client-side for burst traffic.
- Contact support for higher limits on proven production volume.
Next steps
Integration guide
Full integration patterns.
Rules
How rule evaluation works.
Webhooks
Webhook mechanics.