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

# Environment layer (declarative rules)

> Read and write environment-wide declarative policy rules with the environment layer endpoints.

> [!NOTE]
>
> Declarative rules are in **early access** and are not enabled by default. [Talk to us](https://www.dynamic.xyz/talk-to-us) if you'd like to participate.

These endpoints write environment-wide [declarative rules](https://www.dynamic.xyz/docs/embedded-wallets/mpc/policies/declarative-rules.md). Requests go to `/environments/<environment_id>/...` and authenticate with a developer API token (`<api_token>`) for a user with the Admin role, or with a dashboard login. Writes need the environment settings write scope, and reads need the read scope.

Declarative rules must be enabled for your environment. Until they are, a declarative write returns 403 with `rule_syntax_disabled`.

The legacy environment endpoints on [Creating & Managing Rules](https://www.dynamic.xyz/docs/embedded-wallets/mpc/policies/creating-rules.md) take legacy rules only. With declarative rules you can write the environment layer two ways:

* **One rule at a time** with `PATCH`: add or update a rule, remove a rule, or apply several changes together.
* **The whole list** with `PUT`: send the layer's full rule list, so anything you leave out is removed.

A layer holds legacy rules or declarative rules, never both, so a write that mixes them is refused. Approval rules are refused on the environment layer.

> [!WARNING]
>
> Once the environment layer holds a declarative rule, it is no longer kept in step with the legacy environment policy. Legacy rules created through the legacy environment endpoints stay stored but are no longer enforced. Until then, legacy edits keep overwriting the layer.

## Read the layer

Read the current rules:

```bash theme={"system"}
curl "https://app.dynamicauth.com/api/v0/environments/<environment_id>/waas/policies/env-layer" \
  -H "Authorization: Bearer <api_token>"
```

## Add or update a rule

`PATCH` with `op: "upsert"` adds a rule or updates one in place. Send the rule in `declarativeRule`. `ruleId` is optional: leave it out to create a rule, and the response returns the generated id in `layerContent.rules`. To update a rule, send its `ruleId`.

```bash theme={"system"}
curl -X PATCH \
"https://app.dynamicauth.com/api/v0/environments/<environment_id>/waas/policies/env-layer" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <api_token>" \
-d '{
  "op": "upsert",
  "declarativeRule": {
    "name": "Cap at 5 ETH",
    "phase": "transaction",
    "then": "DENY",
    "when": {
      "exists": {
        "in": "outgoingAssets",
        "where": {
          "all": [
            { "field": "asset.isNative", "op": "eq", "value": true },
            { "field": "totalRawValue", "op": "gt", "value": "5000000000000000000" }
          ]
        }
      }
    }
  }
}'
```

The other rules in the layer are left as they are. For more rules, see [Rule examples](https://www.dynamic.xyz/docs/embedded-wallets/mpc/policies/rule-examples.md).

> [!NOTE]
>
> Both `PATCH` and `PUT` edit a layer that already exists. The environment layer is created automatically, for example when the environment's first wallet is created. Until it exists, both return 404.

## Remove a rule

```bash theme={"system"}
curl -X PATCH \
"https://app.dynamicauth.com/api/v0/environments/<environment_id>/waas/policies/env-layer" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <api_token>" \
-d '{
  "op": "remove",
  "ruleId": "<existing_rule_id>"
}'
```

## Apply several changes at once

`op: "batch"` applies 1 to 100 upserts and removes together. They all succeed or none are applied.

```bash theme={"system"}
curl -X PATCH \
"https://app.dynamicauth.com/api/v0/environments/<environment_id>/waas/policies/env-layer" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <api_token>" \
-d '{
  "op": "batch",
  "operations": [
    {
      "op": "upsert",
      "declarativeRule": {
        "name": "Blocked address",
        "phase": "transaction",
        "then": "DENY",
        "when": {
          "exists": {
            "in": "counterparties",
            "where": { "field": "address", "op": "in", "value": ["0x0000000000000000000000000000000000000bad"] }
          }
        }
      }
    },
    { "op": "remove", "ruleId": "<existing_rule_id>" }
  ]
}'
```

## Replace the whole list

Write the full list with `PUT`, or with `PATCH` and `op: "replace"` and a `rules` array. Any rule you leave out is removed, so keep the `ruleId` of every rule you are keeping. This example blocks one address and caps transactions at 5 ETH.

```bash theme={"system"}
curl -X PUT \
"https://app.dynamicauth.com/api/v0/environments/<environment_id>/waas/policies/env-layer" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <api_token>" \
-d '{
  "rules": [
    {
      "ruleId": "00000000-0000-4000-8000-000000000004",
      "name": "Blocked address",
      "phase": "transaction",
      "then": "DENY",
      "when": {
        "exists": {
          "in": "counterparties",
          "where": { "field": "address", "op": "in", "value": ["0x0000000000000000000000000000000000000bad"] }
        }
      }
    },
    {
      "ruleId": "00000000-0000-4000-8000-000000000001",
      "name": "Cap at 5 ETH",
      "phase": "transaction",
      "then": "DENY",
      "when": {
        "exists": {
          "in": "outgoingAssets",
          "where": {
            "all": [
              { "field": "asset.isNative", "op": "eq", "value": true },
              { "field": "totalRawValue", "op": "gt", "value": "5000000000000000000" }
            ]
          }
        }
      }
    }
  ]
}'
```

## Good to know

* Edits are saved as they arrive and aren't checked against what else changed. If two people edit the environment layer at the same moment, one change can overwrite the other. The account, wallet, and signer layers behave the same way.
* Until the layer holds its first declarative rule, a write to the legacy environment endpoints still overwrites it with the legacy rules. Once it holds a declarative rule, legacy writes leave it alone.

A signed-in end user can read, but not write, the environment layer at `GET /sdk/<environment_id>/waas/env-policy-layer` with their JWT.

## Next steps

> **[Rule examples](https://www.dynamic.xyz/docs/embedded-wallets/mpc/policies/rule-examples.md)**
>
> Ready-made declarative rules.

> **[Creating & Managing Rules](https://www.dynamic.xyz/docs/embedded-wallets/mpc/policies/creating-rules.md)**
>
> The dashboard and the legacy environment API.

> **[Managing layers](https://www.dynamic.xyz/docs/embedded-wallets/mpc/policies/managing-layers.md)**
>
> Account, wallet, and signer layers.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.