Skip to content

Approvals

Queues → Approvals is where dual control is visible. “Ten actions on this platform need a second person. This is where they wait.”

Needs approval.read to see. Deciding needs the permission the action itself requires — see below.

Action What it changes
Accounting period lock Closes a period to further posting.
Accounting period reopen Reopens a closed period.
Balance hold release Frees money held against a merchant’s balance.
KYC check override Marks a failed or unrun check as satisfied.
Merchant deposit Credits a merchant’s balance with money they sent us. See Deposits.
Merchant fee settings Changes what a merchant is charged.
Merchant live status Enables or disables real money for a merchant.
Merchant suspension Stops a merchant trading.
MFA reset Clears a staff member’s authenticator.
Settlement release Makes a batch payable.

Each has its own decision route, and each route answers 404 for anything that is not its own action — deliberately, so that a refusal cannot reveal the existence of a pending change you were not shown.

Control Type Values
Action One of The ten action codes.
Status Multi-select Pending, Approved, not applied, Applied, Rejected, Expired, Cancelled.
Raised by Toggle Raised by me — what you are waiting on others for.
Column What it holds
Action Which of the ten.
Against The merchant, period, batch or staff account affected.
Raised by The requester. Your own requests show as You.
Approvals “1 of 2” — see below.
An approver needs The permission required to decide it.
Amount “The figure the policy’s amount band was chosen on.”
Expires Time remaining. A lapsed request cannot be decided.
Status —
You Needs you, or the reason your account cannot decide it.
Raised When.

The required count is approvers besides the person who raised it. So a request showing 1 of 2 needs one more signature, not two more. The detail panel spells this out, because “2” on its own reads as “two people in total” — which would make a one-approver policy look as though it needed nobody.

The “You” column is the answer to the most common question

Section titled “The “You” column is the answer to the most common question”

“Why can I not decide this one?” It is one of four reasons, and the column says which:

  1. You raised it. A requester cannot approve their own request. The API refuses it: “maker and checker must be different people — that is the entire control.” The row says so rather than offering a button that will be refused.
  2. You lack the permission. An approver who could not have made the change themselves is a signature, not an approval, so the permission required to decide is the permission required to act.
  3. It has lapsed. A pending request past its deadline stays pending until something touches it, so the platform’s own lapsed flag — not your clock — decides whether a decision is offered.
  4. It is about you. A change to a staff account — an MFA reset, a password reissue, a status change, a role assignment, or any held change to /v1/users/{id}/… — can never be approved by the person it changes. It is refused with 403. The Authorised by picker leaves that person out, and a held change naming them is refused before anything is held.

Open the row. The detail panel shows everything the decision should be made on:

Fact Why it is there
Status —
Approvals “Required counts approvers besides the person who raised it.”
An approver must hold The permission.
Environment Test or live. Check it.
Raised by / Raised —
Expires “A lapsed request is refused rather than queued.”
Amount “Recorded so the policy’s amount band stays auditable after the policy changes.”
Request The change itself, in full.
Policy “Recorded so an auditor can reconstruct the decision from the policy as it stood.”
Reason given What the requester wrote.
Decisions recorded Every signature so far, with Step-up verified where the approver proved identity at the point of deciding.

To decide, you provide:

Field Notes
Reason Yours, recorded against your decision.
Authenticator code “A current code from your own authenticator. A recovery code is not accepted here.”

Approving records your signature. The change applies once the required number of approvals is in.

If you raised it, you can withdraw it — “it can be raised again if the change is still wanted.” One field: Reason, e.g. “Raised against the wrong merchant.”

Withdrawing a wrong request is always better than leaving it for somebody to approve by mistake.

Two shapes of dual control, and the form tells you which

Section titled “Two shapes of dual control, and the form tells you which”

Most dual control here is after the fact: the write raises a request, this register holds it, and somebody else decides it. Nothing has changed when you submit, and the dialog says so.

