# Compliance Freezes, Refunds & Reversals

> How Noah handles compliance freezes, refunds and reversals across payin and payout flows, and what each one means for a transaction.

This page explains how Noah handles compliance freezes, refunds, and reversals across payin and payout flows.

## Compliance Freezes

A compliance freeze occurs when a transaction requires Enhanced Due Diligence (EDD) review before proceeding.

### When Freezes Occur

| Flow                       | Freeze Point             | What Happens                                                        |
| -------------------------- | ------------------------ | ------------------------------------------------------------------- |
| **Payin** (Fiat → Crypto)  | `FiatDeposit` stage      | Fiat is received but not converted to crypto until review completes |
| **Payout** (Crypto → Fiat) | `CryptoSettlement` stage | Crypto is received but not converted and paid out until approved    |

### What to Expect During a Freeze

1. **EDD Request**: Noah's Compliance team will request documentation based on your KYC model (Reliance or Standard)
2. **10-Day Window**: Customers have 10 days to provide requested documentation
3. **Resolution**:
   - **Approved**: Funds are unfrozen, converted, and sent to the destination
   - **Rejected**: Transaction is rejected and funds are automatically refunded

## What Triggers Enhanced Due Diligence

EDD can be triggered by transaction-level conditions, customer risk factors, or a combination of both.

### Transaction-Level Triggers

These thresholds are enforced per Virtual Account currency. When a limit is exceeded, the deposit is frozen at the `FiatDeposit` stage pending review.

| Currency | Single-Transaction Limit | Monthly Aggregate Limit | Third-Party Trigger                              |
| -------- | ------------------------ | ----------------------- | ------------------------------------------------ |
| **USD**  | $10,000                  | $20,000                 | Non-family third-party deposits exceeding $5,000 |
| **EUR**  | €15,000                  | €30,000                 | -                                                |

