> ## 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.

# Decisions

> Request a compliance decision and retrieve past decisions.

The decision engine evaluates an investor and wallet against a policy and returns an `"allow"`, `"deny"`, or `"review"` verdict. Every decision is stored immutably and can be retrieved by its `audit_id`.

<Warning>
  All requests to these endpoints require a valid API key in the `Authorization` header.
</Warning>

***

## Request a decision

<code>POST /v1/decisions</code>

Runs a compliance check by evaluating the investor, wallet, and policy you specify. The engine applies the following rules in order:

| Priority | Condition                                                                   | Decision                                  |
| -------- | --------------------------------------------------------------------------- | ----------------------------------------- |
| 1        | Wallet `screening_status` is `"blocked"`                                    | `deny` — `wallet_blocked`                 |
| 2        | Investor `kyc_status` is not `"verified"`                                   | `review` — `kyc_not_verified`             |
| 3        | Policy `requires_accredited` is `true` and investor is not accredited       | `deny` — `not_accredited`                 |
| 4        | Policy `allowed_countries` is non-empty and investor's country is not in it | `deny` — `country_not_allowed`            |
| 5        | Policy `wallet_must_be_verified` is `true` and wallet is not `"verified"`   | `review` — `wallet_not_verified`          |
| 6        | All checks pass                                                             | `allow` — `policy_requirements_satisfied` |

### Request body

<ParamField path="investor_id" type="string" required>
  The ID of the investor to evaluate. Returns `404` if not found.
</ParamField>

<ParamField path="wallet_id" type="string" required>
  The ID of the wallet to evaluate. Returns `404` if not found.
</ParamField>

<ParamField path="asset_policy_id" type="string" required>
  The ID of the policy to evaluate against. Returns `404` if not found.
</ParamField>

<ParamField path="action" type="string" required>
  A label describing the action being attempted (e.g. `"transfer"`, `"mint"`, `"redeem"`). Stored for audit purposes.
</ParamField>

### Response fields

<ResponseField name="decision" type="string">
  The outcome of the compliance check: `"allow"`, `"deny"`, or `"review"`.
</ResponseField>

<ResponseField name="reasons" type="string[]">
  An array of reason codes explaining the decision. Possible values: `"policy_requirements_satisfied"`, `"wallet_blocked"`, `"kyc_not_verified"`, `"not_accredited"`, `"country_not_allowed"`, `"wallet_not_verified"`.
</ResponseField>

<ResponseField name="audit_id" type="string">
  The unique ID of this decision record. Format: `dec_...`. Use this to retrieve the decision later with `GET /v1/decisions/:id`.
</ResponseField>

<ResponseField name="policy_version" type="string">
  The version of the decision engine used. Always `"v1"`.
</ResponseField>

<ResponseField name="timestamp" type="string">
  ISO 8601 timestamp of when the decision was made.
</ResponseField>

### Examples

<CodeGroup>
  ```bash allow theme={null}
  # inv_seed_001: verified, accredited, US — wal_seed_001: verified, low-risk
  curl -X POST https://clearlayer-api-production.up.railway.app/v1/decisions \
    -H "Authorization: Bearer cl_test_key_1234567890" \
    -H "Content-Type: application/json" \
    -d '{
      "investor_id": "inv_seed_001",
      "wallet_id": "wal_seed_001",
      "asset_policy_id": "pol_seed_001",
      "action": "transfer"
    }'
  ```

  ```bash deny theme={null}
  # inv_seed_003: verified, accredited, US — wal_seed_003: blocked
  curl -X POST https://clearlayer-api-production.up.railway.app/v1/decisions \
    -H "Authorization: Bearer cl_test_key_1234567890" \
    -H "Content-Type: application/json" \
    -d '{
      "investor_id": "inv_seed_003",
      "wallet_id": "wal_seed_003",
      "asset_policy_id": "pol_seed_001",
      "action": "transfer"
    }'
  ```

  ```bash review theme={null}
  # inv_seed_002: KYC pending — wal_seed_002: pending
  curl -X POST https://clearlayer-api-production.up.railway.app/v1/decisions \
    -H "Authorization: Bearer cl_test_key_1234567890" \
    -H "Content-Type: application/json" \
    -d '{
      "investor_id": "inv_seed_002",
      "wallet_id": "wal_seed_002",
      "asset_policy_id": "pol_seed_001",
      "action": "transfer"
    }'
  ```
</CodeGroup>

**201 — Allow** (investor and wallet pass all policy checks)

```json theme={null}
{
  "decision": "allow",
  "reasons": ["policy_requirements_satisfied"],
  "audit_id": "dec_q3r4s5t6u7v8",
  "policy_version": "v1",
  "timestamp": "2024-01-15T10:35:00.000Z"
}
```

**201 — Deny** (wallet is blocked — first check triggers immediately)

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

**201 — Review** (investor KYC is pending, manual review required)

