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

# Control Withdrawals with Spending Rules

> Set which outgoing transactions go ahead automatically, which need approval, and how much can be sent, per destination and time period.

Spending rules control the money leaving your sub-account. Each rule says who it applies to, where the funds are going, how much can be sent, and whether a transaction goes ahead on its own or waits for approval.

> [!WARNING]
>
> By default, outgoing transactions are blocked. A transaction only goes ahead if an active spending rule allows it, so set up rules before you send your first withdrawal.

You can set rules for each wallet and for each sub-account, and manage them in the Finrock dashboard or with the API. For every API field, see [Create Spending Rule](https://apidocs.finrock.io/api-reference/spending-rules/create-spending-rule.md) and [Spending Rule Values](https://apidocs.finrock.io/reference/spending-rule-values.md).

## What a rule is made of

| Part | Field | Example |
| - | - | - |
| Who it applies to | `initiated_by` | `API` for your API users, `Admin` for dashboard admins, or `Anyone` |
| Where funds go | `destination_type` | `External`, `Internal`, `SubAccount` or `Exchange`. See [Transaction Types](https://apidocs.finrock.io/reference/transaction-types.md#destination_type). |
| Which external addresses | `destination_id` | For `External`: `WhitelistedAddress` or `AdhocAddress` |
| Which addresses exactly | `external_address` | For whitelisted rules, the ID of a [whitelist](https://apidocs.finrock.io/guides/whitelist-addresses.md). For ad-hoc rules, one address outside Finrock, or any address. For `SubAccount` destinations, the sub-account's ID. |
| How much | `amount` | The maximum USD value allowed |
| Over what period | `rule_type`, `time_period_frequency` | `PerTransaction` (one-time, each transaction), or `Hourly` with a number of hours, such as `24` |
| What happens | `sr_action`, `minimum_approvals` | `Allow`, or `NeedsApproval` with the number of approvals needed |

## Who does what

Three kinds of users take part in spending:

| User | Role in spending |
| - | - |
| **Owners** | Set up spending rules, and approve rule changes. |
| **Admins** | Approve outgoing transactions that need approval. At least 2 admins together can also approve rule changes. |
| **Approvers** | Approve outgoing transactions that need approval. |

Admins and approvers approve transactions in the **Finrock mobile app**. When a rule's `sr_action` is `NeedsApproval`, `minimum_approvals` sets how many of these approvals a transaction needs before it goes ahead.

## Every rule change needs approval

Creating or deleting a rule doesn't take effect straight away. The owner, or at least 2 admins, must approve it in the dashboard first.

| Status | What it means |
| - | - |
| `UnApproved` | You created the rule, and it's waiting for approval. |
| `Active` | The rule was approved, and it's in effect. |
| `Rejected` | The rule was rejected. |
| `AwaitingDeleteApproval` | You asked to delete it, and the deletion is waiting for approval. |
| `Deleted` | The rule is gone. |

Check a rule's status at any time with [List Spending Rules](https://apidocs.finrock.io/api-reference/spending-rules/list-spending-rules.md).

## Create a rule in the dashboard

**1. Open Spending Rules**

In the Finrock dashboard, go to **Policy** and select **Spending Rules**. The list shows each rule's title, description and status.

**2. Add a rule**

Click **Add Rules**. The form shows which sub-account the rule is for, for example **Main Account**.

**3. Fill in the rule**

* **Initiator:** who the rule applies to.
* **Rule Title:** a name you'll recognise.
* **Destination:** where funds are going.
* **Rule Type:** one-time (each transaction), or hourly (over a time window).
* **Maximum Amount (USD):** the most the rule allows.
* **Action:** allow the transaction, or require approval.

**4. Check the summary and get approval**

Click **Continue**. Finrock shows a plain-English sentence describing the rule you're creating. Check it says what you intend, then confirm. The rule appears as **Unapproved** until the owner, or at least 2 admins, approve it.

## Create a rule with the API

These examples show common rules. Each one is a `POST /dac/v1/spending-rule` request from your server.

> [tab] Allow small payouts
>
> Let your app pay out up to 500 USD per transaction to any address your customers give, without approval. Use this on a sub-account with [ad-hoc addresses](https://apidocs.finrock.io/guides/ad-hoc-addresses.md) turned on.
>
> ```bash cURL theme={null}
> curl --request POST \
>      --url https://api.finrock.io/dac/v1/spending-rule \
>      --header 'Authorization: Bearer {JWT}' \
>      --header 'accept: application/json' \
>      --header 'content-type: application/json' \
>      --header 'x-api-key: YOUR_API_KEY' \
>      --data '{
>        "rule_title": "Customer payouts",
>        "amount": 500,
>        "initiated_by": "API",
>        "sr_action": "Allow",
>        "destination_type": "External",
>        "destination_id": "AdhocAddress",
>        "rule_type": "PerTransaction",
>        "time_period_frequency": 0
>      }'
> ```

> [tab] Require approval
>
> Require 2 approvals for ad-hoc payouts, with up to 10,000 USD in any 24-hour window.
>
> ```bash cURL theme={null}
> curl --request POST \
>      --url https://api.finrock.io/dac/v1/spending-rule \
>      --header 'Authorization: Bearer {JWT}' \
>      --header 'accept: application/json' \
>      --header 'content-type: application/json' \
>      --header 'x-api-key: YOUR_API_KEY' \
>      --data '{
>        "rule_title": "Large payouts need approval",
>        "amount": 10000,
>        "initiated_by": "Anyone",
>        "sr_action": "NeedsApproval",
>        "minimum_approvals": 2,
>        "destination_type": "External",
>        "destination_id": "AdhocAddress",
>        "rule_type": "Hourly",
>        "time_period_frequency": 24
>      }'
> ```

> [tab] Cold wallet transfers
>
> Allow transfers to the addresses on your `Cold storage` whitelist, up to 50,000 USD per transaction. Create the whitelist first, then pass its ID as `external_address`. See [Whitelist Addresses](https://apidocs.finrock.io/guides/whitelist-addresses.md).
>
> ```bash cURL theme={null}
> curl --request POST \
>      --url https://api.finrock.io/dac/v1/spending-rule \
>      --header 'Authorization: Bearer {JWT}' \
>      --header 'accept: application/json' \
>      --header 'content-type: application/json' \
>      --header 'x-api-key: YOUR_API_KEY' \
>      --data '{
>        "rule_title": "Move to cold storage",
>        "amount": 50000,
>        "initiated_by": "Admin",
>        "sr_action": "Allow",
>        "destination_type": "External",
>        "destination_id": "WhitelistedAddress",
>        "external_address": "f59efb58-1891-4b21-9514-5d37a36cb415",
>        "rule_type": "PerTransaction",
>        "time_period_frequency": 0
>      }'
> ```

A successful request returns `{"code": 1000}`. The new rule starts as `UnApproved` until the owner, or at least 2 admins, approve it.

## How Finrock picks a rule

When you [send a transaction](https://apidocs.finrock.io/guides/send-transaction.md), Finrock finds every active rule that covers it, then applies one of them.

### Which rules cover a transaction

A rule covers a transaction only when all of these are true:

* **The initiator matches.** `Anyone` covers everyone. `API` covers API users. `Admin` covers admins and owners.
* **The destination matches.**
  * `External`: the rule covers any address (`Any`), or the address is on the rule's active whitelist. The asset and the destination tag must match too. An ad-hoc rule that covers `Any` address also covers addresses on your whitelists, so it can compete with your whitelist rules.
  * `SubAccount`: the transaction goes to that specific sub-account.
  * `Exchange`: the transaction goes to that exchange account.
* **The amount fits.** The transaction's USD value is within the rule's limit. For an `Hourly` rule, this transaction plus the earlier withdrawals in the same window must fit within the limit.

### The rule with the lowest limit wins

Of the rules that cover a transaction, Finrock applies the one with the **smallest amount**, whatever its action. If two rules have the same amount, the one needing fewer approvals wins, so `Allow` beats `NeedsApproval`.

The rule it applies decides what happens:

* `Allow`: the transaction goes ahead.
* `NeedsApproval`: the transaction waits with status `NeedsApproval` until enough admins or approvers approve it in the Finrock mobile app. It then moves to `Processing`, or to `Rejected` if it's turned down.

For example, with an `Allow` rule up to 500 USD and a `NeedsApproval` rule up to 10,000 USD:

| Withdrawal | Rules that cover it | Result |
| - | - | - |
| 300 USD | Both | `Allow` has the lower limit, so it's sent without approval. |
| 2,000 USD | `NeedsApproval` only | Needs approval. |
| 20,000 USD | None | Refused with `SPENDING_RULE_VIOLATION`. |

> [!WARNING]
>
> The narrowest rule wins, not the strictest. If you swap the example above, so that `NeedsApproval` covers up to 500 USD and `Allow` covers up to 10,000 USD, then a 300 USD withdrawal needs approval but a 2,000 USD withdrawal goes out automatically. Check how your rules overlap before you activate them.

> [!NOTE]
>
> Hourly and per-transaction rules compete on the same number. An `Hourly` rule with a 400 USD limit beats a `PerTransaction` `Allow` rule at 500 USD, even though the two limits measure different things.

### No matching rule means refused

If no active rule covers a transaction, it's refused with `SPENDING_RULE_VIOLATION`. It never falls back to needing approval. To allow larger amounts with approval, add a `NeedsApproval` rule with a higher limit.

See [Transaction Statuses](https://apidocs.finrock.io/reference/transaction-statuses.md) for every status.

## Example rule sets by wallet type

These are starting points for the three [wallet security models](https://apidocs.finrock.io/concepts/key-features.md#wallet-security-models-hot-warm-cold). Apply them to the wallet or sub-account that holds those funds, and change the amounts to fit your volumes. Each set is designed so the lowest-limit rule gives the result you'd expect.

> [tab] Hot wallet
>
> Hot wallets sign automatically and handle day-to-day payouts, so the goal is to let your app pay out on its own up to a daily cap, and stop anything bigger for a human check.
>
> | Rule | Initiator | Destination | Rule type | Max amount (USD) | Action |
> | - | - | - | - | - | - |
> | Automated payouts | `API` | External, ad-hoc addresses | Hourly, 24 | 5,000 | Allow |
> | Large payouts | `API` | External, ad-hoc addresses | Per transaction | 25,000 | Needs 2 approvals |
> | Sweep to cold storage | `Admin` | External, `Cold storage` whitelist | Per transaction | 100,000 | Allow |
>
> **What happens:**
>
> * Your app's payouts go out automatically until they total 5,000 USD in any 24 hours.
>
> * After that, or for a single payout above the remaining daily allowance, each payout up to 25,000 USD needs 2 approvals.
>
> * API payouts above 25,000 USD are refused.
>
> * Admins and owners can move up to 100,000 USD at a time to your cold storage addresses without approval.
>
> > [!NOTE]
> >
> > Make the automatic rule `Hourly`, not per transaction. A per-transaction `Allow` rule keeps covering small payouts even after a daily total is reached, so it can't cap your daily spend.

> [tab] Warm wallet
>
> Warm wallets need approval in the Finrock mobile app to sign, and usually hold operating funds. The goal is to pay known partners and top up your hot wallet, with more approvals for bigger amounts. There are no ad-hoc rules, so funds can only go to whitelisted addresses and your own sub-accounts.
>
> | Rule | Initiator | Destination | Rule type | Max amount (USD) | Action |
> | - | - | - | - | - | - |
> | Top up hot wallet | `Admin` | Your hot wallet sub-account | Per transaction | 10,000 | Allow |
> | Partner payments | `Anyone` | External, `Partners` whitelist | Per transaction | 50,000 | Needs 1 approval |
> | Large partner payments | `Admin` | External, `Partners` whitelist | Hourly, 24 | 200,000 | Needs 2 approvals |
>
> **What happens:**
>
> * Admins and owners can top up the hot wallet with up to 10,000 USD at a time without approval.
> * A partner payment up to 50,000 USD needs 1 approval.
> * An admin's partner payment above 50,000 USD needs 2 approvals, up to 200,000 USD in any 24 hours.
> * Anything else is refused.

> [tab] Cold wallet
>
> Cold wallets hold long-term reserves and sign offline. The goal is that nothing leaves without several approvals, and funds can only go to your own warm wallet or a treasury whitelist. There are no `Allow` rules, no `API` rules and no ad-hoc rules.
>
> | Rule | Initiator | Destination | Rule type | Max amount (USD) | Action |
> | - | - | - | - | - | - |
> | Refill warm wallet | `Admin` | Your warm wallet sub-account | Per transaction | 100,000 | Needs 2 approvals |
> | Treasury transfers | `Admin` | External, `Treasury` whitelist | Hourly, 24 | 1,000,000 | Needs 3 approvals |
>
> **What happens:**
>
> * Only admins and owners can move funds out.
>
> * Refilling the warm wallet with up to 100,000 USD at a time needs 2 approvals.
>
> * Transfers to treasury addresses need 3 approvals, up to 1,000,000 USD in any 24 hours.
>
> * Anything else is refused.
>
> > [!NOTE]
> >
> > These approvals come before signing. Cold wallet transactions still need to be signed on your offline device. See [Wallet Types](https://apidocs.finrock.io/concepts/wallet-types.md).

> [!TIP]
>
> Set `minimum_approvals` no higher than the number of admins and approvers who can actually approve. Otherwise matching transactions can never go ahead.

## Delete a rule

In the dashboard, click the delete icon next to the rule. With the API, send the rule's `rule_guid`, from [List Spending Rules](https://apidocs.finrock.io/api-reference/spending-rules/list-spending-rules.md), to `DELETE /dac/v1/spending-rule`. The rule moves to `AwaitingDeleteApproval` until the owner, or at least 2 admins, approve the deletion.

```bash cURL theme={null}
curl --request DELETE \
     --url https://api.finrock.io/dac/v1/spending-rule \
     --header 'Authorization: Bearer {JWT}' \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --header 'x-api-key: YOUR_API_KEY' \
     --data '{
       "rule_guid": "f2f97ab8-f8ed-46eb-ae48-d93533893baf"
     }'
```

## Good practice

> [card] [Pair ad-hoc addresses with limits](https://apidocs.finrock.io/guides/ad-hoc-addresses.md)
>
> Ad-hoc addresses let funds go to any address. Always cap them with a spending rule and require approval for large amounts.

> [card] Limit API users
>
> Use `initiated_by: API` for rules meant for your app, so automated payouts get their own limits.

> [card] Use a time window
>
> An `Hourly` rule caps the total sent over a window, which a per-transaction limit alone can't do.

> [card] [Screen addresses too](https://apidocs.finrock.io/guides/aml-compliance.md)
>
> Combine spending rules with AML screening so risky counterparties are blocked before funds move.


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