Skip to content

Approval policies

Platform → Approval policies is “how many people must agree before an action happens, by environment and amount”.

Needs approval.read to open. Changing anything needs approval.policy.write, and both writes on this screen raise an approval request rather than taking effect — which is why the primary button says Request a policy and why a raised-request panel appears above the table instead of a success toast.

The decision itself is taken on the register — see Approvals.

In the order they are misread.

Policies stack by amount. An action can have one band for any amount and another for over GHS 50,000. The one that applies is the highest band a request clears, in the same currency. A GHS band says nothing about a USD figure, which falls through to the band with no floor.

An action marked dual-control with no band here still needs approval. The flag on the permission and a band in this table are two different facts. Equally, publishing a band for an action nothing raises a request for changes nothing at all.

Nothing here is edited in place. A pending request snapshots the terms that governed it, so a row whose terms moved underneath it would make the register misstate what was agreed. Publishing a band retires the one it matches, in the same approved change, and both rows stay in the history.

Filtered by Environment (both, live, sandbox) and Action (a permissions.code — the same vocabulary roles are composed from).

Column What it holds
Action The permission code this governs, with its label.
Environment Policies are per-environment; a sandbox threshold and a live one are separate rows.
Band The inclusive floor, or “Any amount” for the fallback band.
Approvers Shown as +n — besides the maker. 1 is the two-person control, 2 is three-eyes. The requester never counts, and the database refuses them as their own approver.
An approver holds Not the same as the permission needed to request the action. An approver who could not make the change themselves is a signature, not an approval.
Step-up Set means each approver enters a current authenticator code as they decide. A decision without one is refused outright rather than recorded as unverified.
Window How long a request stays decidable. An expired request is refused, not queued.
Action is dual-control The action’s own flag — a different fact from this policy existing.
In force since When the band started applying.

Request a policy for a new one, or Publish a replacement from a row’s menu, which pre-fills from that row.

Field Notes
Action this governs A permissions.code. A policy for an action that does not exist never matches anything.
Environment Live or sandbox. Separate rows.
Only above an amount Off is the fallback band: it matches any amount in any currency, and it is what governs an action that has no amount at all.
Floor, in minor units Inclusive. 5000000 is GHS 50,000.00 — a batch of exactly that falls in this band, not below it.
Currency The band is denominated in this. A GHS band is silent about a USD figure.
Approvers besides the maker 1 to 10.
An approver must hold A permission held by one role of one person cannot be exercised at all — check who holds it before you name it.
Each approver re-authenticates Step-up, on by default.
How long a request stays decidable One hour to thirty days. Shorter and a request lapses before an approver is reachable, which makes the action impossible rather than guarded.
How this reads in the register At least four characters. An approver sees this before they open anything — “Settlement over GHS 50,000: three people”.
Why the committee set it here Optional, and shown beside the band for ever.
Why this should change Required. The second approver reads this before deciding, and it is the permanent record of the decision — “Risk committee of 3 October lowered the three-approver floor from GHS 100,000 to GHS 50,000 after the September incident.”

Nothing changes on submit. The band appears once a second person approves it; until then the policy in force is the old one.

From the row menu. The one field is Why it should stop applying, and it raises a request like everything else here — the band still applies until that request is approved.

A policy is never deleted and never reopened: it is given an end date and stays, so a request can always name the policy that decided it.

Its own table, because “what applies now” and “what applied, and when it stopped” are different questions and a reader who confused them would act on a superseded threshold. It follows the same filters, since the question that brings somebody here — “when did this threshold move” — is asked one action at a time.

An amendment reads as two rows: the retirement and its replacement.

Published by is the approver whose claim wrote the row, not the person who asked for it — that person is in the approvals register with their reason. An empty author means a migration seeded the row, which is what the thresholds the platform shipped with look like.

  • Approvals — the register these requests land in, and where a policy change is decided.
  • Staff — who holds the approver permission a band names.
  • Setting up the platform — where reviewing these thresholds sits in bring-up.