For the full guardrails per currency, including third-party deposit rules, see the respective payin recipe: [USD Guardrails](../recipes/payin/bank-onramp-us.md#guardrails), [EUR Guardrails](../recipes/payin/bank-onramp-eu.md#guardrails).

### Customer Risk Triggers

Noah applies Enhanced Due Diligence on B2B2C customers if:

- The customer is identified as a **Politically Exposed Person (PEP)**
- The customer is from a **FATF or EU high-risk third country**
- The customer is from a **highly corrupt country**
- The customer is from a country with a **weak AML/CTF regime**

All jurisdictions that fall under these categories can be found on the official [FATF](https://www.fatf-gafi.org/), [EU](https://finance.ec.europa.eu/financial-crime/anti-money-laundering-and-countering-financing-terrorism_en), and [CPI](https://www.transparency.org/en/cpi) websites.

Additionally, Noah scores customers based on their:

- **Main source of income** - whether the customer has a regular and reliable source of income
- **Employment status**
- **Industry of employment**
- **Transactional forecasts**

### How to Handle EDD in Your Integration

When EDD is triggered, your system will observe the `FiatDeposit` webhook remaining in `Pending` status beyond normal processing times. The deposit is frozen - no conversion or withdrawal occurs until review completes.

- **Reliance Model**: Noah contacts your compliance team to request documentation (Proof of Source of Funds, full KYC pack, purpose of transaction).
- **Standard Model**: Noah contacts your customer directly via their email address on file (Proof of Source of Funds, purpose of transaction).

Your customer has **10 days** to provide the requested documentation. If approved, the deposit is unfrozen and processing continues. If documents are not provided within the window, the transaction is rejected and funds are automatically refunded.

**UX recommendation**: If a `FiatDeposit` remains in `Pending` status for longer than the expected settlement time for the payment method (see [FiatDeposit Event](./webhooks/fiat-deposits.md#expected-settlement-times)), display a message to your user indicating that their deposit is under review and they may be contacted for additional documentation.

## Refunds

Refunds can happen as a result of an EDD/Compliance rejection.

### Refund Destinations by Flow

| Scenario                                                 | Refund Destination           |
| -------------------------------------------------------- | ---------------------------- |
| **Payin** (Fiat deposit)                                 | Depositing Payment Method    |
| **Payout** (Prefunded dashboard balance)                 | Custodian Stablecoin Account |
| **Payout** (Customer crypto deposit / automated payouts) | Sending Crypto Wallet        |

### Refund Lifecycle

Refunds progress through the following statuses:

| Status       | Description                                 |
| ------------ | ------------------------------------------- |
| `Pending`    | Refund requested, being processed           |
| `Successful` | Funds returned to destination               |
| `Failed`     | Refund could not complete (contact support) |

You will receive `FiatDeposit` webhook updates as the refund status changes. The `Refunds` array in the webhook payload contains the complete refund history.

:::note
The status values above apply to **payin** (`FiatDeposit`) refunds. On **payout** flows, refund entries in a `Transaction` webhook's `Refunds` array use the transaction status set instead — `Pending`, `Settled`, `Failed`.
:::

## Reversals

Reversals are distinct from refunds.

### Key Difference: Refunds vs. Reversals

| Aspect        | Refund                     | Reversal                                 |
| ------------- | -------------------------- | ---------------------------------------- |
| **When**      | Before transaction settles | After transaction has settled            |
| **Trigger**   | EDD/Compliance rejection   | Regulatory or banking-level intervention |
| **Frequency** | Standard process           | Rare                                     |

### Transaction Finality

Noah transactions are processed with **finality** on `Settled` status for both payins and payouts. Once a transaction reaches `Settled`, under normal circumstances the transaction is complete.

### When Reversals Happen

Reversals occur in rare cases, typically where a banking rail returns a payout after it has already settled (for example, a Swift wire return issued by the receiving bank).

When a reversal occurs, Noah automatically creates a **new** transaction that credits the original crypto-asset back to the customer's account. The original transaction is **not** modified — it remains `Settled`. You receive a standard `transaction` webhook event for the new reversal transaction. The `Reverses` field on that transaction contains the ID of the original transaction, which is the signal to treat it as a reversal.

### Reversal Webhook Payload

```json
{
  "EventType": "transaction",
  "EventVersion": 1,
  "Occurred": "2026-06-23T14:00:00Z",
  "UserID": "<user-uuid>",
  "Data": {
    "ID": "<reversal-transaction-uuid>",
    "CryptoCurrency": "USDC",
    "Direction": "In",
    "Network": "OffNetwork",
    "Status": "Settled",
    "Amount": "123.45",
    "RequestedAmount": {
      "FiatCurrency": "USD",
      "Amount": "100.00"
    },
    "Reverses": "<uuid-of-original-sell-transaction>",
    "Created": "2026-06-23T14:00:00Z"
  }
}
```

Key fields on a reversal transaction:

| Field             | Value          | Notes                                                                                               |
| ----------------- | -------------- | --------------------------------------------------------------------------------------------------- |
| `Direction`       | `"In"`         | Crypto credited back to the customer                                                                |
| `Network`         | `"OffNetwork"` | Internal ledger credit — no on-chain movement                                                       |
| `Status`          | `"Settled"`    | Delivered already settled; no intermediate `Pending` state                                          |
| `Reverses`        | UUID           | ID of the original sell/payout transaction — **the key signal that this is a reversal**             |
| `Amount`          | Decimal        | Crypto amount at market rate at time of reversal; may differ from the original send amount          |
| `RequestedAmount` | Object         | The fiat amount returned by the banking rail (e.g. `{ "FiatCurrency": "USD", "Amount": "100.00" }`) |

### Two-Step Reversal Process for Bank Returns

When a banking rail returns a **settled** payout (e.g. a SWIFT wire return), Noah does not modify the original transaction. Instead, the return is processed as **two sequential transactions**:

#### Step 1: Internal Reversal

Noah creates an internal ledger reversal that credits the returned fiat amount back to the customer's account. This is the transaction described in the [Reversal Webhook Payload](#reversal-webhook-payload) above — it carries the `Reverses` field and is `OffNetwork` / `Direction: "In"`.

#### Step 2: On-Chain Crypto Return

After the internal reversal, Noah creates a **second** transaction that sends the crypto-asset back to the customer's original sending wallet on-chain. This transaction carries the `AdjustmentFor` object instead of `Reverses`:

```json
{
  "EventType": "transaction",
  "EventVersion": 1,
  "Occurred": "2026-06-23T15:30:00Z",
  "UserID": "<user-uuid>",
  "Data": {
    "ID": "<crypto-return-transaction-uuid>",
    "CryptoCurrency": "USDC",
    "Direction": "Out",
    "Network": "Ethereum",
    "Status": "Settled",
    "Amount": "123.43",
    "AdjustmentFor": {
      "AdjustedTransactionID": "<uuid-of-original-crypto-deposit>",
      "AdjustmentID": "<uuid-matching-refund-id-on-original>",
      "Reason": "Refund"
    },
    "PublicID": "0xabc123... (on-chain tx hash)",
    "Created": "2026-06-23T15:30:00Z"
  }
}
```

Key fields on the crypto return transaction:

| Field                                 | Value           | Notes                                                                    |
| ------------------------------------- | --------------- | ------------------------------------------------------------------------ |
| `Direction`                           | `"Out"`         | Crypto sent from Noah back to the customer's wallet                      |
| `Network`                             | e.g. `Ethereum` | On-chain network — this is a real blockchain transaction                 |
| `Status`                              | `"Settled"`     | On-chain tx confirmed                                                    |
| `AdjustmentFor.AdjustedTransactionID` | UUID            | ID of the **original crypto deposit** (the inbound leg), not the sell tx |
| `AdjustmentFor.Reason`                | `"Refund"`      | Signals this is a refund of the original deposit                         |
| `PublicID`                            | Hash            | On-chain transaction hash — visible to the customer on the blockchain    |

#### How to Link All Three Transactions

A bank return involves three transactions linked together. Use the `Orchestration.RuleExecutionID` (shared across all legs) or the field references below to correlate them:

| Transaction                              | Key Field                             | Points To                   |
| ---------------------------------------- | ------------------------------------- | --------------------------- |
| Original sell/payout (`Out`, Settled)    | `Refunds[].RefundID`                  | The refund entry on this tx |
| Internal reversal (`In`, OffNetwork)     | `Reverses`                            | Original sell/payout tx     |
| On-chain crypto return (`Out`, on-chain) | `AdjustmentFor.AdjustedTransactionID` | Original crypto deposit tx  |

:::important
**Do not treat `Settled` as purely terminal for payout flows.** A settled payout can still be reversed by a bank return days later. Your integration should handle `Transaction` webhooks with either `Reverses` or `AdjustmentFor.Reason=Refund` by reversing the corresponding entry on your side.
:::

#### Amount Differences

The crypto amount returned on-chain may differ from the original deposit amount. This is expected:

- **Fiat return fees**: The banking rail may deduct return/correspondent-bank fees from the fiat amount before returning it.
- **Market rate at time of return**: The crypto amount is calculated at the market rate at the time of the reversal, not the original exchange rate.
- **Network fees**: On-chain gas fees are deducted from the returned crypto amount.

For example, a 1,234.67 USD payout may return as 1,194.67 USD (after ~40 USD in SWIFT return fees), which converts to a slightly different crypto amount than the original deposit.

## Related Documentation

- [FiatDeposit Event](webhooks/fiat-deposits) Webhook details for payin deposits
- [Transaction Event](webhooks/transactions) Webhook details for payouts
- [Bank Onramp US Guardrails](../recipes/payin/bank-onramp-us#guardrails) Deposit source restrictions and EDD process
- [Bank Onramp EU Guardrails](../recipes/payin/bank-onramp-eu#guardrails) Deposit source restrictions and EDD process
