Quickstart — agent in 5 minutes

Register a JECP agent, top up its wallet, and invoke a capability with the TypeScript SDK.

Prerequisites

1. Install the SDK

npm install @jecpdev/sdk

2. Register an agent

import { JecpClient } from '@jecpdev/sdk';

const reg = await JecpClient.register({
  name: 'MyResearchAgent',
  agent_type: 'research',
  description: 'Reads docs, writes summaries',
});

console.log('agent_id:', reg.agent_id);
console.log('api_key: ', reg.api_key);   // shown ONCE — save it
Save the api_key now. Treat it like a Stripe secret. It cannot be recovered if lost — you'd register a new agent and start over.

3. Top up the wallet

const jecp = new JecpClient({
  agentId: reg.agent_id,
  apiKey:  reg.api_key,
});

const { url } = await jecp.topup(5);   // 5, 20, or 100 (USD)
console.log('Pay here:', url);         // Stripe Checkout — wallet is credited after payment

Calls are paid from the agent's own wallet. There is no free tier; browsing the catalog is free.

4. Invoke a capability

const { output, billing, wallet_balance_after } = await jecp.invoke(
  'jobdonebot/content-factory',
  'translate',
  { text: 'Hello, world!', target_lang: 'JA' },
);

console.log(output);                    // { translated: 'こんにちは、世界!' }
console.log(billing.charged);           // true
console.log(billing.amount_usdc);       // 0.005
console.log(wallet_balance_after);      // 4.995 (after a $5 top-up, charged 0.005)

What just happened

  1. Register: Hub created an agent_id + api_key pair.
  2. Top up: Stripe Checkout credited the agent's wallet.
  3. Invoke: Hub validated credentials, looked up the jobdonebot/content-factory manifest, found the translate action, charged $0.005 from your wallet, signed the request with HMAC, forwarded to the Provider's endpoint, and returned the result.
  4. Billing: 85% to Provider, 10% Hub fee, 5% payment processing — atomic in a single SQL transaction.

Production-grade defaults

const jecp = new JecpClient({
  agentId, apiKey,
  timeoutMs: 30_000,
  retryConfig: { maxRetries: 3 },     // exp backoff on 5xx/408/429/network
  logger: console,                    // observe retries and errors
});

// Cancel mid-flight + per-call timeout
const ctl = new AbortController();
const r = await jecp.invoke('a/b', 'c', input, {
  signal: ctl.signal,
  timeoutMs: 60_000,
  mandate: { budget_usdc: 1.00 },     // pre-authorize spend cap
});

Error handling with next_action

import { JecpError, InsufficientBalanceError } from '@jecpdev/sdk';

try {
  await jecp.invoke('a/b', 'c', input);
} catch (e) {
  if (e instanceof InsufficientBalanceError) {
    // Auto-recovery — open the topup URL
    const { url } = await jecp.topup(20);
    console.log('Top up here:', url);
  }
  if (e instanceof JecpError) {
    console.log('next_action:', e.nextAction);
  }
}