The other writes — pricing rules, a blocklist entry, a risk rule’s mode, a limit, a routing rule, an FX rate, a statement close, a staff account, a settlement batch, a withdrawal, verifying a settlement destination by hand, settling a payment on evidence, releasing a payment from risk review — carry an Authorised by picker. Naming a colleague there holds the change until they approve it: “They are asked to approve {what} in Approvals; nothing changes until they do. It cannot be you.”

Approval request Held for a co-signer
What the dialog says “This raises a request” Authorised by
When it takes effect When the second person approves When the person you named approves
Where it waits Approval requests Waiting on you (theirs) and Asked by you (yours)

When you submit a form naming a colleague in Authorised by, nothing changes. The console shows a blue notice — “Sent to {name} for approval. Nothing changes until they approve it in Approvals; it lapses if not decided within 72 hours.”

Three tabs on this page:

Tab What it holds
Waiting on you “Changes a colleague made and named you as authorising. Nothing has happened until you approve.” The tab shows how many.
Asked by you “Changes you made that name a colleague. They take effect when that colleague approves.”
Approval requests The policy queue described above.

Opening a held change shows exactly what will be sent — the method, the path and the request body — with the requester’s reason. Then:

  • Approve and apply — the change is run again, as the person who made it, with their permissions as they stand at that moment. Every check the action normally makes applies again, and the audit entry names you as the approver. The sheet then shows “Approved and applied”, or “Approved, but the change was refused” with what the server returned — a permission removed or a record changed since, for example.
  • Reject — needs “Why you are rejecting it”, at least eight characters. “They read this.”
  • Withdraw this request — for the person who made it, while it waits.

A held change not decided within 72 hours lapses.

Naming yourself is not held. The action’s own rule applies, and nearly all of them refuse it. The exceptions:

  • Creating a staff account while yours is the only active one.
  • Changing a partner’s addresses or setting its credentials while yours is the only active account. See Partners.
  • Approving a withdrawal, verifying a settlement destination by hand, settling a payment on evidence, or releasing one from risk review, while yours is the only active account. See Withdrawals and Merchants.
  • Credential recovery (a password reissue or an authenticator rebind) while no active account exists other than yours and the person being recovered. They can’t approve their own recovery, so nobody else could decide it.

All take effect at once and are recorded as self-authorised. See Staff and When there are only two accounts.

From the API (approval.read): GET /v1/cosign-requests?side=to_me|by_me, GET /v1/cosign-requests/{id}, POST /v1/cosign-requests/{id}/decide with approve or reject and a reason, and POST /v1/cosign-requests/{id}/cancel. A held write answers 202 with the code approval_pending and a cosign_request_id.

When Who Subject
An approval request is raised Every active staff member who holds the policy’s approver permission, or is a super admin, except the person who raised it. At most 25 people. Approval needed: {action}
A change is held for co-signing The colleague named in Authorised by. Approval needed: {action}
A request or held change is decided The person who raised it, whether it was approved and applied, rejected, or approved but refused when it ran. Your request was {decision}: {action}

The emails have no button. They name the page to open, Approvals, because a link in a staff email would point at the merchant portal. The email is queued in the same transaction as the request or decision, so nobody is told about a decision that rolled back.

You do not raise approvals from this page. Each request is raised where the change is made — a suspension from the merchant’s page, a period lock from Periods, an MFA reset from Staff. This page is only where they wait.

What makes a request easy to approve:

  • A reason that states the facts, not the conclusion. “Merchant requested limit raise” is not a reason; “trading history since March supports GHS 50k, dispute rate 0.3%, KYC level 2 approved 14 Aug” is.
  • The right amount band. The amount decides which policy applies, and it is recorded for audit.
  • Raised in the right environment. A live change raised against test is the most common wasted request.
  1. Filter to Pending and sort your attention by Expires — a lapsed request means somebody has to start again.
  2. Read the request, not the title. The action code tells you what kind of change it is; the request body tells you what it actually does.
  3. Check the environment.
  4. Ask yourself whether you would have made this change. That is the question dual control asks you. If the answer is “I would want to know more”, that is not an approval.
  5. Write the reason you would want to read in six months.