Skip to content
pinecode

Developers

TypeScript SDK

@pinecode/sdk reference. Recall, contribute, stake, and earn — typed and signed.

Install

bash
-accent">pnpm add @pinecode/sdk

Requires Node 20+. Browser builds ship as ESM. No peer dependencies — ethers v6 is bundled.

Pinecode client

typescript
import { Pinecode, type PinecodeOptions } from class="text-success/90">"@pinecode/sdk";
const pinecode = new Pinecode({
network: class="text-success/90">"base", class=class="text-success/90">"text-fg-subtle italic">// class="text-success/90">"base" | class="text-success/90">"base-sepolia" | { rpcUrl, chainId }
gateway: class="text-success/90">"https:class="text-fg-subtle italicclass="text-success/90">">//api.pinecode.xyz", // override the default gateway
privateKey: process.env.PRIVATE_KEY, class=class="text-success/90">"text-fg-subtle italic">// optional — read-only without it
defaultModel: class="text-success/90">"openai/text-embedding-3-large",
timeoutMs: 8_000,
});

The client is safe to share across requests and threads. It maintains a small recall cache and a nonce queue.

recall()

typescript
type RecallParams = {
query: string;
limit?: number; class=class="text-success/90">"text-fg-subtle italic">// default 5, max 50
minScore?: number; class=class="text-success/90">"text-fg-subtle italic">// 01 similarity threshold
tags?: string[]; class=class="text-success/90">"text-fg-subtle italic">// restrict to seeds tagged with all of these
paymentMax?: string; class=class="text-success/90">"text-fg-subtle italic">// USDC ceiling per call, e.g. class="text-success/90">"0.01"
embeddingModel?: string;
preferIndexer?: string; class=class="text-success/90">"text-fg-subtle italic">// pin to a specific indexer
};
type RecallHit = {
seedId: number;
cid: string;
title?: string;
content: string;
score: number;
contributor: class="text-success/90">`0x${string}`;
contributorEns?: string;
tags: string[];
qualityScore: number;
feePaid: string; class=class="text-success/90">"text-fg-subtle italic">// USDC
};
const hits: RecallHit[] = await pinecode.recall({ query: class="text-success/90">"..." });
Streaming recall
Use pinecode.recall.stream(...) to receive partial results via Server-Sent Events. Useful when you want to start summarizing while the indexer is still ranking.

contribute()

typescript
type ContributeParams = {
content: string | Uint8Array;
title?: string;
source?: string;
tags?: string[];
embeddingModel?: string;
bond?: string; class=class="text-success/90">"text-fg-subtle italic">// PINE bond, default = protocol minimum
};
type ContributeReceipt = {
seedId: number;
cid: string;
txHash: class="text-success/90">`0x${string}`;
bondLocked: string;
};
const receipt = await pinecode.contribute({
content: class="text-success/90">"ERC-4337 introduces UserOperations…",
source: class="text-success/90">"https:class="text-fg-subtle italicclass="text-success/90">">//eips.ethereum.org/EIPS/eip-4337",
tags: [class="text-success/90">"ethereum", class="text-success/90">"erc-4337"],
});

stake()

typescript
await pinecode.stake({
seedId: 418293,
amount: class="text-success/90">"250", class=class="text-success/90">"text-fg-subtle italic">// PINE
duration: class="text-success/90">"30d", class=class="text-success/90">"text-fg-subtle italic">// class="text-success/90">"7d" | class="text-success/90">"30d" | class="text-success/90">"90d" | class="text-success/90">"365d"
});
class=class="text-success/90">"text-fg-subtle italic">// Withdraw after lock expires
await pinecode.unstake({ seedId: 418293, positionId: 42 });

rewards()

typescript
const summary = await pinecode.rewards.summary();
class=class="text-success/90">"text-fg-subtle italic">// { unclaimedUsdc: class="text-success/90">"12.40", unclaimedPinecode: class="text-success/90">"184.2", nextEpoch: class="text-success/90">"2026-05-22T00:00:00Z" }
await pinecode.rewards.claim({ epochs: [142, 143] });

Events & streams

typescript
pinecode.events.on(class="text-success/90">"recall", (e) => {
90">console.log(e.seedId, e.feePaid, e.querier);
});
pinecode.events.on(class="text-success/90">"contribute", (e) => {
90">console.log(e.seedId, e.contributor);
});
const stop = pinecode.events.subscribe({
topics: [class="text-success/90">"challenge", class="text-success/90">"slash"],
fromBlock: class="text-success/90">"latest",
});

Errors

The SDK throws typed errors that you can switch on:

typescript
import { isPinecodeError, PinecodeErrorCode } from class="text-success/90">"@pinecode/sdk";
try {
await pinecode.recall({ query: class="text-success/90">"..." });
} catch (err) {
if (isPinecodeError(err)) {
switch (err.code) {
case PinecodeErrorCode.PaymentExceedsCeiling: /* ... */ break;
case PinecodeErrorCode.GatewayUnavailable: /* ... */ break;
case PinecodeErrorCode.IndexerStale: /* ... */ break;
case PinecodeErrorCode.InsufficientBalance: /* ... */ break;
}
}
}