Governance
On-chain governance proposals, voting results, stage history, pre-governance council review, and token governance configuration.
Vision Hub verification
Kalvora governance must be verified by Kalscan, never by a Zera verifier. Kalscan generates only the explicit network-bound vote URI:
visionhub://vote?network=kalvora%3Amainnet&proposal=<64-lowercase-nonzero-hex>&coin=<encodeURIComponent(canonical-Kalvora-mint)>
The authority is exactly vote, the path is empty, and the query contains
exactly network, proposal, then coin in that order. The colon must be
the uppercase %3A encoding. Duplicate, reordered, extra, fragmented,
alternately encoded, ZERA-discriminated, and legacy network-less vote links are
rejected; the coin grammar is never used to infer a network. Kalscan's browser
launcher requires the same exact query after /open/visionhub.
Vision Hub calls:
GET https://kalscan.net/api/visionhub/governance/verify?proposal=<64-lowercase-hex>&coin=<canonical-Kalvora-mint>&network=mainnet|testnet|protonet
The route accepts exactly one of each parameter and returns only
proposal, coin, network, verified: true, and browserUrl
on success. It verifies the exact raw indexer hash and symbol; it does
not trim or case-fold identifiers and never accepts caller-selected upstreams.
For mainnet, browserUrl is exactly
https://kalscan.net/governance/<proposal>?coin=<encoded-mint>. It is
null for testnet and protonet until those networks have verified
browser routes; Vision Hub must fail closed and not open a browser when it is
null. The public route is CORS-readable for GET/OPTIONS, does not
use browser credentials, and can return 429 while capacity is limited.
Status values
| Value | Code | Meaning |
|---|---|---|
passed | 0 | Passed at its final stage |
failed | 1 | Failed / denied |
passed_stage | 2 | Passed the current stage, more stages remain |
active | 3 | Open for voting |
pending | 4 | Waiting for the voting period to start |
cancelled | 7, 9 | Cancelled by a contract update, or by the proposer |
pending_results | 8 | Stage matured, indexed result still pending |
Codes 5 and 6 were fast_passed and no_pass_fast. Fast quorum was removed from the Kalvora protocol. Both numbers are permanently retired so persisted values never shift meaning, and no proposal can ever report them again. There is no fast-quorum status, filter, or configuration field.
pending_results is derived in the response and is not accepted by the stored-status filter. The API also adjusts statuses against real time: pending → active once validFrom passes, and active → pending_results once maturesAt passes.
Pre-governance and the proposal phase
A governance contract may declare an optional council review that runs before public voting. Proposals and stages on such contracts carry a derived phase:
| Value | Meaning |
|---|---|
PRE_GOVERNANCE | Under council review; not open for public voting |
REGULAR_GOVERNANCE | Promoted into the contract's regular governance pipeline |
PASSED | Passed at its final stage |
FAILED | Failed |
CANCELLED | Cancelled by the proposer or by a contract update |
phase is derived at read time — it is never stored, no status code encodes it, and it is not accepted by the stored-status filter.
Read phaseAvailable first. Phase derivation is activated per deployment. While it is off, phaseAvailable is false and the phase key is absent from the payload entirely — not null, not empty, not a default. In that state fall back to plain status display; do not infer that a stored proposal is open for public voting, and do not render "unknown".
REGULAR_GOVERNANCE is reported only on positive evidence of promotion (a recorded stage ≥ 2, or a passed-stage result), so a proposal still at stage 1 reads PRE_GOVERNANCE even if its council window has already elapsed. While a proposal is in PRE_GOVERNANCE its validFrom and maturesAt are provisional: they describe the public voting window it would get if the council promotes it.
Proposals inside their council review window are excluded from the votable-proposals listing and from a contract's activeProposals count, regardless of the gate — both answer "what is open for public voting right now". The full proposals listing is history and still returns them, flagged by phase. Council votes stay in the ordinary votes ledger and are never aggregated into proposal results.
The approved tally in the governance config counts final-stage proposals with status 0 only. It previously also counted the retired fast-pass code.
List Proposals
/v1/governance?request=proposalsPaginated list of governance proposals with current voting stage. Supports multi-symbol filtering.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| request | string | Required | — | `proposals` or `list` |
| limit | int | Optional | 20 | Number of results (1–100) |
| offset | int | Optional | 0 | Pagination offset |
| symbol | string | Optional | — | Filter by governed contract mint ID(s), comma-separated |
| status | string | Optional | — | Filter: passed, failed, passed_stage, active, pending, cancelled |
| sort | string | Optional | created_at | Sort: created_at, title, status, matures_at, votes, percentage, active_time_left, vote_value_desc, support_desc, contract_asc, created_desc, closes_asc |
| order | string | Optional | desc | Sort direction: asc or desc |
Usage & Credits
Notes
- `phase` is present only when `phaseAvailable` is true; while the gate is off the key is omitted entirely. `phaseAvailable` describes the deployment, not the page, so it is returned even for an empty result page.
- This listing is the full indexed history, so a proposal under council review can appear here with `phase: PRE_GOVERNANCE`. Treat that phase as not open for public voting: the answers to "what is open right now" — `votableProposals` and a contract's `activeProposals` count — exclude it.
Response
{
"found": "integer",
"proposals": [
{
"hash": "string",
"stageNumber": "integer",
"lastStage": "boolean *",
"symbol": "string",
"creator": "string",
"title": "string",
"synopsis": "string",
"body": "string",
"options": [
{
"name": "string",
"curEquiv": "float",
"percentage": "float",
"votes": "object",
"transactions *": [
{
"type": "string",
"hash": "string"
}
]
}
],
"resultUpdated": "integer",
"result": "string",
"createdAt": "integer",
"validFrom": "integer",
"maturesAt": "integer",
"phase": "string *"
}
],
"phaseAvailable": "boolean"
}Proposal Details
/v1/governance?request=detailsFull proposal detail with all voting stages and projected future stages. Performs live validator sync for active proposals.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| request | string | Required | — | `details` or `proposal` |
| hash | string | Required | — | Proposal hash |
Usage & Credits
Notes
- The top-level `phase` mirrors the current stage's derived phase. Both it and the per-stage `phase` are omitted while `phaseAvailable` is false, and projected (not yet stored) stages never carry one.
Response
{
"hash": "string",
"symbol": "string",
"creator": "string",
"title": "string",
"synopsis": "string",
"body": "string",
"options": [ "string" ],
"createdAt": "integer",
"stages": [
{
"stageNumber": "integer",
"lastStage": "boolean",
"options": [
{
"name": "string",
"curEquiv": "float",
"percentage": "float",
"votes": "object",
"transactions *": [
{
"type": "string",
"hash": "string"
}
]
}
],
"resultUpdated": "integer",
"result": "string",
"validFrom": "integer",
"maturesAt": "integer",
"phase": "string *"
}
],
"phase": "string *",
"phaseAvailable": "boolean"
}Errors
| Status | Condition |
|---|---|
| 400 | Missing hash/proposalHash parameter |
| 404 | Proposal not found |
Governance Config
/v1/governance?request=configGovernance configuration for a token: type, stages, cycle timing, quorum, and pre-governance council setup.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| request | string | Required | — | Must be `config` |
| symbol | string | Required | — | Governed contract mint ID |
Usage & Credits
Notes
- `threshold` is a percentage multiplied by 100 (`7500` means 75%). `preGovernance.threshold` and `preGovernance.regularQuorum` are scaled so `10000` means 100%, returned exactly as the governance contract stored them.
- `preGovernance` is omitted entirely when the contract declares no council review, and each of its fields is omitted rather than zeroed when unset — a stored `0` threshold is a meaningful value.
- `activeProposals` counts only proposals open for public voting, so a proposal still inside its council review window is not included.
Response
{
"type": "string",
"activeProposals": "integer",
"totalProposals": "integer",
"threshold": "integer",
"quorum": "integer",
"preGovernance *": {
"votingInstrument": "string *",
"days": "integer *",
"threshold": "integer *",
"regularQuorum": "integer *"
},
"durationDays": "integer *",
"durationMonths": "integer *",
"startCycleUnix": "integer *",
"endCycleUnix": "integer *",
"numberStages": "integer *",
"currentStageNumber": "integer *",
"stages *": [
{
"stageNumber": "integer",
"isBreak": "boolean",
"period": "string",
"length": "integer",
"maxAllowed": "integer *",
"startsAt": "integer *",
"endsAt": "integer *"
}
],
"approved": "integer",
"denied": "integer",
"firstTimeUnix": "integer",
"optionProposalsAlwaysWinner": "boolean *"
}