Quickstart — agent in 5 minutes

Register a JECP agent, get 100 free calls, 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
console.log('free calls:', reg.free_calls_remaining); // 100
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. Invoke a capability

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

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);      // 0.995 (started 1.00, charged 0.005)

What just happened

  1. Register: Hub created an agent_id + api_key pair, allocated 100 free calls.
  2. 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.
  3. 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);
  }
}