Skip to content

Someone else has to sign off on this.

Wire transfers, production access, price changes, content going live. Every serious application ends up needing a second pair of eyes, and every team builds the sign-off flow again. Quorum is that second pair of eyes, as one self-hosted service.

Open source under MIT. Written in Go. Runs on PostgreSQL or SQL Server.

A status column, a couple of endpoints, an audit table that is never quite complete, a UI only one app can use. Then the next application needs the same thing and it starts again.

Rolling your ownWith Quorum
StateApproval state lives in a column on your own table, with transitions scattered across handlers.Requests, stages, votes and expiry are a first-class model with enforced transitions.
Guards“Not the maker”, “one vote per stage”, “only managers” are re-implemented, and re-forgotten, per app.Layered guards are enforced centrally and configured per policy.
ChangesChanging who approves what means a code change and a deploy.Policies are data. Edit them at runtime in the console or the API.
AuditThe trail is whatever logging you remembered to add.Every action is recorded with actor, timestamp and details, in the same transaction as the change.
ScreensEach app builds its own approval pages.Three themeable Web Components, or the admin console.
  1. Your app creates a request

    One call with a type and a JSON payload. The caller is the maker.

  2. Quorum finds the policy

    Stages, thresholds, who may act and when to expire, all read from data.

  3. Checkers sign

    Self-approval, roles, permissions, scope and duplicate votes are checked before a signature lands.

  4. Your app acts on the decision

    Approved, rejected or expired arrives by webhook, event stream or poll. Your app performs the write.

Stages in order
Each with its own threshold, allowed roles or permissions, and rejection rule.
Scope
Only the compliance officers in the maker’s branch may sign the second stage. Attributes come from your identity provider’s claims or your gateway’s headers.
Bypass with a velocity limit
Amounts under 1,000 skip review, but the fourth one in a day comes back for a human to look at. Limits stop a threshold from being gamed.
Expiry
A request nobody decides on does not stay open forever.
POST /api/v1/policies
{
"name": "High-value wire transfer",
"request_type": "wire_transfer",
"stages": [
{ "name": "Manager approval",
"required_approvals": 1,
"allowed_checker_roles": ["manager"] },
{ "name": "Compliance review",
"required_approvals": 2,
"allowed_checker_roles": ["compliance_officer"],
"scope": [{ "attribute": "branch_id" }] }
],
"bypass_rules": [
{ "name": "petty cash",
"payload": [{ "path": "amount", "op": "lt", "value": 1000 }],
"limits": [{ "window": "24h", "max_count": 3 }] }
],
"auto_expire_duration": "24h"
}
Layered permission guards
The maker cannot approve their own request. Per-request eligible reviewers, per-stage roles and permissions, reviewer scoping by attributes such as branch, an optional authorization endpoint you control, and one vote per checker per stage. Evaluated in order on every decision.
An audit trail you can hand to an auditor
Every create, approve, reject, cancel, bypass and expiry is permanently logged with actor, timestamp and details. One place to answer who approved this, and when.
Webhooks that cannot be lost
Deliveries are written to an outbox in the same transaction as the state change, signed with HMAC-SHA256 and retried with backoff. A review_requested event tells your application exactly who is allowed to act next, so you can notify them.
Approval screens for any front end
Three Lit Web Components: an approval panel, a request list and a stage progress bar. Shadow DOM isolation, theming through CSS custom properties, live updates over Server-Sent Events. Load them from a script tag or npm.
Your identity provider stays in charge
Validate JWTs against any OIDC provider’s JWKS endpoint with claim mapping and automatic key rotation, or trust headers from your gateway. Quorum never becomes a user directory.
Built to be operated
PostgreSQL or SQL Server, with everything in its own schema so Quorum can share your database. Prometheus metrics, a health endpoint that reports its version, multi-arch Docker images, an OpenAPI contract validated against the real server in tests.

Manage policies, browse requests, read every audit entry and watch webhook deliveries. It ships inside the server binary when you opt in at build time.

Quorum console dashboard listing pending and decided approval requests
The requests dashboard
Policy editor with multi-stage configuration
Policy editor
Approval detail with payload and audit trail
Approval detail
Audit log
Audit log

Three sample applications on three stacks share one hosted Quorum. Switch personas in the navigation bar to walk a request from maker to checker.

  • BankingGo, html/template, built on the Go client

    Multi-stage wire transfers that execute when the approved webhook arrives.

  • Expense trackerNode.js and Express

    Single-stage expense approval with status polling.

  • Access portalPython and Flask

    Threshold voting: two of three security reviewers must approve.

One command brings up the database, the migrations and a server with the console and widgets. Then create a policy and your first request.

Terminal
git clone https://github.com/lawale/quorum.git && cd quorum
docker compose up
# PostgreSQL, migrations, Quorum with console and widgets at localhost:8080

Quorum is built by .