Transactional Policy & Approval Schemes
Koywe’s transactional policy is the layer that decides what happens when a user or API key tries to perform a sensitive money movement. It works the same way most enterprise wallet policies do: you write an ordered list of rules, the first matching rule wins, and that rule says either let it through or require an approval from one or more designated approvers.
This page explains the building blocks at a high level. It is meant for the person who decides who can do what in your organization — not for someone implementing signing libraries. For signing mechanics, see Passkeys & Approvals.
Which Operations Are Subject to Policy
Transactional policy applies to operations that move funds, change a saved destination, or change policy/security configuration. In practice that covers:
- Money movements that have a destination — payouts, offramps, onramps, balance transfers.
- Destination changes — adding, editing, or deleting a saved bank account or wallet address.
- Policy management — changes to the policy itself (adding rules, reordering them, swapping approvers).
If an operation is not in this set, the policy is never consulted and the operation runs as normal.
You only need to think about transactional policy when you want to control who can do what, with how much, and how many people need to sign off. Every new organization is onboarded with a default policy attached to the first super admin — it is good enough for a solo super admin running the whole operation. As soon as you add other operators (humans or API users) or want different controls per merchant, balance, or amount band, the super admin should replace the default with a proper policy designed for your structure.
The Three Pieces
A working setup has three pieces:
- The policy — a single container that holds the rules for your organization.
- The rules — an ordered list. Each rule describes a situation (“any payout of $10,000 USD or more”) and an outcome.
- The approvers — the human users (with enrolled passkeys) who will be asked to approve when a rule says approval is required.
You manage these through the dashboard, the CLI, or the REST API.
How a Rule Is Evaluated
Every in-scope operation is checked against the policy before it is executed. The policy walks the rules in order and stops at the first one that matches. That rule’s outcome decides what happens next.
If no user-defined rule matches, an implicit catch-all rule at position 99999 denies the operation. There is no implicit “allow” — the default behavior of a policy is to reject anything you have not explicitly written a rule for. New organizations are not empty: they ship with a starter policy whose rules cover the first super admin; once you grow past that, your own rules need to keep at least one path open for the operations you want to support.
Rules are first-match-wins — order is policy. Put your stricter rules at the top and your broader fallbacks at the bottom, the same way you’d organize a firewall rule list. Swap the order and a permissive rule will swallow operations you meant to send to a stricter rule. The implicit 99999 deny is always last and cannot be removed or reordered.
What a Rule Can Match On
A rule is a set of filters combined with an outcome. All filters in a single rule are ANDed together: every filter must match for the rule to apply. To make a filter match anything, set it to the wildcard string "*" — that is how “any value” is expressed at the API level (the dashboard exposes this as an “Any” option in each picker).
The supported filters are:
- Operation type — what is being attempted. The canonical values come straight from the policy enum:
PAYOUT_FIAT,PAYOUT_CRYPTO,BALANCE_TRANSFER,DESTINATION_EDIT,POLICY_MANAGE(plus enrollment/security operations such asPASSKEY_ENROLL,API_USER_MFA_ENROLL,API_USER_MFA_REVOKE,EMBEDDED_WALLET_ACCESS_GRANT,USER_INVITE). Note that at the policy layer there is noONRAMPorOFFRAMPtoken — an offramp is gated asPAYOUT_FIAT(fiat leaves to the destination) and an onramp is gated asPAYOUT_CRYPTO(crypto leaves to the destination). This is the most common starting point: most policies are organized first by operation type. - Initiator — who is acting. Typical values are
*(any user or API key), a specific role (for example a super admin), or a specific user or API user. Use this to write rules like “only super admins can manage the policy” or “this API user can auto-approve payouts up to $1,000”. - Amount threshold — a minimum amount, always normalized to USD. The rule matches every operation whose USD-equivalent is greater than or equal to the threshold. A threshold of
0matches every amount (i.e. all operations of that type); a threshold of10000matches every operation of $10,000 USD-equivalent or more. There is no maximum field — to express a band like “between $1k and $10k”, you order rules from highest threshold to lowest and let first-match-wins do the rest (see Rule Ordering & Precedence below). For non-monetary operations (destination edits, policy management), the amount is ignored — set it to0. - Source — where the money comes from inside your organization. This has two parts: a specific merchant (one of the merchants under your organization) and a specific balance in that merchant (i.e. a balance in a given currency, fiat or crypto). Use this to write rules like “payouts from Merchant A’s USDC balance need approval” while leaving Merchant B untouched.
- Destination / counterparty — who is on the other side: a specific bank account, a specific contact, a saved wallet address, or any non-whitelisted destination. This is how you express things like “payouts to whitelisted bank accounts are auto-approved, anything else needs review”. Every destination referenced by a transaction must be pre-created in Koywe before it can be used — you cannot send to an ad-hoc address. The policy filters on which of those pre-created destinations is being used (and on whether it has been whitelisted).
* on operation type does not include POLICY_MANAGE. The wildcard matches every other in-scope operation, but never policy-management actions. To cover changes to the policy itself, you must write a rule whose operation type is explicitly POLICY_MANAGE. This is a safety design: it prevents you from accidentally granting policy edits via a broad fallback rule.
A rule with every filter set to "*" matches every in-scope operation except policy management. That is occasionally useful as an explicit fallback above the implicit 99999 deny.
The Possible Outcomes
A rule resolves to one of these outcomes:
- Allow — the operation goes through immediately. No approver is paged. This is the right outcome for routine, low-risk movements (small payouts to whitelisted bank accounts, internal rebalancing, etc.).
- Require approval — the operation is held as a pending approval. It does not execute until approvers act on it. This is where the approval schemes below kick in.
- Deny — the implicit
99999catch-all rejects the operation up front. You don’t write deny rules by hand; you express “this should never happen” by not writing an allow/approval rule for it and letting the catch-all do its job.
Approval Schemes
When a rule’s outcome is require approval, the rule also specifies who has to approve and how many of them. Koywe supports three schemes, in increasing strictness:
Auto-approve
Effectively the allow outcome above — no human is in the loop. You list it here because, when you are designing a policy, the question “should this be auto-approved?” is the first one you ask for every operation type.
Single approver
The operation is sent to a designated group of approvers (typically by listing the users explicitly). Any one of them can approve it. The first approval releases the operation; any approver can also reject it, which kills the request.
This is the most common scheme for day-to-day operational controls — for example: “payouts above $1,000 require one super admin to approve”.
M-of-N quorum
The operation is sent to a group of N approvers and requires M distinct approvals before it can execute (for example, 2-of-3 or 3-of-5). Each approver can only contribute one vote. A single rejection from any member of the group kills the request.
Use this for the most sensitive operations: large payouts, destination whitelisting changes, anything that would be catastrophic if a single approver were compromised. The point is to make collusion the only failure mode.
Every approval — single or quorum — is anchored to the approver’s passkey. The approver signs the approval payload with their passkey; the signature is what counts, not just a click. See Passkeys & Approvals for the signing mechanics.
Who Can Be an Approver
By default, approvers are human users with a passkey enrolled in Koywe Platform.
API users can also be listed as approvers in a policy. By default, an API user’s approval is just an authenticated API call — no MFA or cryptographic signature is required. This is convenient when you want a service to participate in approvals (for example, an internal automation that double-checks a payout against an external ledger).
If you want stronger guarantees on those automated approvals, you can opt into MFA signing for the API user. That requires two things:
- Koywe enables the API-user signing feature on your account — this is a manual flag, not self-service. Contact Koywe to turn it on.
- The API user onboards a public key (PEM) with Koywe. From that moment on, every approval from that API user must be signed with the matching private key; an unsigned call is rejected.
Use this when an API-user approver guards something material — for example, when it acts as one of the votes in an M-of-N quorum on a high-value flow. For lower-stakes automation, the default “no MFA” behavior is fine. See the API User Signing Tutorial for the key-onboarding flow.
Putting It Together: A Worked Example
Imagine a treasury team that wants the following behavior:
- Money movements (fiat payouts, crypto payouts including offramps/onramps, balance transfers) of $5,000 USD or more: two of three treasury officers must approve.
- Money movements under $5,000: go through automatically.
- Any destination edit (changing a saved bank account or wallet address): two of three treasury officers must approve.
- The super admin can manage the policy itself.
- Anything else: implicitly denied by rule
99999.
Notice how the verbal needs collapse into a shorter rule list once you stop thinking in narrative and start thinking in filters. Here is the rule list that implements the behavior above, in order. Comma-separated values in the Operation type column are OR conditions — Rule 1 matches if the operation is PAYOUT_FIAT or PAYOUT_CRYPTO or BALANCE_TRANSFER and the amount is at least $5,000. A rule with multiple operation types is still a single rule, not three.
| # | Operation type | Initiator | Source | Destination | Amount (USD min) | Outcome |
|---|---|---|---|---|---|---|
| 1 | PAYOUT_FIAT, PAYOUT_CRYPTO, BALANCE_TRANSFER | * | * | * | 5000 | Require approval — 2-of-3 treasury officers |
| 2 | PAYOUT_FIAT, PAYOUT_CRYPTO, BALANCE_TRANSFER | * | * | * | 0 | Allow |
| 3 | DESTINATION_EDIT | * | * | * | 0 (ignored) | Require approval — 2-of-3 treasury officers |
| 4 | POLICY_MANAGE | super admin user | * | * | 0 (ignored) | Allow |
| 99999 | * | * | * | * | * | Deny (implicit catch-all) |
A few things to notice:
- Rule 1 must come before rule 2. Thresholds are minimums, so rule 2’s
0would match every amount if you put it first; rule 1 would never fire. - Rule 3 has to be its own rule because
DESTINATION_EDITis not a money movement and is not in Rules 1 or 2’s explicit operation-type lists — those rules only coverPAYOUT_FIAT,PAYOUT_CRYPTO, andBALANCE_TRANSFER. As a side note, if Rule 2 had used the wildcard*instead of the explicit list, it would have caughtDESTINATION_EDITunder $5,000 first and auto-approved it — which is exactly why we listed operation types explicitly. The wildcard*includesDESTINATION_EDITbut notPOLICY_MANAGE, so Rule 4 also has to be explicit. - Rule 4 is the policy-management rule. It’s typically the rule new organizations get by default, attached to the first super admin. Don’t delete it without a replacement, or no one will be able to edit the policy.
- The implicit
99999deny sits at the very end, untouched. Anything not matched by rules 1–4 is rejected. That is how this policy expresses “anything else: denied” — by simply not writing a rule for it.
If you flipped the order — for example, put rule 2 above rule 1 — every payout, no matter how large, would fall into the auto-approve case, because rule 2’s threshold of 0 matches it first. Order is policy.
Every destination in these rules must be pre-created in Koywe (as a contact’s bank account, a saved wallet address, or a merchant external account) before any payout can reference it. The policy decides whether a transaction to that destination is allowed; it doesn’t relax the requirement that the destination exists in the first place.
Once this baseline works, you can layer extra rules on top — for example, an “auto-approve” rule above rule 1 that targets payouts to a specific whitelisted contact, or a stricter rule that targets a particular merchant’s USDC balance.
End-to-End Approval Flow
When a rule requires approval, the lifecycle of the operation looks like this:
Three details are worth calling out:
- The original request gets a
pendingApprovalIdimmediately. Your application should treat that as a normal, expected response — not an error — and surface it to the requester. - Approvers do not need to be online when the operation is triggered. They are notified, and they act on the approval queue (
koywe policy approvals listor the dashboard) on their own time. - A single rejection ends the request, regardless of how many approvals were already gathered. There is no “majority wins” — quorum means M positive votes with no negative votes.
Rule Ordering & Precedence
Three practical guidelines:
- Highest amount thresholds first. Because thresholds are minimums and a threshold of
0matches every amount, a rule with0placed above a rule with10000will swallow every operation and the higher-threshold rule will never run. Sort rules from the highest threshold down to0within each operation type. - Most specific filters first, broad fallbacks last. A rule “payouts at or above $5,000 to non-whitelisted destinations require 2-of-3” should sit above “payouts at or above $5,000 require one approver”, which should sit above any catch-all you write. The implicit
99999deny is always at the very end. - Reordering is a privileged operation. Use the dashboard or
koywe policy rules reorderto change the order. Every reorder is recorded in the policy audit log; you can review it later throughkoywe policy audit.
When you are not sure how a given operation will be routed, the audit log is the best place to look: it records which rule matched and what the outcome was, for every evaluation.
Operator Playbook
A pragmatic checklist for the person rolling this out:
- Treat the default policy as a starting point, not a permanent setup. New orgs are onboarded with a default policy that works for a solo super admin. The moment you add other operators, more merchants, or want amount-based controls, design and replace it deliberately — don’t accumulate rules on top of the default without understanding what it already allows.
- Enroll passkeys first. Approval rules are useless if your approvers can’t sign. Make sure every intended approver has a passkey enrolled in Koywe Platform before you switch on any approval-required rules. See Passkeys & Approvals.
- Decide whether API-user approvers should sign with MFA. API users can be approvers out of the box, no extra setup — their approval is just an authenticated API call. If a given API-user approver guards something material (a quorum vote on a large payout, for instance), upgrade it to MFA signing: ask Koywe to enable the API-user signing feature on your account, then have the API user onboard a PEM public key. Both steps are manual, so plan ahead.
- Start permissive, tighten over time. Begin with a small number of high-value rules (for example, only payouts above a large threshold require approval). Watch the audit log for a week. Then add more specificity. You can always add rules — you cannot easily un-block operations that were rejected.
- Always test in sandbox first. Build the same policy in the sandbox environment, run real operations through it, and confirm the right rule fires. Policy bugs are far cheaper to find before they block production movements.
- Have at least three approvers for quorum rules. A 2-of-3 with only two enrolled passkeys becomes 2-of-2 in practice, which means one absent approver blocks all critical operations. For 2-of-3, enroll at least four people if you can.
- Don’t put humans in the auto-approve path of high-volume flows. If your business does hundreds of small payouts per day, do not require approval on those — your approvers will start rubber-stamping, which defeats the purpose. Reserve approval for events that are rare and material.
- Review the audit log on a schedule.
koywe policy audit(or the dashboard equivalent) shows every rule match, every approval, every rejection. Treat it like a SIEM feed for treasury. - Document the policy in plain language outside Koywe. Approvers should know what they are approving and why. A one-page internal doc that explains “we have these rules because…” makes approvers thoughtful instead of mechanical.
Common Pitfalls
- Replacing the default with a policy that has no path for your operations. Brand-new orgs ship with a working default policy, but as soon as you rewrite it you own the outcomes. A policy that contains no rule matching a given operation — or where you deleted the only allow rule for it — falls through to the catch-all
99999and rejects every such operation. If production movements suddenly start failing with a policy error after a policy edit, this is the first thing to check. - Deleting the
POLICY_MANAGErule. The default policy includes a rule allowing the super admin to manage the policy itself. Because operation-type*does not includePOLICY_MANAGE, no other “broad” rule covers it. Delete that rule without a replacement and nobody — including the super admin — will be able to edit the policy. You will need to contact Koywe to recover. - Expecting
*on operation type to cover policy management. It doesn’t. Always writePOLICY_MANAGEas its own explicit rule. - Ordering bugs with the
0threshold. A rule with amount threshold0matches every amount. If you place it above a rule with a higher threshold, the higher-threshold rule will never run. Always sort by threshold descending within an operation type. - Ordering bugs in general. Adding a strict rule at the bottom of the list does nothing — an earlier permissive rule will already have matched. Always check the resulting order with
koywe policy info. - Missing approvers. A quorum rule that requires 2-of-3 from a group where only one person has a passkey enrolled will deadlock every matching operation. Add approvers before activating the rule.
- Treating policy errors as bugs. When a request is held for approval, your application gets back a
pendingApprovalId, not the final resource. Code that expects an immediate success will look broken. Plan for this state. - Editing the policy under load. Reordering or deleting rules takes effect on the next evaluation. Avoid policy edits during a payout batch — finish the batch, then change the policy.
Where to Go Next
- Passkeys & Approvals — the cryptographic side: how passkeys, MFA tokens, and approval signatures fit together.
- CLI Reference — Policy & Approvals — the exact commands for creating policies, adding rules, listing pending approvals, and viewing the audit log.
- Security Best Practices — credential hardening and webhook verification, both of which complement policy controls.