Developers

HTTP API

The Plumb API reads the chain and builds, simulates and relays transactions. It never holds keys. The app uses it for everything.

The API serves JSON over HTTPS under /api/plumb on this site, and it is the same API the app uses. In the examples, $PLUMB_API stands for that base URL, for example https://<this site>/api/plumb.

Conventions

  • On-chain quantities, timestamps and slots are decimal strings in raw units. PLMB has 6 decimals and JitoSOL 9, so "100000000" is 100 PLMB and "2500000000" is 2.5 JitoSOL.
  • Addresses are base58 strings.
  • Errors are {"error": "a sentence"} with a 4xx or 5xx status.
  • Read routes return 503 while the API's index of the chain is not current, rather than stale data.

Routes

Route Returns
GET /v1/branches Every branch and the finalized slot it was read at
GET /v1/branches/:branch The branch account as recorded
GET /v1/branches/:branch/buckets All sixteen rates with their troves
GET /v1/branches/:branch/troves?owner= Troves, optionally for one owner
GET /v1/branches/:branch/pool Stability pool totals and depositors
GET /v1/branches/:branch/live?owner= One confirmed read of everything the app shows, with the price
POST /v1/transactions An unsigned transaction, built and simulated
POST /v1/send Relays a signed Plumb transaction
GET /v1/signatures/:signature Confirmation status, with a reason if it failed

The branches, buckets, troves and pool routes read a finalized snapshot of the chain. live reads at confirmed commitment, a few seconds fresher.

Live state

curl "$PLUMB_API/v1/branches/$BRANCH/live?owner=$WALLET"

One response, read from a single slot (abbreviated):

{
  "programId": "…",
  "commitment": "confirmed",
  "slot": "312040551",
  "clock": { "slot": "312040551", "epoch": "740", "unixTimestamp": "1790000000" },
  "address": "…",
  "branch": { "debt": "…", "collateral": "…", "poolStable": "…", "bitmap": 120, "ledger": [] },
  "buckets": [],
  "price": { "microUsdPerToken": "153498899", "issues": [], "sol": {}, "lst": {} },
  "owner": { "lamports": "…", "stable": {}, "collateral": {}, "trove": { "active": true, "tick": 4, "slot": 2 } }
}

price.microUsdPerToken is the price the program would use at this slot, in millionths of a dollar per JitoSOL: 153498899 is $153.498899. When the program would refuse the price it is null, and issues lists every check that failed. buckets has sixteen entries, null for a rate that was never opened. owner appears only when you pass ?owner=.

Building a transaction

curl -X POST "$PLUMB_API/v1/transactions" \
  -H "content-type: application/json" \
  -d '{"kind":"open","branch":"…","owner":"…","tick":4,"collateral":"3000000000","debt":"100000000"}'

tick is the rate minus one: tick 4 is 5%. Kinds and their fields:

Kind Fields
open tick, collateral, debt
adjust add, withdraw, borrow, repay
changeRate tick
redeem amount, minCollateral, maxFeeBps
poolDeposit amount
poolWithdraw amount, collateral
liquidate targetOwner
accrue tick

Every request also needs branch and owner; the owner signs and pays the fee. The API adds the compute-budget instructions and creates any associated token account the owner lacks. redeem always uses the lowest rate that holds debt.

A success returns the transaction for the owner to sign:

{
  "transactionBase64": "AQAAAA…",
  "lastValidBlockHeight": 290118843,
  "requiredSigner": "…",
  "unitsConsumed": 99907,
  "units": "raw integer token units"
}

Before answering, the API simulates the transaction. If the program would reject it, the response is 422 with a sentence, the Plumb error code if there is one, and the program's last log lines:

{
  "ok": false,
  "error": "Collateral ratio failed, trove is not liquidatable, or redemption requires liquidation first",
  "code": 5,
  "logs": ["Program log: …"]
}

Sending and confirming

curl -X POST "$PLUMB_API/v1/send" \
  -H "content-type: application/json" \
  -d '{"transactionBase64":"<signed>"}'
# {"signature":"5h…"}

curl "$PLUMB_API/v1/signatures/5h…"
# {"signature":"5h…","status":"confirmed","slot":312040560,"failure":null}

/v1/send accepts only signed transactions that call the Plumb program, and simulates them once more with signature checks before forwarding them. status moves from null (not seen yet) through processed and confirmed to finalized. If the transaction failed on chain, failure explains why.

You can also submit signed transactions through any Solana RPC yourself; the relay exists so a browser needs no RPC endpoint of its own.

© 2026 PlumbBorrowing against JitoSOL can end in liquidation. Read the risks before you open a trove.