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

# Decision Engine

> How Clearlayer evaluates investor and wallet compliance against an asset policy.

The decision engine is the core of Clearlayer. When you submit a decision request, the engine receives an investor, a wallet, and an asset policy — and evaluates them against a fixed set of compliance rules to produce a single outcome. Rules are checked in order; the first rule that matches wins and no further checks run.

## Decision outcomes

<Tabs>
  <Tab title="allow">
    All policy requirements are met. The investor is KYC-verified, accredited (if required), located in an allowed country, and their wallet has passed screening. The transaction can proceed.
  </Tab>

  <Tab title="deny">
    A hard requirement has failed. The transaction is blocked and cannot proceed without resolving the underlying issue — for example, a blocked wallet or an investor who is not accredited.
  </Tab>

  <Tab title="review">
    A soft requirement has failed. The transaction cannot proceed automatically but does not constitute a hard block. Common causes include pending KYC or a wallet that has not yet been screened. Manual review is required before a final decision is made.
  </Tab>
</Tabs>

## Evaluation order

<Note>
  The engine uses a first-match-wins strategy. As soon as one rule triggers, the remaining checks are skipped and the result is returned immediately.
</Note>

| # | Condition                                                                              | Decision | Reason code                     |
| - | -------------------------------------------------------------------------------------- | -------- | ------------------------------- |
| 1 | Wallet `screeningStatus` is `blocked`                                                  | `deny`   | `wallet_blocked`                |
| 2 | Investor `kycStatus` is not `verified`                                                 | `review` | `kyc_not_verified`              |
| 3 | Policy `requiresAccredited` is `true` and investor `accreditedStatus` is `false`       | `deny`   | `not_accredited`                |
| 4 | Policy `allowedCountries` is non-empty and investor `country` is not in the list       | `deny`   | `country_not_allowed`           |
| 5 | Policy `walletMustBeVerified` is `true` and wallet `screeningStatus` is not `verified` | `review` | `wallet_not_verified`           |
| 6 | All checks pass                                                                        | `allow`  | `policy_requirements_satisfied` |

## Reason codes

| Reason code                     | Meaning                                                                            |
| ------------------------------- | ---------------------------------------------------------------------------------- |
| `wallet_blocked`                | The wallet has been flagged during screening and is blocked from transacting.      |
| `kyc_not_verified`              | The investor's KYC status is not `verified` (e.g., still `pending`).               |
| `not_accredited`                | The policy requires accredited investors but this investor is not accredited.      |
| `country_not_allowed`           | The investor's country is not in the policy's `allowed_countries` list.            |
| `wallet_not_verified`           | The policy requires a verified wallet but this wallet has not completed screening. |
| `policy_requirements_satisfied` | All policy requirements passed; no compliance issues found.                        |

## Input snapshot

Every decision stores an immutable snapshot of the investor, wallet, and policy state at the moment the decision was made. This snapshot is returned as the `input_snapshot` field when you retrieve a decision via `GET /v1/decisions/:id`.

The snapshot preserves the exact values that drove the decision, making each decision fully auditable even if the underlying investor, wallet, or policy is later updated.

```json theme={null}
// GET /v1/decisions/:id response
{
  "id": "dec_abc123",
  "investor_id": "inv_seed_001",
  "wallet_id": "wal_seed_001",
  "asset_policy_id": "pol_seed_001",
  "action": "transfer",
  "decision": "allow",
  "reasons": ["policy_requirements_satisfied"],
  "input_snapshot": {
    "investor": {
      "id": "inv_seed_001",
      "kyc_status": "verified",
      "accredited_status": true,
      "country": "US"
    },
    "wallet": {
      "id": "wal_seed_001",
      "screening_status": "verified",
      "risk_level": "low"
    },
    "policy": {
      "id": "pol_seed_001",
      "requires_kyc": true,
      "requires_accredited": true,
      "allowed_countries": ["US"],
      "wallet_must_be_verified": true
    }
  },
  "policy_version": "v1",
  "created_at": "2024-01-15T10:30:00.000Z"
}
```

When you create a decision via `POST /v1/decisions`, the response contains the top-level summary:

```json theme={null}
{
  "decision": "deny",
  "reasons": ["wallet_blocked"],
  "audit_id": "dec_abc123",
  "policy_version": "v1",
  "timestamp": "2024-01-15T10:30:00.000Z"
}
```
