> ## Documentation Index
> Fetch the complete documentation index at: https://docs.corsa.finance/llms.txt
> Use this file to discover all available pages before exploring further.

# Halting transactions

> Automatically freeze suspicious transactions in real time using rule-based halt actions, then release them after analyst review.

Corsa can automatically **freeze** a transaction when a monitoring rule matches, preventing it from settling until a compliance analyst reviews the associated alert. This page explains how the halting mechanism works, the difference between synchronous and asynchronous evaluation, and how frozen transactions move through status changes.

***

## How halting works

When you create a rule, you choose one of two response modes:

* **Alert only** -- Create an alert for analyst review. The transaction proceeds normally.
* **Alert + Halt transaction** -- Create an alert **and** freeze the transaction until it is explicitly released.

When a rule with the `HALT_TRANSACTION` action matches a transaction, the evaluation returns a **FREEZE** decision. If multiple rules match, the final decision is `FREEZE` if **any** matching rule includes a halt action.

***

## Evaluation modes

Corsa supports two ways to evaluate transactions against your rules. The key difference is **who acts on the decision**.

### Asynchronous evaluation (automatic)

This is the default mode for production transaction monitoring. When you [ingest a transaction](/api/ingesting-operations) through the API, Corsa automatically evaluates it against all active rules in the background.

If a rule with `HALT_TRANSACTION` matches:

1. The transaction status is set to **FROZEN**.
2. A compliance alert is created with the highest priority from all matching rules.
3. The alert includes metadata indicating the transaction was halted.

No additional integration is needed -- halting happens automatically as part of the ingestion pipeline.

### Synchronous evaluation (on-demand)

You can evaluate a transaction on demand by calling the evaluation endpoint directly:

**Endpoint:** `POST /v1/evaluation/evaluate`

<CodeGroup>
  ```json REST API theme={null}
  POST /v1/evaluation/evaluate
  Content-Type: application/json

  {
    "transactionId": "txn-uuid-123",
    "transactionData": {
      "amount": 75000,
      "currency": "USD",
      "type": "WITHDRAW",
      "clientId": "client-uuid-123"
    }
  }
  ```

  ```typescript SDK theme={null}
  const result = await corsa.evaluation.evaluate({
    transactionId: "txn-uuid-123",
    transactionData: {
      amount: 75000,
      currency: "USD",
      type: "WITHDRAW",
      clientId: "client-uuid-123",
    },
  });

  if (result.decision === "FREEZE") {
    // Hold the transaction on your side
  }
  ```

  ```python Python SDK theme={null}
  from corsa_sdk.api.evaluation.evaluate import _get_kwargs
  from corsa_sdk.models.evaluation_request_dto import EvaluationRequestDto

  resp = http.request(**_get_kwargs(
      body=EvaluationRequestDto(
          transaction_id="txn-uuid-123",
          transaction_data={
              "amount": 75000,
              "currency": "USD",
              "type": "WITHDRAW",
              "clientId": "client-uuid-123",
          },
      ),
  ))
  result = resp.json()

  if result["decision"] == "FREEZE":
      # Hold the transaction on your side
      pass
  ```
</CodeGroup>

The response includes a `decision` field:

| Decision | Meaning                                                                             |
| -------- | ----------------------------------------------------------------------------------- |
| `ALLOW`  | No matching rule requires halting. The transaction can proceed.                     |
| `FREEZE` | At least one matching rule includes a halt action. You should hold the transaction. |

<Note>In synchronous mode, Corsa returns the decision but does **not** automatically freeze the transaction. Your system is responsible for acting on the `FREEZE` decision -- for example, by holding settlement until the alert is resolved.</Note>

### Synchronous evaluation (inline on ingest)

You can evaluate a transaction during ingestion by setting `evaluateSynchronously: true` on the transaction object within a deposit, withdrawal, or trade request. The response includes an `evaluationResult` field with the rule-engine decision, matched rules, and action outcomes.

Unlike the on-demand endpoint above, inline sync evaluation **automatically freezes** the transaction when the decision is `FREEZE` -- you do not need to handle the status change yourself.

