Auto-recovery with next_action

Every JECP error returns a structured machine-readable hint so agents can recover without humans.

The shape of an error

{
  "jecp": "1.0",
  "status": "failed",
  "error": {
    "code": "INSUFFICIENT_BALANCE",
    "message": "wallet 0 USDC < 0.005"
  },
  "next_action": {
    "type": "topup",
    "ui":   "https://jecp.dev/topup",
    "api":  "https://jecp.dev/api/agents/topup",
    "hint": "Top up via Stripe."
  }
}

Branching with the SDK

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

try {
  await jecp.invoke('a/b', 'c', input);
} catch (e) {
  if (e instanceof JecpError) {
    switch (e.nextAction?.type) {
      case 'topup':
        await jecp.topup(20);
        break;
      case 'register':
        await JecpClient.register({ name: 'NewAgent' });
        break;
      case 'discover': {
        const cat = await jecp.catalog();
        // pick a real one
        break;
      }
      case 'retry_after':
        await sleep(60_000);
        break;
      case 'increase_mandate':
        // bump budget and retry
        break;
      case 'earn_trust':
        // trust tier too low — try a different capability
        break;
      // ...
    }
  }
}

Full next_action catalog (v1)

typeWhenRecovery hint
topupWallet too lowOpen Stripe Checkout via jecp.topup()
registerAuth failed entirelyRe-register the agent
increase_mandateMandate budget exhaustedRaise budget if operator approves
refresh_mandateMandate expiredIssue a new mandate
retry_afterRate limitedSleep then retry (Retry-After header)
discoverCapability not foundQuery /v1/capabilities
see_manifestAction not foundRead manifest for valid actions
earn_trustTrust tier too lowTry a lower-trust capability or build history
try_alternative_providerProvider unreachableUse catalog to find another
upgrade_clientSDK version too oldUpdate SDK

Typed error classes

The SDK provides 9 typed subclasses of JecpError: InsufficientBalanceError, InsufficientBudgetError, MandateExpiredError, AuthError, RateLimitError, CapabilityNotFoundError, ActionNotFoundError, InsufficientTrustError, ProviderError.

Each carries .code, .status, .nextAction, .message, and .raw (full server response).

Auto-retry layered on top

The SDK auto-retries transient errors (5xx, 408, 429, network) with exponential backoff. Your catch block only sees terminal failures, so the dispatch above runs after retries are exhausted. The same request_id is preserved across retries so the Hub's idempotency cache prevents double-charging.