Transaction Anomalies

A transaction anomaly is a situation where a transaction's recorded status conflicts with later information received from the payment provider. For example, a transaction may be marked FAILED while the provider later confirms it was actually successful. MoneyHash detects these mismatches in near real time and notifies you so your systems can react.

This page covers the developer-facing parts of the feature: the webhooks MoneyHash sends when an anomaly is detected and resolved, and the API for reading a transaction's resolution history.


Key concepts

A few terms used throughout this page:

  • Transaction anomaly - a conflict between a transaction's recorded status and later provider information.
  • Provider pull - a direct request to the provider to retrieve the latest transaction status. In cases such as a post-success failure signal, the provider pull is treated as the source of truth. A conflicting webhook alone does not confirm that a transaction failed.
  • Resolution - the action taken to close an anomaly, either by correcting the transaction status or by marking the anomaly resolved without a status change.

There are three anomaly types, carried in the anomaly_type field: post_failure_success, duplicate_success, and post_success_failure.


Webhooks

MoneyHash can notify you the moment an anomaly is detected and again when it is resolved.

These webhooks are enabled on request

Anomaly webhooks are not sent by default. Contact the MoneyHash team to enable them for your account.

Anomaly detected

When an anomaly is detected, MoneyHash sends a transaction.anomaly_detected webhook with the anomaly details. This fires for every anomaly, regardless of how it is later resolved or whether automation is turned on.

{
  "type": "transaction.anomaly_detected",
  "data": {
    "anomaly_id": "K9x7pQa",
    "transaction_id": "1f7f4df8-3e4f-4d91-9c3f-2c8a6e8f91b2",
    "anomaly_type": "post_failure_success",
    "severity": "critical",
    "detected_at": "2026-06-02T09:15:30.123456+00:00",
    "mh_status": "FAILED",
    "provider_reported_status": "SUCCESS",
    "provider_evidence": {
      "status": "SUCCESS",
      "provider_reference": "abc123",
      "amount": 1000,
      "currency": "EGP"
    }
  }
}
About provider_evidence

The provider_evidence object contains the raw provider evidence stored by MoneyHash. Its structure may vary depending on the provider.

Resolving the anomaly

Once you receive a transaction.anomaly_detected webhook, you can resolve the anomaly programmatically using the Resolve Anomaly API.

Anomaly resolved

When an anomaly is resolved, MoneyHash sends a transaction.anomaly_resolved webhook. This fires regardless of how the anomaly was resolved, whether from the dashboard, through the API, or by an automation rule.

{
  "type": "transaction.anomaly_resolved",
  "data": {
    "anomaly_id": "K9x7pQa",
    "transaction_id": "1f7f4df8-3e4f-4d91-9c3f-2c8a6e8f91b2",
    "anomaly_type": "post_failure_success",
    "resolution_action": "CORRECT_STATUS",
    "resolved_at": "2026-06-02T09:22:11.654321+00:00",
    "resolved_by": "[email protected]",
    "original_status": "FAILED",
    "corrected_status": "SUCCESSFUL",
    "resolution_notes": "Provider confirmed the payment succeeded; MoneyHash status corrected."
  }
}
Handle a status change that arrives after you treated the transaction as final

If a merchant automates the Correct Status action, this webhook is how your systems learn that a transaction's status has moved, for example from FAILED to SUCCESSFUL. Make sure your webhook handling can process a status change that arrives after you already considered the transaction complete.

Correcting the status does not issue a refund. It brings the MoneyHash record in line with the provider so the transaction becomes refundable. Whether to refund remains your decision and is a separate step.


Resolution Trace API

Every resolved anomaly writes a resolution trace on its transaction, recording what action was taken, how it was resolved, and when. You can read a transaction's resolution traces with the endpoint below.

Endpoint

GET https://web.moneyhash.io/api/v1.4/payments/transactions/{transaction_id}/resolution-traces/

Headers

Pass your API key in the X-API-Key header:

accept: application/json
X-API-Key: <your-api-key>

Response

The data field is an array, since a transaction can have more than one resolution trace. When a transaction has no resolution traces, data is an empty array.

{
  "status": {
    "code": 200,
    "message": "success",
    "errors": []
  },
  "data": [
    {
      "id": "wA9eY9m",
      "anomaly_id": "zgEQ6jg",
      "anomaly_type": "post_success_failure",
      "action_taken": "MARK_RESOLVED",
      "previous_status": "SUCCESSFUL",
      "new_status": "SUCCESSFUL",
      "resolution_method": "DASHBOARD",
      "anomaly_type_config_id": null,
      "anomaly_type_name": null,
      "rule_id": null,
      "rule_name": null,
      "resolved_by": {
        "id": 300,
        "email": "[email protected]"
      },
      "notes": "",
      "resolved_at": "2026-09-15T14:39:47.398189Z"
    }
  ]
}

Fields

FieldDescription
idThe ID of the resolution trace.
anomaly_idThe ID of the anomaly this trace resolved.
anomaly_typeThe anomaly type: post_failure_success, duplicate_success, or post_success_failure.
action_takenThe action applied to resolve the anomaly, for example CORRECT_STATUS or MARK_RESOLVED.
previous_statusThe transaction status before resolution.
new_statusThe transaction status after resolution. For a mark-resolved action, this matches previous_status.
resolution_methodHow the anomaly was resolved: DASHBOARD, API, or RULE.
anomaly_type_config_idFor a rule-based resolution, the ID of the anomaly type configuration. null otherwise.
anomaly_type_nameFor a rule-based resolution, the name of the anomaly type configuration. null otherwise.
rule_idFor a rule-based resolution, the ID of the rule that decided it. null otherwise.
rule_nameFor a rule-based resolution, the name of the rule that decided it. null otherwise.
resolved_byFor a dashboard resolution, the user who resolved it, as an id and email.
notesAny notes recorded with the resolution.
resolved_atWhen the anomaly was resolved.
Manual Review writes no trace

When an anomaly is left for manual review, no resolution trace is written yet. A trace is created later, once a person resolves the anomaly.

A corrected status cannot be undone

Once a transaction's status has been corrected, it cannot be reverted, whether the correction came from a rule, the API, or the dashboard.

Anomalies cannot be tested in sandbox

Anomaly detection cannot be replicated in the sandbox environment, as these are edge cases. This path cannot be tested there.


Common errors and troubleshooting

The resolution trace endpoint returns an empty array.
A transaction only has resolution traces once one of its anomalies has been resolved. If the anomaly is still open or was left for manual review, no trace exists yet. An empty data array is the expected response in that case, not an error.

A transaction's status changed after I treated it as final.
This is expected when a merchant has automation enabled. An automated Correct Status resolution updates the transaction and fires transaction.anomaly_resolved. Your webhook handling should be able to process a status change that arrives after you considered the transaction complete.


Related pages

  • Webhooks - how MoneyHash delivers webhook notifications to your backend.
  • Payment Webhook - payment webhook structure and examples.

Did this page help you?