@leashmarket/sdk
v0.3.3
Published
Typed Leash API client for app developers. Discover services, vet counterparties, manage agent webhooks, and ingest receipts in any TypeScript runtime.
Downloads
154
Readme
@leashmarket/sdk
Typed TypeScript client for the public Leash API. Use it from any JavaScript runtime — browsers, Bun, Deno, Node, edge — to:
- Search the agent marketplace (
leash.discover) - Resolve and verify agent identities (
leash.resolveIdentity,leash.verifyIdentity) - Ask for trust verdicts before agent-to-agent calls (
leash.verifyIdentityDecision,leash.verifyCapabilitySeller) - Read shareable selective-disclosure links (
leash.readIdentityDisclosure) - Update the active agent's handle, capability cards, claims, domains, and selective disclosures with X-Leash-Sig
- Vet a counterparty's reputation (
leash.reputation) - Record a client-minted agent on the platform (
leash.recordAgent) - Create/list/revoke agent-owned API keys with X-Leash-Sig
- Manage agent-scoped webhooks signed with X-Leash-Sig
- Pull receipts for an agent (legacy API-key auth)
- Create + manage x402/MPP payment links, including upstream API paywalls with expected POST body metadata (legacy API-key auth)
Provisioning agents (generating keypairs, minting MPL Core assets, setting USDC delegation) is not in the SDK — use
@leashmarket/mcp(mintAgentLocally()) or theleash agent createCLI for that. The SDK is for "remote control" of agents that already exist; the MCP is the engine that creates them.
Install
pnpm add @leashmarket/sdk
# or
npm install @leashmarket/sdkQuickstart
import { LeashClient } from '@leashmarket/sdk';
const leash = new LeashClient({ baseUrl: 'https://api.leash.market' });
// 1. Marketplace browse — public, no auth.
const services = await leash.discover({ capability: 'ocr', max_price_usdc: 0.1 });
const first = services.items[0];
if (first.seller_identity) {
console.log('seller identity', first.seller_identity.mint, first.seller_identity.reputation);
}
// 2. Reputation lookup before paying — public, no auth.
const rep = await leash.reputation({
agentMint: services.items[0].seller_agent_mint!,
});
if (rep.rating < 0.5) throw new Error('seller has too low a rating');
// 3. Resolve or verify identity selectors — public, no auth.
const profile = await leash.resolveIdentity({ handle: 'payce-demo' });
const verdict = await leash.verifyIdentity({ mint: profile.mint });
if (!verdict.verified) throw new Error('identity did not verify');
const decision = await leash.verifyIdentityDecision({
selector: { mint: profile.mint },
intent: 'pay',
capability: { slug: 'agentmail/email', protocol: 'x402' },
thresholds: { require_verified_domain: true },
});
if (decision.verdict === 'deny') throw new Error('seller did not pass trust checks');
const sellerDecision = await leash.verifyCapabilitySeller({
selector: { mint: profile.mint },
capability: { slug: 'agentmail/email', protocol: 'x402' },
});
if (sellerDecision.verdict === 'deny') throw new Error('capability seller did not verify');
// Disclosure links reveal only resources the identity owner shared.
const disclosed = await leash.readIdentityDisclosure('lsh_disclosure_token');
console.log(disclosed.resources.capability_cards);
// 4. Record a client-minted agent — public, no auth (idempotent on
// `mint`). Mint + delegate the asset locally with `@leashmarket/mcp`'s
// `mintAgentLocally` first, then hand the result here.
const recorded = await leash.recordAgent({
mint: 'BcN4ToBs8jE3dbYNhYqDJqGnKPjH3zRX8gsDUDH72JQp',
executive_pubkey: '947dU4Nk8HsdkFcrVip5Zt9XLnfFF5iJSvepEArdr5Ma',
name: 'my-experimental-bot',
network: 'solana-devnet',
});
console.log('recorded', recorded.mint, 'treasury', recorded.treasury);Payment links and expected POST bodies
Payment links are hosted x402/MPP paywalls served at /x/{id}. Set
metadata.upstream_url to monetize an API you already host. The settled request
forwards to that upstream URL and returns the live upstream response. For POST
endpoints, set metadata.expected_request_body to describe the JSON shape buyers
should send to the hosted Leash URL.
const link = await leash.createPaymentLink({
label: 'Design agent',
owner_agent: 'AjfeyP...',
method: 'POST',
protocol: 'x402',
price: '1 USDC',
currency: 'USDC',
response: {
status: 200,
mimeType: 'application/json',
body: { ok: true, message: 'Payment accepted. Forwarding to upstream.' },
},
metadata: {
upstream_url: 'https://api.example.com/design',
provider_url: 'https://api.example.com',
pricing_type: 'fixed',
expected_request_body: {
prompt: 'string',
style: 'string',
format: 'string',
},
},
});
console.log(link.share_url);The SDK creates and reads the metadata. Paying requires Solana signing, so buyer
agents should use @leashmarket/buyer-kit, leash pay --method POST --body ...,
or leash_pay_payment_link to send the actual runtime body.
Authenticated calls
The webhook endpoints are agent-scoped — they verify a
X-Leash-Sig header signed with the agent's executive ed25519
keypair. Pass the keypair and mint to the constructor; the SDK
stamps a fresh signature per request.
import { LeashClient } from '@leashmarket/sdk';
const leash = new LeashClient({
agentMint: 'AjfeyP...',
executiveSecretBase58: process.env.LEASH_EXECUTIVE_KEY!,
});
const createdKey = await leash.createAgentApiKey({ label: 'local worker' });
console.log('STORE ONCE:', createdKey.plaintext);
const keys = await leash.listAgentApiKeys();
await leash.revokeAgentApiKey(keys.items[0].id);
const updatedProfile = await leash.updateAgentIdentityProfile({
handle: 'plexpert',
capability_cards: [
{
kind: 'seller_api',
title: 'Tax summary API',
source: 'manual',
endpoint: 'https://api.plexpert.xyz/tax',
protocols: ['x402'],
visibility: 'public',
},
],
});
console.log('identity handle:', updatedProfile.handle);
await leash.verifyAgentDomain('plexpert.xyz');
const claim = await leash.createIdentityClaim({
issuer: 'Leash Labs',
type: 'verified_builder',
value: 'true',
signature: 'sig_...',
});
const disclosure = await leash.createIdentityDisclosure({
resources: [{ kind: 'claim', id: claim.id }],
});
console.log('share once:', disclosure.url);
const sub = await leash.createWebhook({
url: 'https://my-app.example/leash-webhook',
events: ['receipt.published', 'agent.treasury.withdraw'],
});
console.log('SAVE THIS SECRET:', sub.secret); // returned ONCE.
const subs = await leash.listWebhooks();
await leash.deleteWebhook(sub.id);Agent-created keys are bound to the active agent mint, owned by the executive
public key, and scoped as exactly agent. Use them as LEASH_API_KEY for
legacy bearer-token surfaces such as receipt reads and payment-link CRUD.
Reputation cheat sheet
reputation.rating is a normalised score in [0, 1]:
rating = (1 - dispute_rate) * weight
weight = min(1, log10(settled_calls + 1) / 3)- A new agent with
settled_calls: 0hasrating: 0regardless of dispute rate. That's intentional — you don't have data yet. - An established agent with no disputes saturates at
1.0around ~1000 settled calls. dispute_rate = denied_calls / (settled_calls + denied_calls).
Errors
Network / non-2xx responses throw LeashError:
import { LeashError } from '@leashmarket/sdk';
try {
await leash.discover();
} catch (err) {
if (err instanceof LeashError) {
console.log('status:', err.status, 'body:', err.body);
}
}OpenAPI
The full set of endpoints is documented at
https://api.leash.market/openapi.json. The SDK is hand-rolled
against that surface so the runtime stays dep-free; type drift is
caught by integration tests.
Develop
pnpm --filter @leashmarket/sdk typecheck
pnpm --filter @leashmarket/sdk test
pnpm --filter @leashmarket/sdk build