```json theme={null}
{
  "decision": "review",
  "reasons": ["kyc_not_verified"],
  "audit_id": "dec_c5d6e7f8g9h0",
  "policy_version": "v1",
  "timestamp": "2024-01-15T10:37:00.000Z"
}
```

***

## Retrieve a decision

<code>GET /v1/decisions/:id</code>

Retrieves a previously recorded decision by its `audit_id`. The response includes an immutable snapshot of the investor, wallet, and policy state at the time the decision was made.

### Path parameters

<ParamField path="id" type="string" required>
  The `audit_id` returned from `POST /v1/decisions`.
</ParamField>

### Response fields

<ResponseField name="id" type="string">
  The decision record ID. Format: `dec_...`
</ResponseField>

<ResponseField name="investor_id" type="string">
  The ID of the investor evaluated.
</ResponseField>

<ResponseField name="wallet_id" type="string">
  The ID of the wallet evaluated.
</ResponseField>

<ResponseField name="asset_policy_id" type="string">
  The ID of the policy used.
</ResponseField>

<ResponseField name="action" type="string">
  The action label provided at decision time.
</ResponseField>

<ResponseField name="decision" type="string">
  `"allow"`, `"deny"`, or `"review"`.
</ResponseField>

<ResponseField name="reasons" type="string[]">
  Reason codes for the decision outcome.
</ResponseField>

<ResponseField name="policy_version" type="string">
  Always `"v1"`.
</ResponseField>

<ResponseField name="created_at" type="string">
  ISO 8601 timestamp of when the decision was recorded.
</ResponseField>

<ResponseField name="input_snapshot" type="object">
  An immutable snapshot of the investor, wallet, and policy data used to reach the decision. This does not reflect any subsequent changes to those records.

  <Expandable title="properties">
    <ResponseField name="input_snapshot.investor" type="object">
      Snapshot of the investor at decision time.

      <Expandable title="properties">
        <ResponseField name="input_snapshot.investor.id" type="string">
          Investor ID.
        </ResponseField>

        <ResponseField name="input_snapshot.investor.kyc_status" type="string">
          KYC status at decision time.
        </ResponseField>

        <ResponseField name="input_snapshot.investor.accredited_status" type="boolean">
          Accreditation status at decision time.
        </ResponseField>

        <ResponseField name="input_snapshot.investor.country" type="string">
          2-letter ISO country code at decision time.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="input_snapshot.wallet" type="object">
      Snapshot of the wallet at decision time.

      <Expandable title="properties">
        <ResponseField name="input_snapshot.wallet.id" type="string">
          Wallet ID.
        </ResponseField>

        <ResponseField name="input_snapshot.wallet.screening_status" type="string">
          Screening status at decision time.
        </ResponseField>

        <ResponseField name="input_snapshot.wallet.risk_level" type="string">
          Risk level at decision time.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="input_snapshot.policy" type="object">
      Snapshot of the policy at decision time.

      <Expandable title="properties">
        <ResponseField name="input_snapshot.policy.id" type="string">
          Policy ID.
        </ResponseField>

        <ResponseField name="input_snapshot.policy.requires_kyc" type="boolean">
          Whether KYC was required.
        </ResponseField>

        <ResponseField name="input_snapshot.policy.requires_accredited" type="boolean">
          Whether accreditation was required.
        </ResponseField>

        <ResponseField name="input_snapshot.policy.allowed_countries" type="string[]">
          Country allowlist in effect at decision time.
        </ResponseField>

        <ResponseField name="input_snapshot.policy.wallet_must_be_verified" type="boolean">
          Whether wallet verification was required.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

### Example

<CodeGroup>
  ```bash curl theme={null}
  curl https://clearlayer-api-production.up.railway.app/v1/decisions/dec_q3r4s5t6u7v8 \
    -H "Authorization: Bearer cl_test_key_1234567890"
  ```
</CodeGroup>

### 200 — OK

```json theme={null}
{
  "id": "dec_q3r4s5t6u7v8",
  "investor_id": "inv_a1b2c3d4e5f6",
  "wallet_id": "wal_g7h8i9j0k1l2",
  "asset_policy_id": "pol_m3n4o5p6q7r8",
  "action": "transfer",
  "decision": "allow",
  "reasons": ["policy_requirements_satisfied"],
  "policy_version": "v1",
  "created_at": "2024-01-15T10:35:00.000Z",
  "input_snapshot": {
    "investor": {
      "id": "inv_a1b2c3d4e5f6",
      "kyc_status": "verified",
      "accredited_status": true,
      "country": "US"
    },
    "wallet": {
      "id": "wal_g7h8i9j0k1l2",
      "screening_status": "verified",
      "risk_level": "low"
    },
    "policy": {
      "id": "pol_m3n4o5p6q7r8",
      "requires_kyc": true,
      "requires_accredited": true,
      "allowed_countries": ["US"],
      "wallet_must_be_verified": true
    }
  }
}
```

### 404 — Not found

```json theme={null}
{
  "error": "not_found",
  "message": "decision dec_notexist not found",
  "docs": "/decisions"
}
```
