TypeScript SDK and CLI
The agentex-creator-sdk package: the typed buyer client, payment rail helpers, typed reports, errors and retries, the agentex-buyer CLI and the creator CLI.
agentex-creator-sdk is the official TypeScript package for AGENTEX. It contains a typed client for the buyer API, helpers for payment assets and reports, the agentex-buyer command line for buyers and the agentex command line for creators. This page is for developers using it from Node.js; for other languages, use the REST API.
Install#
npm install agentex-creator-sdk- Version 1.0.0, MIT licensed, published on npm.
- Node.js 22 or later. ESM only (
import, notrequire). Type definitions are included. - It installs two commands:
agentex-buyerandagentex.
| Import path | Contents |
|---|---|
agentex-creator-sdk/buyer | createBuyerClient, AgentexApiError, isAgentexApiError, workflowInput, offerFor, the rail helpers, the report helpers, verifyWebhook and createMemoryReplayStore |
agentex-creator-sdk/report | readReport, evidenceFor, sourcesOf, reportKind and the report types, with no client |
agentex-creator-sdk/rails | ASSETS, describeAsset, formatAmount, formatAtomic, parseAmount, assetIdOf, resolveAssetId, with no client |
agentex-creator-sdk/buyer-cli | runBuyerCli, to embed the buyer CLI in your own tool |
agentex-creator-sdk | The creator toolkit: scaffold, validate, estimate, test and pack agent packages |
agentex-creator-sdk/cli | runCreatorCli, to embed the creator CLI |
Create a client#
import { ASSETS, createBuyerClient } from 'agentex-creator-sdk/buyer';
const agentex = createBuyerClient({ apiKey: process.env.AGENTEX_API_KEY!, assetId: ASSETS.SOL });| Option | Default | Meaning |
|---|---|---|
apiKey | required | An agx_live_... key from Developers. A malformed key throws unauthorized / invalid_api_key immediately. |
assetId | the key's own asset | The payment asset for quotes and billing: an asset id, ASSETS.SOL, ASSETS.USDC, ASSETS.ETH_ROBINHOOD, or the aliases sol, usdc, eth. Without it the client reads the key's asset once from GET /v1/buyer/key. |
origin | https://agentex.sh | The API origin. It must be HTTPS; plain HTTP is accepted only for a local host. |
timeoutMs | 15,000 | Timeout for each HTTP request. |
maxRetries | 2 (at most 5) | Retries for idempotent calls. |
retryDelayMs | 250 | First retry delay, doubling per attempt up to 8 seconds. |
fetch | global fetch | A custom fetch implementation. |
The client sends the key only as Authorization: Bearer, never sends cookies, never follows redirects, refuses responses larger than 4 MiB and never puts the key in an error message.
Client methods#
| Method | Calls | Returns |
|---|---|---|
key() | GET /v1/buyer/key | The key's scopes, asset, limits, remainingSpendAtomic and status |
listAgents(query) | GET /v1/public/agents | One page: { agents, nextCursor, total, sort } |
agents(query, maxPages?) | GET /v1/public/agents, page by page | An async iterator over agents (at most 20 pages by default) |
getAgent(listingId) | GET /v1/public/agents/{listingId} | Agent detail with offers, inputFields, permissions, limits, resultPolicies, limitations |
listings({ assetId }) | GET /v1/solana-custody/catalog or /v1/custody/catalog | The listings the key can buy, with full manifests and prices |
createQuote({ listingId, input, resultPolicy?, assetId? }) | POST .../quotes | A Quote. Never retried. |
acceptQuote({ quoteId, contractHash, idempotencyKey?, assetId? }) | POST .../quotes/{id}/accept | { run, reservation, notice, idempotencyKey } |
getRun(runId) | GET /v1/runs/{id} | { run, events } |
waitForRun(runId, wait?) | GET /v1/runs/{id}, polled | The final { run, events } |
getReport(runId) | GET /v1/runs/{id} | A typed ResearchReport |
getResult(runId) | GET /v1/runs/{id}/export | { artifactId, run, version, events } |
cancelRun(runId) | POST /v1/runs/{id}/cancel | The run |
getBilling(runId, { assetId? }) | GET .../runs/{id}/billing | Reservation, status and settlement |
getReceipt(runId, { quote?, assetId?, waitForSettlement? }) | GET .../runs/{id}/billing, polled when waiting | { status, outcome, payment, chargedAtomic, charged, fees, pendingReason, billing } |
research(request) | quote, accept and wait | { quote, acceptance, idempotencyKey, run, events, report, payment } |
listMonitors(), getMonitor(id), stopMonitor(id) | /v1/monitors... | Monitors (ETH keys with monitor scopes) |
listNotifications(), acknowledgeNotification(id) | /v1/notifications... | Notifications (ETH keys with monitor scopes) |
Each request method also accepts an AbortSignal as signal in its options (the agents() iterator does not). The client also has createMonitor; in production an API key cannot create monitors, so that call is refused (see Webhooks).
Payment assets and amounts#
| Helper | Example | Result |
|---|---|---|
ASSETS.SOL, ASSETS.USDC, ASSETS.ETH_ROBINHOOD | The three production asset ids | |
describeAsset(id) | describeAsset('sol') | { assetId, rail, profile, currency: 'SOL', decimals: 9, label: 'SOL on Solana', ... } |
formatAmount(atomic, id) | formatAmount('2200000', ASSETS.SOL) | '0.0022 SOL' |
parseAmount(text, decimals) | parseAmount('0.02', 9) | '20000000' |
formatAtomic(atomic, decimals) | formatAtomic('2200000', 9) | '0.0022' |
offerFor(agent, id) | offerFor(agent, ASSETS.USDC) | The listing's USDC offer, or undefined |
assetIdOf(quote.asset) | The asset id of a quote |
All amounts are exact strings; none of these helpers use floating point. A key pays only in its own asset: asking a SOL key to quote in USDC is refused with 403, and if the server ever quotes in another asset than the one you named, createQuote throws conflict / asset_mismatch before anything is accepted.
Run inputs#
- Research workflows (most catalog agents):
workflowInput(chain, values), for exampleworkflowInput('solana', { mint })orworkflowInput('ethereum', { token }). The value names come fromgetAgent(id).inputFields. - Token Researcher:
{ chain: 'base', address: '0x...' }. - Transaction Inspector, Wallet Analyst and Deployer Investigator:
{ chain, ... }with their own named fields. - Solana Transaction Inspector:
{ analysisChain: 'solana', network: 'mainnet-beta', encoding, payloadBase64 }.
Discover agents lists every input field.
Research in one call#
research() creates a quote, checks it against your bound, accepts it and waits. It refuses to run without a consent bound, and refuses, without accepting, any quote above it.
import { ASSETS, createBuyerClient, parseAmount, workflowInput } from 'agentex-creator-sdk/buyer';
const agentex = createBuyerClient({ apiKey: process.env.AGENTEX_API_KEY!, assetId: ASSETS.SOL });
const outcome = await agentex.research({
listingId: '<listingId>',
input: workflowInput('solana', { mint: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263' }),
maxDebitAtomic: parseAmount('0.01', 9), // or approve: quote => boolean, or both
});
console.log(outcome.run.status, outcome.report.findings.length);| Field | Meaning |
|---|---|
maxDebitAtomic | The most one run may reserve, in atomic units. A higher quote throws refused / quote_exceeds_limit. |
approve(quote) | A callback that sees the exact quote and returns true to accept. false throws refused / not_approved. |
idempotencyKey | Optional; generated when omitted and returned in the outcome. |
resultPolicy | complete_only (default) or, for Token Researcher, canonical_metadata. |
wait | The same options as waitForRun. |
With neither maxDebitAtomic nor approve, research() throws refused / consent_required. If waiting fails after the run was accepted, the error carries runId so you can resume with waitForRun(error.runId).
Waiting#
waitForRun(runId, options) polls until the status is succeeded, partial, failed or cancelled.
| Option | Default | Meaning |
|---|---|---|
intervalMs | 1,000 | First poll interval |
maxIntervalMs | 10,000 | Longest poll interval |
backoff | 1.5 | Interval multiplier per poll |
timeoutMs | 300,000 | Give up after this long with a retryable timeout / wait_timeout error |
signal | none | An AbortSignal; aborting throws aborted |
onStatus | none | Called with every { run, events } read |
Transient failures while polling are retried until the deadline. Waiting never changes the run. getReceipt(runId, { waitForSettlement: true }) waits for settlement the same way.
Typed reports#
getReport(runId), or readReport(run.output) from agentex-creator-sdk/report, turns any kind of AGENTEX report into one shape:
| Field | Contents |
|---|---|
kind | workflow, token-research, transaction-inspection, solana-transaction-inspection, deployer-investigation, wallet-analysis, watchtower or unknown |
status | complete, partial, failed or null |
headline | The result in one sentence, when the report declares one |
findings | Every finding as { code, text, label, value, status, origin, confidence, section, reason, evidenceIds }. Deterministic findings come first; AI-assisted claims have origin: 'model'. |
sections | Research workflow sections, each with its findings |
evidence | { id, tool, source: { kind, provider, method, documentationUrl }, chain, block, slot, finality, completeness, request, result, contentHash, ... } |
sources | Evidence grouped by provider, with the methods read and the evidence ids |
limitations, unknowns, errors, analysis, usage | As stored |
raw | The report exactly as stored |
evidenceFor(report, finding) returns the evidence items a finding cites, in order. Report strings come from public chains and websites: escape them before rendering them as HTML. See Reports and receipts.
Errors#
Every failure is an AgentexApiError with kind, status (the HTTP status, or null), code (the server's or the SDK's code), message (safe to show), retryable and retryAfterMs.
kind | When | Retry |
|---|---|---|
invalid_input | 400 or 413: bad input, cursor or asset id | Fix the request |
unauthorized | 401: missing, expired or revoked key, or a malformed key given to the client | Use a valid key |
forbidden | 403: missing scope, another asset, a listing restriction or the spend limit | No |
not_found | 404: not found or not visible to this key | No |
conflict | 409: hash mismatch, expired or accepted quote, insufficient balance, no report yet, asset_mismatch | After changing state |
gone | 410: a stored export expired | Request it again |
rate_limited | 429 | Yes, after retryAfterMs |
unavailable | 503 | Not automatically |
server | Other 5xx | Idempotent calls only |
network | No response, or the request timed out (code is network or timeout) | Idempotent calls only |
invalid_response | A non-JSON or oversized response | No |
timeout | A wait passed its deadline (wait_timeout) | Waiting again is safe |
aborted | Your AbortSignal fired | Your choice |
refused | research() declined: consent_required, quote_exceeds_limit or not_approved. Nothing was accepted. | No |
import { AgentexApiError } from 'agentex-creator-sdk/buyer';
try {
await agentex.acceptQuote({ quoteId: quote.id, contractHash: quote.contractHash });
} catch (error) {
if (error instanceof AgentexApiError && error.code === 'insufficient_available_credit') console.error('Deposit more SOL, then quote again.');
else throw error;
}The client retries GETs, acceptances (with one idempotency key for all attempts), cancellations, monitor stops and acknowledgements when the failure is a network error, a 429 or a 5xx other than 503. It honours a Retry-After of up to 30 seconds. It never retries quote creation.
The agentex-buyer CLI#
agentex-buyer runs every buyer action from a terminal. It reads the key from AGENTEX_API_KEY and never prints it. Output is JSON on standard output; errors are one line on standard error, Buyer command failed (HTTP <status> <code>): <message>, with exit code 1.
| Command | What it does |
|---|---|
agentex-buyer key | Show the key's grant and remaining spend |
agentex-buyer catalog [--q TEXT] [--chain CHAIN] [--topic TOPIC] [--sort newest|name|price] [--limit N] [--cursor CURSOR] | Search the catalog; --asset keeps listings that accept that asset |
agentex-buyer agent --listing ID | Agent detail |
agentex-buyer quote --listing ID INPUT [--result-policy POLICY] | Create a quote; prints the exact accept command to run next |
agentex-buyer accept --quote ID --contract-hash HASH --idempotency-key KEY --confirm | Accept a quote. Refuses without --confirm. |
agentex-buyer research --listing ID INPUT --max-debit AMOUNT --confirm [--idempotency-key KEY] [--timeout SECONDS] | Quote, check, accept and wait; refuses a quote above --max-debit (in the payment currency, for example 0.02) |
agentex-buyer status --run ID [--wait] [--timeout SECONDS] | Run status, optionally waiting for it to end |
agentex-buyer report --run ID | The typed report |
agentex-buyer result --run ID [--out result.json] | The canonical JSON export |
agentex-buyer billing --run ID | Billing and settlement |
agentex-buyer receipt --run ID [--wait] [--timeout SECONDS] | The receipt, optionally waiting for settlement |
agentex-buyer cancel --run ID | Cancel a run |
agentex-buyer monitor list, monitor get --monitor ID, monitor stop --monitor ID, monitor notifications, monitor ack --notification ID | Monitor reads and actions for ETH keys with monitor scopes |
agentex-buyer version, agentex-buyer --help | Version and help |
INPUT is one of:
--chain CHAIN --value NAME=VALUE(repeatable) for research workflows, for example--chain solana --value mint=DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263;--chain CHAIN --address ADDRESSfor Token Researcher;--input input.jsonfor any agent's exact input object.
Common options: --asset sol|usdc|eth or an asset id (or AGENTEX_ASSET; default: the key's own asset) and --api ORIGIN (or AGENTEX_API_ORIGIN; default https://agentex.sh). Files named with --input and --out must be inside the current directory, and outputs never overwrite an existing file.
export AGENTEX_API_KEY=agx_live_...
npx agentex-buyer catalog --chain solana --asset sol --limit 10
npx agentex-buyer quote --listing <listingId> --chain solana --value mint=DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263
npx agentex-buyer accept --quote <quoteId> --contract-hash <contractHash> --idempotency-key my-run-0001 --confirm
npx agentex-buyer status --run <runId> --wait --timeout 300
npx agentex-buyer report --run <runId>
npx agentex-buyer receipt --run <runId> --waitOn Windows PowerShell, set the key with $env:AGENTEX_API_KEY = 'agx_live_...' and run the same commands.
The creator CLI#
The agentex command builds a data-only agent package on your own machine, which you then import in Studio. Everything runs offline, and files stay inside the current directory without overwriting.
| Command | What it does |
|---|---|
agentex scaffold --id ID --name NAME [--chains ethereum,base] [--description TEXT] [--read-owner true|false] [--read-proxy-slots true|false] [--max-rpc N] --out manifest.json | Start a token inspection manifest from the current template |
agentex validate --file manifest.json | Check the manifest against the supported schema |
agentex test --file manifest.json | Run the platform's fixed fixture suite offline |
agentex estimate --file manifest.json | Estimate the nominal blockchain reads per run |
agentex pack --file manifest.json --out package.json | Wrap the manifest and its hash into an importable package |
To import the package, open Studio's Import package page (/studio/import), choose or paste the package JSON (up to 64 KiB), select Inspect package, review its permissions, then select Import private version. The import is a private draft and version; it goes through the normal creator test and review before it can be listed. See Templates and workflows and Create an agent.
The same functions are available in code from agentex-creator-sdk: scaffoldTokenResearcher, validateManifest, testManifest, estimateManifest and prepareCreatorPackage. The creator API accepts JSON data only: it rejects functions, accessors, cycles, class instances and inputs above 64 KiB or 32 levels deep.