> ## Documentation Index
> Fetch the complete documentation index at: https://partner.tren.ch/llms.txt
> Use this file to discover all available pages before exploring further.

# Read and Participate in Governance

> Read proposals, tallies, and the connected user's own votes without a scope, then cast votes and create proposals with the governance write scopes.

Token metadata on Trench is governed on-chain. Holders vote on changes to a token's name, symbol, image, and links, and on whether to lock that metadata permanently.

Governance splits cleanly in two. Reads require no scope, because proposals and tallies mirror public on-chain state, and only writes are gated.

## Endpoints Used

* [`GET /partner/v1/governance/{mint}`](/api-reference/governance-read)
* [`POST /partner/v1/governance/votes`](/api-reference/governance-vote)
* [`POST /partner/v1/governance/proposals/settle`](/api-reference/governance-vote)
* [`POST /partner/v1/governance/proposals/update-content`](/api-reference/governance-propose)

## Reading a Token's Governance

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.tren.ch/partner/v1/governance/$MINT" \
    -H "Authorization: Bearer $ACCESS_TOKEN"
  ```

  ```javascript Node.js theme={null}
  const res = await fetch(`https://api.tren.ch/partner/v1/governance/${mint}`, {
    headers: { Authorization: `Bearer ${accessToken}` },
  });

  const { governance, proposals, viewerVotes } = await res.json();
  ```

  ```python Python theme={null}
  import requests

  res = requests.get(
    f"https://api.tren.ch/partner/v1/governance/{mint}",
    headers={"Authorization": f"Bearer {access_token}"},
  )

  data = res.json()
  ```
</CodeGroup>

A single call returns everything needed to render a governance UI: the config, up to 100 proposals newest first, and the connected user's own votes. If the token has no governance, the endpoint responds with `404 governance_not_found`.

```json theme={null}
{
  "governance": {
    "governance": "…", "mint": "…", "creator": "…",
    "totalSupply": "…", "mutableUntilUnix": "…",
    "minVoterCount": 25, "minLockAmount": "…",
    "minParticipatingSupplyBps": 1500, "approvalBps": 6600,
    "proposalBondBps": 100, "finalized": false,
    "contentRevision": "0", "mutabilityExtended": false,
    "nameLocked": false, "symbolLocked": false, "imageLocked": false,
    "descriptionLocked": false, "websiteLocked": false,
    "twitterLocked": false, "telegramLocked": false
  },
  "proposals": [ { "…": "…" } ],
  "viewerVotes": [ { "…": "…" } ]
}
```

See [Governance reads](/api-reference/governance-read) for a description of every field.

<Note>
  The `viewerVotes` array contains the connected user's own votes, derived from the access token rather than from a caller-supplied address. You can use it to show that a user has already voted without making a second request and without requesting a scope.
</Note>

## What the Config Parameters Mean

Four parameters determine whether a proposal can pass, and we recommend surfacing them in your UI before a user commits tokens to a vote.

| Parameter                   | Controls                                                 |
| --------------------------- | -------------------------------------------------------- |
| `minVoterCount`             | Distinct qualifying voters required                      |
| `minParticipatingSupplyBps` | Share of total supply that must vote, in basis points    |
| `approvalBps`               | Share of cast weight that must be `yes`, in basis points |
| `minLockAmount`             | Smallest vote that counts toward the voter count         |

Basis points are hundredths of a percent, so `6600` is 66% and `1500` is 15%.

A proposal must clear both participation thresholds as well as the approval threshold. This means a change with overwhelming support can still fail for lack of turnout, which is the outcome most worth explaining to users.

## The Mutability Window

Every token launches with a finite window during which its metadata can be changed at all. After `mutableUntilUnix` passes, metadata locks permanently whether or not anyone votes.

* The window can be extended once by proposal. A second attempt returns `mutability_already_extended`.
* Extensions are capped, and an over-long request returns `mutability_extension_exceeds_cap`.
* Holders can end the window early by passing a finalize-metadata proposal.
* Individual fields lock independently, so check the `*Locked` flags before offering an edit.

<Warning>
  A proposal cannot outlive the window. If `voteDurationSeconds` would run past `mutableUntilUnix`, creation fails with `vote_duration_exceeds_window`, and proposals submitted too close to the deadline fail with `proposal_window_closing`.
</Warning>

## Voting

Voting requires the `governance:vote` scope.

```bash cURL theme={null}
curl -X POST 'https://api.tren.ch/partner/v1/governance/votes' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "proposal": "…",
    "side": "yes",
    "amount": "1000000",
    "priorityFeeLamports": "20000",
    "tipLamports": "1000000"
  }'
```

Vote weight is the token amount locked, which means voting locks those tokens for the duration of the proposal. Users reclaim them with `votes/withdraw` after settlement.

<Warning>
  Locked tokens cannot be traded, and users who are not aware of this tend to read it as missing balance. We recommend showing both the locked amount and when it can be reclaimed.
</Warning>

A second vote on the same proposal returns `already_voted`. To change a vote, cancel the existing one first.

See [Voting endpoints](/api-reference/governance-vote) for cancel, withdraw, and settle.

## Settling

Voting coming to an end does not apply the result. Someone has to call `proposals/settle`, which computes the outcome and executes the action if the proposal passed. The operation is permissionless, so any token holder with `governance:vote` can crank it, including yours.

Until a proposal is settled, bonds and locked vote tokens remain locked. If your product surfaces governance, settling closed proposals on your users' behalf is a genuinely useful thing to offer.

## Proposing

Proposing requires the `governance:propose` scope. Creating a proposal locks a bond from the user's wallet, sized at `proposalBondBps` of supply, which is reclaimed with `bonds/withdraw` after settlement.

Only one proposal can be active per governance at a time, and a second returns `active_proposal_exists`.

<Warning>
  The `voteDurationSeconds` field defaults to 600 seconds, which is ten minutes and far too short for a real governance decision. We recommend setting it explicitly on every proposal.
</Warning>

### Changing Metadata

The `proposals/update-content` endpoint is the only multipart endpoint in the Partner API, because it can carry a new image. Send only the fields you want to change, since omitted fields are left alone and empty strings clear text fields.

```bash cURL theme={null}
curl -X POST 'https://api.tren.ch/partner/v1/governance/proposals/update-content' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -F mint=… \
  -F voteDurationSeconds=86400 \
  -F priorityFeeLamports=20000 \
  -F tipLamports=1000000 \
  -F name="New Name" \
  -F image=@logo.png
```

<Warning>
  Proposals are authored against a `contentRevision`. If another proposal lands first, yours becomes stale and fails with `stale_content_revision`. Re-read the governance, rebase the change set, and have the user confirm before resubmitting, since silently resubmitting can spend their bond on a change they did not intend.
</Warning>

<Note>
  Validation failures on `website`, `twitter`, and `telegram` currently surface as `500 internal` rather than `400`, and they are permanent rather than transient. We recommend validating these three fields on your own side before submitting. See [Error Handling](/concepts/errors).
</Note>

See [Proposal endpoints](/api-reference/governance-propose) for extend-mutability, finalize-metadata, and bond withdrawal.

## Write Responses

All governance writes respond in the same shape, with identifiers included where they apply.

```json theme={null}
{ "signature": "…", "status": "processed", "mint": "…", "governance": "…", "proposal": "…" }
```

<Warning>
  A status of `processed` means the transaction was included in a block, not that it is rooted. Confirm the signature against Solana through your own RPC before telling a user their vote counted.
</Warning>

The `update-content` endpoint additionally returns `metadataUri` and `imageUri` for the newly pinned content.
