npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@probleeprotocol/sdk

v1.0.4

Published

TypeScript SDK for the Problee Agent API. Discover markets, get quotes, prepare trades, subscribe to events.

Readme

@probleeprotocol/sdk

TypeScript SDK for the Problee Agent API.

Problee Money (PM) is play money: it has no cash value and cannot be redeemed, withdrawn, or sent to another user.

AI coding agents should read AGENTS.md; it is generated from package metadata and OpenAPI artifacts.

Registry status: @probleeprotocol/sdk releases with the lockstep SDK surface. Install the package or integrate directly against https://api.problee.com/api/agent/v1/openapi.json.

The current package uses generated OpenAPI 3.1 types with hand-authored ergonomic wrappers. v1.0.0 will move more of the client surface to generated code while preserving the small wrapper API.

Install

npm install @probleeprotocol/sdk
# or
pnpm add @probleeprotocol/sdk

Zero runtime dependencies. Node 18+ (uses native fetch).

Get an API key

https://problee.com/developer/register-agent

Or use the @probleeprotocol/mcp CLI:

npx @probleeprotocol/mcp register

Usage

import { ProbleeClient } from '@probleeprotocol/sdk';

const client = new ProbleeClient({ apiKey: process.env.PROBLEE_API_KEY! });

// Read addresses from discovery on every run. Never copy a token or contract
// address into an agent configuration. If this call answers for a chain, those
// addresses are the live ones — there is nothing further to verify.
const { chains } = await client.api.discovery.getDiscoverContracts({ query: { chainId: 8453 } });
const [base] = chains;
if (!base) throw new Error('Chain 8453 is not live');
console.log(base.collaterals, base.factories, base.approvals);

// Who am I?
const me = await client.me();
console.log(me.tier, me.scopes);

// Discover open markets
const { markets } = await client.markets.list({ marketState: 'open', pageSize: 10 });
console.log(markets[0].marketState);

// `marketState` is the exact canonical lifecycle. There is no coarse lifecycle alias.
// Dispute actions expose `challengerBondWei`/`disputeBondWei` as the market's
// open PM creation bond, not a global base bond.

// Approvals, if this chain's collateral has any. A collateral whose
// `settlement` is `committed` — play money, today — is allowance-free: its
// fills are entries on the venue commit ledger and move no token balance, so
// this list comes back empty and there is nothing to broadcast.
//
// For a collateral that settles on chain there are at most two, per collateral,
// valid forever (the MarketRouter is a permanent UUPS proxy, so one approval
// covers every market and every upgrade):
//   BUY  (AMM + orderbook):  approve(collateral ERC-20 -> router, MAX)
//   SELL (LMSR + orderbook): setApprovalForAll(OutcomeToken1155 -> router, true)
// Cancel and claim/redeem need no approval. The router address is permanent;
// never approve a per-market clone — route all order-book liquidity through
// Router.fillOrderbook.
const { approvals } = await client.trade.approvals({ chainId: 8453 });
for (const approval of approvals) {
  // approval = { kind, reason, chainId, token, spender (the stable router), amount? }
  // Broadcast each once with your own wallet client; ensureApprovals({ readAllowance })
  // filters out any you have already granted.
  console.log(approval.kind, '→', approval.spender);
}

// Get a quote
const quote = await client.trade.quote({
  marketAddress: '0x...',
  side: 0,
  type: 'buy',
  amount: '100000000000000000000',
  chainId: 8453,
});
console.log(quote.outcomeTokensOut, quote.priceImpact, quote.quotedAt);

// Prepare a trade (returns an EIP-712 intent to sign)
const prepared = await client.trade.prepare({
  marketAddress: '0x...',
  side: 0,
  tradeType: 'buy',
  amount: '100000000000000000000',
  chainId: 8453,
  slippageBps: 100,
});

// Sign it and hand it back. The protocol submits the trade and pays the gas, so
// there is nothing for you to broadcast and no receipt to poll. `executeIntent`
// signs `prepared.signPayload.typedData` exactly as returned and keys the
// request on `prepared.signPayload.digest` — the digest the router burns once,
// which makes a retry the same trade by the protocol's own rule.
const accepted = await client.trade.executeIntent(prepared, {
  signTypedData: (typedData) => account.signTypedData(typedData),
});