<CodeGroup>
  ```json REST API theme={null}
  POST /v1/operations/deposits?upsert=true
  Content-Type: application/json

  {
    "referenceId": "DEP-2024-100",
    "initiatedBy": "123e4567-e89b-12d3-a456-426614174000",
    "initiatedAt": "2024-06-15T08:30:00Z",
    "depositTransaction": {
      "referenceId": "TX-BLOCK-100",
      "amount": {
        "amount": 75000,
        "currency": "USD"
      },
      "from": {
        "walletAddress": "0xSourceWallet..."
      },
      "to": {
        "walletAddress": "0xDepositAddress..."
      },
      "statusHistory": [
        { "type": "PENDING", "timestamp": "2024-06-15T08:30:00Z" }
      ],
      "evaluateSynchronously": true
    }
  }
  ```

  ```typescript SDK theme={null}
  const deposit = await corsa.deposits.createDeposit(
    {
      referenceId: "DEP-2024-100",
      initiatedBy: "123e4567-e89b-12d3-a456-426614174000",
      initiatedAt: "2024-06-15T08:30:00Z",
      depositTransaction: {
        referenceId: "TX-BLOCK-100",
        amount: { amount: 75000, currency: "USD" },
        from: { walletAddress: "0xSourceWallet..." },
        to: { walletAddress: "0xDepositAddress..." },
        statusHistory: [
          { type: "PENDING", timestamp: "2024-06-15T08:30:00Z" },
        ],
        evaluateSynchronously: true,
      },
    },
    true // upsert
  );

  if (deposit.depositTransaction.evaluationResult?.decision === "FREEZE") {
    // Transaction is already frozen in Corsa -- hold settlement on your side
  }
  ```

  ```python Python SDK theme={null}
  from corsa_sdk.api.deposits.create_deposit import _get_kwargs
  from corsa_sdk.models.create_deposit_operation_dto import CreateDepositOperationDto

  resp = http.request(**_get_kwargs(
      body=CreateDepositOperationDto(
          reference_id="DEP-2024-100",
          initiated_by="123e4567-e89b-12d3-a456-426614174000",
          initiated_at="2024-06-15T08:30:00Z",
          deposit_transaction={
              "referenceId": "TX-BLOCK-100",
              "amount": {"amount": 75000, "currency": "USD"},
              "from": {"walletAddress": "0xSourceWallet..."},
              "to": {"walletAddress": "0xDepositAddress..."},
              "statusHistory": [{"type": "PENDING", "timestamp": "2024-06-15T08:30:00Z"}],
              "evaluateSynchronously": True,
          },
      ),
      upsert=True,
  ))
  deposit = resp.json()

  if deposit["depositTransaction"].get("evaluationResult", {}).get("decision") == "FREEZE":
      # Transaction is already frozen in Corsa -- hold settlement on your side
      pass
  ```
</CodeGroup>

#### Evaluation result

When `evaluateSynchronously` is set, the transaction in the response includes an `evaluationResult` object:

| Field                         | Description                                                                                                                                                        |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `decision`                    | `ALLOW` -- no halt rules matched. `FREEZE` -- at least one halt rule matched and the transaction was frozen. `UNKNOWN` -- evaluation failed (see `failureReason`). |
| `matchedRules`                | Array of matched rules, each with `ruleId`, `ruleVersion`, and `ruleName`.                                                                                         |
| `actionsExecuted.haltApplied` | `true` if the transaction was frozen by the evaluation.                                                                                                            |
| `actionFailures`              | Array of action failures, each with `actionType` and `error`. Empty when all actions succeed.                                                                      |
| `failureReason`               | Present only when `decision` is `UNKNOWN`. Either `TIMEOUT` (evaluation took too long) or `ERROR` (evaluation failed).                                             |

<Note>**Fail-open behavior:** If the evaluation times out or encounters an error, the transaction is **not** blocked. The decision is `UNKNOWN` with a `failureReason`, and the transaction proceeds normally. Async evaluation still runs in the background.</Note>

<Note>The `evaluateSynchronously` flag only applies to new creates. When `upsert=true` and a record with the same `referenceId` already exists, the flag is ignored.</Note>

### Choosing the right mode

