Skip to main content
This page documents every method on the Counsel class exported from counsel.ts. Each method corresponds to a single endpoint on the counsel public API. All methods are async and throw on non-2xx responses. The placeBet method additionally throws if the XRP Ledger returns any result other than tesSUCCESS.

Interfaces

The following TypeScript interfaces are exported directly from counsel.ts. Import them alongside the class for typed access to return values.

CounselOptions

export interface CounselOptions {
  /** Base URL of a counsel deployment, e.g. https://api.counsel.markets */
  baseUrl: string;
  /** XRPL node to submit on (testnet by default). */
  wss?: string;
}

BetIntent

export interface BetIntent {
  tx: Payment;
  pool_account: string;
  destination_tag: number;
  source_tag: number;
  amount_xrp: number;
  projected_implied_odds_after: { implied_prob: number; payout_per_unit: number | null };
  market: { id: string; question: string; outcome: number; outcome_label: string };
}
Payment is the xrpl package’s unsigned transaction type. tx is passed directly to client.autofill() and wallet.sign() inside placeBet.

constructor(opts: CounselOptions)

Instantiates the client. No network connection is made at construction time.
baseUrl
string
required
Base URL of the counsel deployment. Use https://api.counsel.markets for the hosted instance.
wss
string
XRPL WebSocket node URL used by placeBet when connecting to the ledger. Defaults to the XRPL testnet (wss://s.altnet.rippletest.net:51233).
const counsel = new Counsel({
  baseUrl: "https://api.counsel.markets",
  wss: "wss://xrplcluster.com", // omit to use testnet
});

markets()

markets(): Promise<{ markets: MarketV1[], source_tag: number | null }>
Fetches all public markets, including live pool sizes, implied probabilities per outcome, and current phase. Use this to discover open markets and read indicative odds before placing a bet. MarketV1 fields include: id, question, family, phase, status ("open" | "resolved" | "void"), pool_account, fee_rate, bet_cutoff, resolution_time, total_xrp, total_drops, and an outcomes array. Each outcome in outcomes carries: index, label, destination_tag, pool_drops, pool_xrp, bets, implied_prob, and payout_per_unit. Returns
markets
MarketV1[]
Array of all markets currently tracked by the counsel indexer.
source_tag
number | null
The SourceTag counsel expects on all Payment transactions. Automatically applied by placeBet.
const { markets } = await counsel.markets();
const open = markets.filter(m => m.status === "open");

market(id: string)

market(id: string): Promise<Record<string, unknown>>
Fetches a single market by its ID. Returns the full market object including all outcome pools and resolution metadata.
id
string
required
The market ID, a hex string such as "9b6a290b0cc8c5be".
Returns
(root)
Record<string, unknown>
The raw market object. Shape matches a single entry from the markets() array.
const m = await counsel.market("9b6a290b0cc8c5be");

betIntent(id, account, outcome, amountXrp)

betIntent(
  id: string,
  account: string,
  outcome: number,
  amountXrp: number
): Promise<BetIntent>
Fetches an unsigned bet intent for the specified outcome and stake. The server computes the projected odds after your stake is added to the pool, so you can check slippage before signing. No transaction is submitted; nothing is sent to the ledger at this point.
id
string
required
Market ID.
account
string
required
Your XRPL address (e.g. "rYourAddress..."). Used as the Account field in the unsigned Payment.
outcome
number
required
Zero-based index of the outcome you want to bet on. Corresponds to OutcomeV1.index in the market’s outcomes array.
amountXrp
number
required
Stake in XRP (not drops). For example, 5 means 5 XRP.
Returns
tx
Payment
Unsigned XRPL Payment transaction. Pass to client.autofill() then wallet.sign().
pool_account
string
The XRPL address of the market’s pool account (the Payment destination).
destination_tag
number
The DestinationTag identifying the outcome on the pool account.
source_tag
number
The SourceTag counsel requires for attribution. Already embedded in tx.
amount_xrp
number
Confirmed stake in XRP as the server interpreted it.
projected_implied_odds_after
object
Parimutuel odds for this outcome after your stake is included.
implied_prob
number
Implied probability (0-1) of this outcome after your stake.
payout_per_unit
number | null
Net payout per 1 XRP staked if this outcome wins, after fees. null if the pool would be zero.
market
object
Compact market summary for display or logging.
id
string
Market ID.
question
string
Human-readable market question.
outcome
number
Outcome index you bet on.
outcome_label
string
Human-readable label for the outcome.
const intent = await counsel.betIntent(
  "9b6a290b0cc8c5be",
  "rYourAddress",
  0,    // outcome index
  5,    // XRP
);
console.log("implied prob after bet:", intent.projected_implied_odds_after.implied_prob);
console.log("payout per XRP if win:", intent.projected_implied_odds_after.payout_per_unit);

positions(address: string)

positions(address: string): Promise<{ account: string, positions: unknown[] }>
Fetches all open and settled positions for the given XRPL address.
address
string
required
The XRPL address to query. Must be a valid r-address.
Returns
account
string
The address that was queried.
positions
unknown[]
Array of position objects, one per bet the address has placed. Each entry includes the market, outcome, stake, and settlement state.
const { positions } = await counsel.positions("rYourAddress");
console.log(`${positions.length} positions found`);

leaderboard()

leaderboard(): Promise<Record<string, unknown>>
Fetches the global leaderboard, ranking participants by volume or profit across all resolved markets. Returns
(root)
Record<string, unknown>
The leaderboard payload. Schema may evolve; treat as a raw object until a stable shape is published.
const lb = await counsel.leaderboard();

placeBet(seed, id, outcome, amountXrp)

placeBet(
  seed: string,
  id: string,
  outcome: number,
  amountXrp: number
): Promise<string>
End-to-end helper: fetches a bet intent, signs it locally using Wallet.fromSeed(seed), autofills ledger sequence fields via client.autofill(), signs with wallet.sign(), submits with client.submitAndWait(), and verifies tesSUCCESS before returning. Opens an XRPL WebSocket connection for the duration of the call, then disconnects. The seed is never sent to the counsel server.
seed
string
required
The bettor’s XRPL wallet seed. Passed to Wallet.fromSeed() entirely client-side. Only the derived account address is sent to the counsel API.
id
string
required
Market ID.
outcome
number
required
Zero-based outcome index.
amountXrp
number
required
Stake in XRP.
Returns
(root)
string
The validated transaction hash from the ledger (res.result.hash), confirmed tesSUCCESS.
const hash = await counsel.placeBet(
  process.env.BOT_SEED!,
  "9b6a290b0cc8c5be",
  0,   // outcome
  5,   // XRP
);
console.log("validated tx:", hash);
placeBet throws if the ledger returns any result other than tesSUCCESS. The error message includes the ledger result code (e.g. "ledger rejected: tecUNFUNDED_PAYMENT"). Handle this in production bots, insufficient balance, sequence conflicts, and other ledger errors all surface here.