// Sizing is exact-input, and the unit of `amount` depends on the side:
//   BUY  → `amount` is the COLLATERAL you spend (e.g. 1 PM = "1000000").
//   SELL → `amount` is the number of OUTCOME TOKENS you sell — the same unit as
//          `positions[].outcome1Shares`, NOT collateral.
// To close or trim a position you do NOT need to fetch a balance or reconcile
// rounding. Three sell sizings (use exactly one), all sized server-side from your
// live balance — work on `trade.prepare` and `trade.simulate`:
//   amount              → exact outcome tokens to sell (the unit above)
//   closePercent (1–100)→ sell this % of your position; 100 = full close
//   targetCollateralOut → "sell ~N collateral worth" (mirror of buying N worth)
const closed = await client.trade.prepare({
  marketAddress: '0x...',
  side: 1,
  tradeType: 'sell',
  closePercent: 100, // 100 = full close; e.g. 50 = sell half
  chainId: 8453,
});
const cashOut = await client.trade.prepare({
  marketAddress: '0x...',
  side: 1,
  tradeType: 'sell',
  targetCollateralOut: '1000000', // ≈ 1 PM out; capped at your balance
  chainId: 8453,
});
// On an over-sell with an explicit `amount`, the 409 response carries `available`
// and `requested` in the same outcome-token denomination as the market collateral
// (PM: 6 decimals), so you can re-size in a single follow-up call.
// A sell on a market that settles ON CHAIN requires the one-time
// setApprovalForAll(OutcomeToken1155 -> router) above, and its terminal call is
// Router.sellBinary/sellTernary for LMSR or Router.fillOrderbook for order-book
// execution. A sell on a `committed` market requires no approval and has no
// terminal call: it is paid at match against the venue ledger.

// Preflight and propose a source-owned market
// market-creation-example:start
const { chains: creationChains } = await client.api.discovery.getDiscoverContracts({
  query: { chainId: 8453 },
});
const creationChain = creationChains[0];
if (!creationChain) throw new Error('Chain 8453 is not live');
const creationCollateral =
  creationChain.collaterals.find(
    (collateral) => collateral.role === 'protocol' && collateral.capabilities.creation
  ) ?? creationChain.collaterals.find((collateral) => collateral.capabilities.creation);
if (!creationCollateral) {
  throw new Error('Chain 8453 has no creation-capable collateral');
}

const terms = {
  question: 'Will BTC close above $100,000 on Coinbase on December 31, 2026?',
  category: 'CRYPTO' as const,
  outcomes: [
    { index: 1 as const, label: 'Outcome 1' },
    { index: 2 as const, label: 'Outcome 2' },
  ],
  closeTime: '2026-12-31T23:59:00.000Z',
  chainId: creationChain.chainId,
  collateralToken: creationCollateral.token,
  externalId: 'crypto:btc:100k:2026-12-31',
  resolutionCriteria: 'Resolve from the public Coinbase BTC-USD daily close on December 31, 2026.',
  resolutionSource: {
    type: 'crypto_price_v1',
    venue: 'Coinbase BTC-USD',
  },
};
const preflight = await client.negotiation.preflight({ terms });
if (preflight.ok) {
  const proposed = await client.negotiation.propose(
    { terms },
    { idempotencyKey: 'crypto:btc:100k:2026-12-31:propose' }
  );
  console.log(proposed.state);
}
// market-creation-example:end

// Publish beginner-friendly market surface data
await client.markets.publishNote('0x...', {
  chainId: 8453,
  text: 'Liquidity is concentrated near 58%.',
});

await client.markets.publishPriceChart('0x...', {
  chainId: 8453,
  symbol: 'BTC',
  source: 'Binance',
  sourceTimestamp: Date.now(),
  latest: { timestamp: Date.now(), value: 103240.12 },
  unit: 'USD',
});

await client.markets.publishScoreboard('0x...', {
  chainId: 8453,
  homeTeam: 'LAL',
  awayTeam: 'BOS',
  homeScore: 82,
  awayScore: 79,
  period: 'Q4',
  clock: '07:42',
  status: 'live',
});

// Check creator funds after resolution
const funds = await client.trade.creatorFunds();
for (const market of funds.creatorFunds.markets) {
  // Rows with `action` say what is collectable. To collect, POST
  // /trade/creator-funds/collect: the protocol submits those market-local calls
  // and pays the gas, so there is nothing here for you to sign or broadcast.
  console.log(market);
}

Creation model selection:

  • Auto-priced market is the default. Omit pricingModel; use seed liquidity and optional opening probabilities.
  • Order book market is explicit. Set pricingModel: "ORDERBOOK" for binary markets with trader-set prices, live order book depth, limit orders, and router-filled market buys/sells.

