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

# counsel-js SDK: Complete Method and TypeScript Reference

> Full method reference for the Counsel class: constructor, markets, betIntent, placeBet, positions, leaderboard, and all TypeScript interfaces.

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`

```typescript theme={null}
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`

```typescript theme={null}
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.

<ParamField path="baseUrl" type="string" required>
  Base URL of the counsel deployment. Use `https://api.counsel.markets` for the hosted instance.
</ParamField>

<ParamField path="wss" type="string">
  XRPL WebSocket node URL used by `placeBet` when connecting to the ledger. Defaults to the XRPL testnet (`wss://s.altnet.rippletest.net:51233`).
</ParamField>

```typescript theme={null}
const counsel = new Counsel({
  baseUrl: "https://api.counsel.markets",
  wss: "wss://xrplcluster.com", // omit to use testnet
});
```

***

## `markets()`

```typescript theme={null}
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**

<ResponseField name="markets" type="MarketV1[]">
  Array of all markets currently tracked by the counsel indexer.
</ResponseField>

<ResponseField name="source_tag" type="number | null">
  The SourceTag counsel expects on all Payment transactions. Automatically applied by `placeBet`.
</ResponseField>

```typescript theme={null}
const { markets } = await counsel.markets();
const open = markets.filter(m => m.status === "open");
```

***

## `market(id: string)`

```typescript theme={null}
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.

<ParamField path="id" type="string" required>
  The market ID, a hex string such as `"9b6a290b0cc8c5be"`.
</ParamField>

**Returns**

<ResponseField name="(root)" type="Record<string, unknown>">
  The raw market object. Shape matches a single entry from the `markets()` array.
</ResponseField>

```typescript theme={null}
const m = await counsel.market("9b6a290b0cc8c5be");
```

***

## `betIntent(id, account, outcome, amountXrp)`

```typescript theme={null}
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.

<ParamField path="id" type="string" required>
  Market ID.
</ParamField>

<ParamField path="account" type="string" required>
  Your XRPL address (e.g. `"rYourAddress..."`). Used as the `Account` field in the unsigned `Payment`.
</ParamField>

<ParamField path="outcome" type="number" required>
  Zero-based index of the outcome you want to bet on. Corresponds to `OutcomeV1.index` in the market's `outcomes` array.
</ParamField>

<ParamField path="amountXrp" type="number" required>
  Stake in XRP (not drops). For example, `5` means 5 XRP.
</ParamField>

**Returns**

<ResponseField name="tx" type="Payment">
  Unsigned XRPL Payment transaction. Pass to `client.autofill()` then `wallet.sign()`.
</ResponseField>

<ResponseField name="pool_account" type="string">
  The XRPL address of the market's pool account (the Payment destination).
</ResponseField>

<ResponseField name="destination_tag" type="number">
  The DestinationTag identifying the outcome on the pool account.
</ResponseField>

<ResponseField name="source_tag" type="number">
  The SourceTag counsel requires for attribution. Already embedded in `tx`.
</ResponseField>

<ResponseField name="amount_xrp" type="number">
  Confirmed stake in XRP as the server interpreted it.
</ResponseField>

<ResponseField name="projected_implied_odds_after" type="object">
  Parimutuel odds for this outcome after your stake is included.

  <ResponseField name="implied_prob" type="number">
    Implied probability (0-1) of this outcome after your stake.
  </ResponseField>

  <ResponseField name="payout_per_unit" type="number | null">
    Net payout per 1 XRP staked if this outcome wins, after fees. `null` if the pool would be zero.
  </ResponseField>
</ResponseField>

<ResponseField name="market" type="object">
  Compact market summary for display or logging.

  <ResponseField name="id" type="string">Market ID.</ResponseField>
  <ResponseField name="question" type="string">Human-readable market question.</ResponseField>
  <ResponseField name="outcome" type="number">Outcome index you bet on.</ResponseField>
  <ResponseField name="outcome_label" type="string">Human-readable label for the outcome.</ResponseField>
</ResponseField>

```typescript theme={null}
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)`

```typescript theme={null}
positions(address: string): Promise<{ account: string, positions: unknown[] }>
```

Fetches all open and settled positions for the given XRPL address.

<ParamField path="address" type="string" required>
  The XRPL address to query. Must be a valid r-address.
</ParamField>

**Returns**

<ResponseField name="account" type="string">
  The address that was queried.
</ResponseField>

<ResponseField name="positions" type="unknown[]">
  Array of position objects, one per bet the address has placed. Each entry includes the market, outcome, stake, and settlement state.
</ResponseField>

```typescript theme={null}
const { positions } = await counsel.positions("rYourAddress");
console.log(`${positions.length} positions found`);
```

***

## `leaderboard()`

```typescript theme={null}
leaderboard(): Promise<Record<string, unknown>>
```

Fetches the global leaderboard, ranking participants by volume or profit across all resolved markets.

**Returns**

<ResponseField name="(root)" type="Record<string, unknown>">
  The leaderboard payload. Schema may evolve; treat as a raw object until a stable shape is published.
</ResponseField>

```typescript theme={null}
const lb = await counsel.leaderboard();
```

***

## `placeBet(seed, id, outcome, amountXrp)`

```typescript theme={null}
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.

<ParamField path="seed" type="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.
</ParamField>

<ParamField path="id" type="string" required>
  Market ID.
</ParamField>

<ParamField path="outcome" type="number" required>
  Zero-based outcome index.
</ParamField>

<ParamField path="amountXrp" type="number" required>
  Stake in XRP.
</ParamField>

**Returns**

<ResponseField name="(root)" type="string">
  The validated transaction hash from the ledger (`res.result.hash`), confirmed `tesSUCCESS`.
</ResponseField>

```typescript theme={null}
const hash = await counsel.placeBet(
  process.env.BOT_SEED!,
  "9b6a290b0cc8c5be",
  0,   // outcome
  5,   // XRP
);
console.log("validated tx:", hash);
```

<Warning>
  `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.
</Warning>