| Mode                        | When to use                                                                                                                                                                                               |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Async (automatic)**       | Standard production flow. Transactions are ingested and evaluated automatically. Freezing and alert creation happen without additional code.                                                              |
| **Sync (on-demand)**        | Pre-settlement checks where your system needs to make a go/no-go decision before processing a transaction. Your system acts on the decision.                                                              |
| **Sync (inline on ingest)** | Get a rule-engine decision at ingestion time within the same API call. Corsa automatically freezes the transaction on `FREEZE`. Useful when you need a decision before returning a response to your user. |

You can combine modes. For example, use inline sync evaluation for real-time decisions during ingestion, while async evaluation continues to run in the background for ongoing monitoring.

***

## Transaction statuses

Every transaction in Corsa has a status that reflects its current state:

| Status      | Description                                            |
| ----------- | ------------------------------------------------------ |
| `PENDING`   | The transaction is in progress or awaiting processing. |
| `SUCCESS`   | The transaction completed successfully.                |
| `FROZEN`    | The transaction is halted pending compliance review.   |
| `CANCELLED` | The transaction was cancelled.                         |
| `FAILED`    | The transaction failed.                                |

### Status flow for halted transactions

A typical halted transaction follows this path:

1. Transaction is ingested with status **PENDING**.
2. Async evaluation triggers a rule with `HALT_TRANSACTION`.
3. Status changes to **FROZEN**. A compliance alert is created.
4. An analyst reviews the alert and the transaction details.
5. Based on the review, the analyst updates the transaction status:
   * **PENDING** or **SUCCESS** if the transaction is cleared.
   * **CANCELLED** if the transaction should not proceed.

***

## Releasing a frozen transaction

After reviewing the associated alert, update the transaction status to release it:

**Endpoint:** `PUT /v1/transactions/{id}/updateStatus`

<CodeGroup>
  ```json REST API theme={null}
  PUT /v1/transactions/txn-uuid-123/updateStatus
  Content-Type: application/json

  {
    "type": "SUCCESS",
    "reason": "Reviewed and cleared by compliance team"
  }
  ```

  ```typescript SDK theme={null}
  await corsa.transactions.updateTransactionStatus("txn-uuid-123", {
    type: "SUCCESS",
    reason: "Reviewed and cleared by compliance team",
  });
  ```

  ```python Python SDK theme={null}
  from corsa_sdk.api.transactions.update_transaction_status import _get_kwargs
  from corsa_sdk.models.transaction_status_dto import TransactionStatusDto

  resp = http.request(**_get_kwargs(
      id="txn-uuid-123",
      body=TransactionStatusDto(
          type="SUCCESS",
          reason="Reviewed and cleared by compliance team",
      ),
  ))
  ```
</CodeGroup>

The status change is recorded in the transaction's **status history** for audit purposes, including the timestamp and reason.

***

## Configuring halt rules

To add halting to a rule, select **Alert + Halt transaction** in the [Rule Builder](/transaction-monitoring/building-rules#halt-transaction) configure step, or include `HALT_TRANSACTION` in the actions array when creating a rule via API:

```json theme={null}
{
  "actions": [
    {
      "type": "CREATE_ALERT",
      "config": {
        "category": "TRANSACTION_MONITORING",
        "priority": "HIGH",
        "status": "NEW"
      }
    },
    {
      "type": "HALT_TRANSACTION",
      "config": {}
    }
  ]
}
```

<Warning>Halting blocks transaction settlement on every match. Use this for high-confidence rules where false positives are rare, and ensure your team has capacity to review frozen transactions promptly.</Warning>

***

## What's next?

<CardGroup cols={2}>
  <Card title="Building rules" icon="pen-ruler" href="/transaction-monitoring/building-rules">
    Configure halt actions in the Rule Builder wizard.
  </Card>

  <Card title="Conditions reference" icon="code" href="/transaction-monitoring/conditions-reference">
    See all operators, entities, and aggregations available for conditions.
  </Card>

  <Card title="Rules and Evaluation API" icon="square-terminal" href="/transaction-monitoring/rules-api">
    Full API reference for rule management and evaluation.
  </Card>
</CardGroup>