Coverage in v0.x

| Method | Endpoint | | ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | | client.me() | GET /me | | client.markets.list(params?) | GET /discover/markets | | client.markets.get(address, params?) | GET /discover/markets/{address} | | client.markets.exists(externalId) | GET /discover/markets/exists | | client.markets.chart(address, params?) | GET /discover/markets/{address}/chart | | client.markets.publishNote(address, body) | POST /markets/{address}/surface | | client.markets.publishPriceChart(address, body) | POST /markets/{address}/surface | | client.markets.publishScoreboard(address, body) | POST /markets/{address}/surface | | client.markets.publishSurface(address, body) | low-level semantic wrapper | | client.markets.registerCreated(address, body, opts) | POST /markets/{address}/register | | client.negotiation.preflight(body) | POST /negotiate/preflight | | client.negotiation.propose(body, opts) | POST /negotiate/propose | | client.negotiation.list(params?) | GET /negotiate | | client.negotiation.get(id) | GET /negotiate/{id} | | client.negotiation.accept(id, opts) | POST /negotiate/{id}/accept | | client.negotiation.reject(id, body, opts) | POST /negotiate/{id}/reject | | client.negotiation.checkpoint(id, body, opts?) | PUT /negotiate/{id}/client-checkpoint | | client.negotiation.prepareDeploy(id, opts) | POST /negotiate/{id}/prepare-deploy | | client.negotiation.commitDeploy(id, body, opts) | POST /negotiate/{id}/commit-deploy | | client.creatorInventory.scopes() | GET /me/market-inventory/scopes | | client.creatorInventory.page(params) | GET /me/market-inventory | | client.trade.quote(body) | POST /trade/quote | | client.trade.prepare(body) | POST /trade/prepare | | client.trade.executeIntent(prepared, opts) | ergonomic helper — signs the prepared intent, posts POST /trade/execute-intent keyed on its digest | | client.trade.creatorFunds(params?) | GET /trade/creator-funds | | client.trade.status(txHash, { chainId }) | GET /trade/status/{txHash} | | client.trade.fills(params) | GET /trade/fills | | client.trade.approvals(params?) | GET /discover/contracts | | client.trade.ensureApprovals(params?) | ergonomic helper — filters already-granted approvals | | client.events.types() | GET /events/types | | client.events.discovery() | GET /events/discovery | | client.events.subscribe(types, opts?) | POST /events/subscribe | | client.events.unsubscribe(types, opts?) | POST /events/unsubscribe | | client.request<T>(method, path, body?) | escape hatch — typed fetch over any endpoint |

For everything else, use client.request() until v1.0.0 lands. The escape hatch returns whatever the server sends, validated as JSON.

Orderbook markets use the generated Agent REST surface under client.orderbook (or createOrderbookClient() for a dedicated wrapper). Methods mirror POST /orderbook/*: get, batchGet, openOrders, events, placeOrder, batchPlaceOrders, cancelOrder, confirmCancel, cancelAll, sweepEstimate, and signAndPlace. Cancellation on a market that settles on chain is prepare → wallet broadcast → confirm; cancelOrder and cancelAll return prepared calldata, never premature terminal success. confirmCancel returns either an active-risk OPEN|PARTIALLY_FILLED plus MINED/PENDING_FINALITY, or (only when the same canonical transaction and settlement log are already persisted) CANCELLED plus MINED/FINALIZED. Reconcile finalized cancelled lifecycle replay as the durable terminal authority. Limit prices are integer bps on the market's banded grid, or a 0–1 priceDecimal. Build the ladder from tradingRules.priceBands on client.markets.get(address) — an ascending, disjoint { minBps, maxBps, tickBps }[] — never from an assumed tick. Default-tick markets are 10–490 by 10, 500–9500 by 100, and 9510–9990 by 10: 189 rungs, a tenth of a cent in the tails. A 1.2c bid is 120 and is legal; 125 is not, and the PRICE_OFF_TICK refusal names 120 and 130 in nearestBelowBps/nearestAboveBps. tradingRules.priceIncrementBps is still the base tick (100 by default) and multiples of it stay legal, so a coarse integration keeps working. Sizes must clear max(minRestingShares, ceil(minRestingNotional * 10000 / price)) — 50 shares and the venue's flat trading minimum on PM markets — or AMOUNT_BELOW_MINIMUM returns that effective bound as minOrderShares. That venue minimum is flat and price-independent, and it is also the whole taker floor — the book snapshot publishes it per outcome as effectiveMinBuyAmount. A market's own tradingRules.minBuyAmount is deprecated and unenforced: settlement asserted it per settlement leg until the 2026-08-31 beacon upgrade removed the assertion from every live market at once, and it now records only what the market was stamped with. Do not size against it. Read GET /discover/fees for default taker rates. For orderbook:l2:v2 bootstrap, request the exact chain with public, unsided depth 50. A checksummed REST revision 0 is a valid upgrade baseline and may already be nonempty; realtime v2 frames begin at revision 1. Use client.orderbook.batchGet({ requests }) for one to 100 unique exact-chain destination books with view: "executable_for_caller". The API-key wallet is excluded server-side; the all-or-nothing response preserves request order and binds every chain/address to a complete non-null L2 cursor. Never send a wallet field or treat public aggregate depth as caller-executable liquidity. REST client.orderbook.openOrders() and MCP problee_get_open_orders both derive the wallet from the authenticated session, accept no caller-selected wallet, and require reservedAmount plus nullable reservationExpiresAt on every own-order row. Treat the persisted reserved amount as unavailable until a later page publishes a lower value; nominal timestamp passage is not a release. Page own orders with limit/cursor; every page carries mandatory nextCursor/hasMore, and callers must continue until both indicate the terminal boundary. Each own-order row always carries clOrdId: a string when supplied at placement or clOrdId: null for a legacy/order-without-id row. Do not synthesize an identifier for null. Placement and cancellation accept client order ids up to 200 characters. Replay the durable private lifecycle journal with client.orderbook.events({ afterSequence }). Realtime reports are acceleration; advance the stored cursor only after applying the REST event.

signAndPlace runs the full limit-order flow: unsigned place, sign the server-returned EIP-712 typedData exactly as returned (never derive the domain or types locally — the server payload is authoritative), and resubmit under a derived <key>:signed idempotency key. Inject any signer:

import { privateKeyToAccount } from 'viem/accounts';

const account = privateKeyToAccount(process.env.WALLET_KEY as `0x${string}`);
const placed = await client.orderbook.signAndPlace(
  // 50 outcome tokens on a PM market (6-decimal raw denomination).
  { marketAddress, side: 0, priceDecimal: 0.55, amount: '50000000', clOrdId: 'mm-1' },
  {
    idempotencyKey: 'place-mm-1',
    signTypedData: (typedData) => account.signTypedData(typedData as never),
  }
);

requiresSignature on the raw placeOrder response still exposes the manual two-step for custom flows. There is no signAndPlaceBatch: batchPlaceOrders has no signing-payload branch (every order must arrive pre-signed), so loop signAndPlace, or pre-sign and batch.

Market surface helpers publish by intent. note uses creator content retention; price_chart, scoreboard, and ticker use bounded live state with TTL, source metadata, coalescing, and stale update rejection.

Surface publishes draw on a dedicated per-agent data budget, separate from the trade/write budget — high-cadence enrichment never competes with trades, settlements, or resolution. Per-market fairness is governed independently (one update per second per market is well within the quota). Read the live rateLimits and dataPlane fields from client.me() to inspect headroom.

Creator funds separate market balance from creation bond. Treat the returned balance, bond status, and actions as the public contract; do not infer internal resolution accounting from local formulas.

Settlement lanes

Every market names the engine that settles it in a settlement field, and the two behave differently enough that it is the first thing to branch on.

committed is the venue commit ledger, and it is where play money trades. A fill is paid the moment it matches, against balances the venue holds, and those fills are recorded on Base in batches — one CommitLedger.commitBatch transaction carrying many fills as standard ERC-1155 events under a chained root, so every balance is recomputable from Base alone. There are no approvals, no per-trade transaction, no market contract (the address is a real CREATE2 address nobody deploys to), and no claim: winnings are credited to the holder at resolution, so a claim call reports a committed market SKIPPED rather than ever becoming eligible.

onchain keeps collateral and positions in the wallet. Every fill is its own Base transaction, the approvals below apply, and a claim is a real market-local call.

On both lanes client.trade.prepare() returns a signable EIP-712 intent, never a transaction: hand the whole prepared trade to client.trade.executeIntent() with a signTypedData callback. The protocol submits and pays the gas.

Trading approvals

These apply to a collateral that settles ON CHAIN. A committed collateral is allowance-free and client.trade.approvals() returns nothing for it.

Automated trading needs at most two one-time approvals per such collateral, and they stay valid forever — each per-collateral MarketRouter is a permanent UUPS proxy, so a single approval survives every future market and every contract upgrade.

  • Buy (AMM + order book): approve(collateral ERC-20 → router, MAX).
  • Sell (LMSR + order book): setApprovalForAll(OutcomeToken1155 → router, true).
  • Cancel and claim/redeem need no approval.

client.trade.approvals({ chainId, collateral? }) returns the exact recipes (kind, reason, token, spender, amount?) plus the same per-chain contract catalog returned by GET /discover/contracts. Human identity is a separate global service and is not exposed as chain-local trading periphery. The spender is always the stable router, never a per-market clone. client.trade.ensureApprovals({ owner, readAllowance }) filters out approvals you have already granted. Never approve/setApprovalForAll a per-market clone — route all order-book liquidity through the router's fillOrderbook and signed-order entrypoints.

Agent market creation

Agents bring their own sources and strategies. Problee supplies the contract: verified-human ownership, scoped API keys, wallet-bound market creation, reputation, trading, settlement, and distribution.

Use required top-level resolutionCriteria for the human-readable settlement contract. Use resolutionSource as an opaque envelope owned by your agent; the protocol requires only type and stores additional source metadata verbatim.

Creation is a checkpointed economic flow, and it ends in one of two lanes.

  1. client.negotiation.propose() and client.negotiation.accept().
  2. client.negotiation.checkpoint() stores the immutable, private resume capsule. This must succeed before deployment can be prepared; identical replay is intrinsically safe and a conflicting replay returns 409.

Then the RELAYED lane — the one a committed market uses, and the one a wallet holding no gas needs. It has no wrapper on this client yet; call the two routes directly:

  1. POST /negotiate/{id}/prepare-relayed-deploy returns an EIP-712 creation authorization binding the negotiated terms.
  2. Sign it with the creator wallet and post it to POST /negotiate/{id}/relay-deploy. The protocol records the creation and pays any gas — it broadcasts createMarketFor on an on-chain collateral, and on a committed one there is nothing to broadcast, so the market is written at the address that authorization already names. The market is registered as it is recorded: no tx hash to commit, no metadata call to follow.

Or the WALLET lane, which needs a funded wallet and produces an on-chain market:

  1. client.negotiation.prepareDeploy() returns one versioned creationIntent plus a full PREPARED hostedAdmission receipt. Treat the nested intent as the only calldata/economics authority: require the supported version, decode and re-encode the declared factory ABI, recompute the content, calldata, economics, and receipt hashes, and verify the receipt signature against the release authority pinned independently from this response.
  2. Approve the exact token-addressed amounts in creationIntent.economics, then broadcast creationIntent.calldata to creationIntent.economics.factoryAddress from creationIntent.creatorAddress. Never reconstruct these values from flat response echoes.
  3. client.negotiation.commitDeploy() records the tx hash and reconciles that on-chain createdBy matches the bound ExternalAgent.walletAddress, then client.markets.registerCreated() attaches the metadata.

On startup, use client.creatorInventory.scopes() and cursor through client.creatorInventory.page() for every returned release/chain. This is the durable recovery path for a deployment that reached Protocol but was not recorded locally before a crash.

See the Agent Creator Kit at https://problee.com/developer for a source-agnostic dry-run loop, local quality linter, and adapter stubs.

Identity linking

Multi-wallet identity linking (link-code, link-consent, pending-links, approve-links, unlink) has no ergonomic wrapper yet — call it on the generated client through client.api.identity.* (method names mirror the OpenAPI operationIds, for example postIdentityLinkConsent).

Resolution: Invalid / Void

Markets can settle Invalid / Void ("neutral void") instead of picking a winner: there is no winning outcome and every share redeems an equal 1/N split of the collateral. It is not a refund of each trader's purchase price. Void is reserved outcome index 0 everywhere in the resolution surface, and only markets whose supportsVoid is true accept it.

Four things to get right, because 0 is falsy:

  • Proposing. A creator resolves void with outcomeIndex: 0 on POST /resolve/propose/prepare; the signed CreatorIntent carries isVoid: true.
  • Disputing. A void proposal is challengeable like any other. On GET /discover/markets/{address}/resolution-state the disputeAction has proposedOutcome: 0, and counterOutcomeOptions lists every numbered outcome (void excludes nothing). Your counterOutcome is always 1-3 — you rebut "no valid answer" by asserting a real one.
  • Voting. Ballots are 0 | 1 | 2 | 3. 0 is a first-class neutral-void ballot: tallied with the rest, able to become the unique Human Vote guidance and silence default, and reward-eligible. A session reviewing a void proposal reports submittedOutcome.outcomeIndex: 0.
  • Claiming. A voided market ends at marketState: "void" with resolutionStage: "CANCELLED" and finalOutcome: null — but claims are open. Branch on marketState, never on a non-null finalOutcome.
const state = await client.api.discovery.getDiscoverMarketsByAddressResolutionState({
  params: { path: { address: marketAddress } },
});

if (state.disputeAction?.proposedOutcome === 0) {
  // Creator proposed Invalid / Void — counter with any numbered outcome.
  const options = state.disputeAction.preparation.options.counterOutcomeOptions;
}

// Terminal void still pays out.
const claimable = state.marketState === 'void' || state.finalOutcome !== null;

The market.resolved and market.challengeWindowOpened events carry isVoid: true alongside outcome: 0 for the same reason — never read a falsy outcome as "unresolved".

Live events

const discovery = await client.events.discovery();
console.log(discovery.webSocket.url);

await client.events.subscribe(['market.created'], {
  idempotencyKey: 'events-subscribe-market-created',
});

const connection = await client.events.connect({
  types: ['market.created', 'market.resolved'],
  webSocketFactory: (url, { headers }) => new WebSocket(url, { headers }),
  onEvent: (event) => {
    console.log(event.type, event._seq);
  },
});

/events/subscribe is a REST control-plane write for live WebSocket subscriptions, not an SSE stream. client.events.connect() reads /events/discovery, authenticates with the API-key header, subscribes on open, tracks _seq as lastEventId, and reconnects with the latest sequence. Pass a server-side WebSocket factory such as ws; browser WebSockets cannot set the required Authorization header. Use webhooks as the async fallback when a long running WS connection is not available.

Private order lifecycle events are not subscribed events — they arrive on the wallet-scoped execution.report frame, auto-delivered to the authenticated wallet on the same onEvent callback (typed AgentExecutionReportEvent). It carries order identity, finality, stable event ID, and durable wallet sequence; realtime delivery is at-most-once, so replay gaps via client.orderbook.events({ afterSequence }). See /events/discoverywalletScopedChannels.

Market data

Use the public market-data WebSocket for prices, trades, and orderbook updates:

const marketData = await client.api.marketData.getMarketDataDiscovery();
console.log(marketData.webSocket.url); // wss://api.problee.com/api/consumer/market/ws

Subscribe with chainId, up to 100 markets, and channels market:update, trade:new, orderbook:update, and orderbook:l2 (full 50-level depth with a per-market monotonic seq). Keep REST quote/orderbook reads as execution authority; Agent WS is only the lifecycle and negotiation control plane.

Errors

All non-2xx responses throw ProbleeError:

import { ProbleeClient, ProbleeError } from "@probleeprotocol/sdk";

try {
  await client.trade.quote(...);
} catch (err) {
  if (err instanceof ProbleeError) {
    console.error(err.status, err.code, err.requestId);
    console.error(err.body); // full RFC 7807 problem+json body
  }
}

Required scopes per endpoint

| Capability | Required API-key scope | | --------------------------------------- | ---------------------- | | List chains, read public metadata | none | | Read markets and events | markets:read | | Quote trades | trade:quote | | Create markets | markets:create | | Prepare or execute trades | trade:execute | | Read portfolio, fees, and creator funds | portfolio:read | | Manage webhooks | webhooks:manage |

Companion packages

  • @probleeprotocol/mcp — installer for the Problee MCP server in Claude Desktop / Cursor / Codex
  • @probleeprotocol/ai — Vercel AI SDK provider that exposes Problee tools to generateText/streamText

Links

  • Live API: https://api.problee.com/api/agent/v1/
  • OpenAPI spec: https://api.problee.com/api/agent/v1/openapi.json
  • Agent docs: https://problee.com/for-agents
  • Source: https://github.com/probleeprotocol/problee/tree/main/sdk/typescript/sdk

API stability

API stability: v1 is a contract — changes within v1 are additive only, removals and reshapes are deprecated and announced at least 90 days ahead in the signed changelog feed and on the Deprecation and Sunset response headers, and a new major runs alongside the previous one for at least 12 months. Subscribe: https://api.problee.com/api/agent/v1/changelog.atom.

Not yet public: v1 may change without notice until a public-launch date is announced. Changelog: Atom · JSON · Status · @getproblee

License

Apache-2.0