Connect Your Agent

SDK Client Reference

Every method maps 1:1 to an AgentOps route. Operator methods need an sk_ key; authorize needs an ag_ key.

createGuardedFetch(config)

Returns a fetch-shaped function that transparently pays for 402-gated resources. Non-402 responses pass through untouched.

ts
createGuardedFetch({
  baseUrl: string;                        // AgentOps proxy base URL
  apiKey: string;                         // the agent's ag_ key
  agentId: string;                        // must be this key's agent
  fetchImpl?: typeof fetch;               // injectable for tests
  idempotencyKey?: () => string;          // default: fresh key per payment
  network?: string;                       // x-agentops-network selector
  onDecision?: (d: GuardedDecision) => void;
});

On a 402 it forwards the challenge to authorize-x402, and on ALLOW retries the original request with the signed payment header plus x-guard-decision-id. The original method, body, and headers are preserved.

Errors

  • PaymentDeniedError — policy refused. Carries reason, decisionId, and resource. The service is never re-hit.
  • PaymentFlowError — the call never reached policy: a bad key, a tenant mismatch, a malformed 402 body, or an ALLOW with no payment header.

NOTE

Keep these distinct in your handling. A denial is the firewall working as designed; a flow error is a misconfiguration on your side. Collapsing them makes a bad API key look like a spend cap.

createAgentOpsClient(config)

Returns a client bound to one credential.

ts
createAgentOpsClient({
  baseUrl: string;
  apiKey: string;
  fetchImpl?: typeof fetch;
});

Operator methods (sk_ key)

createAgent(input)

Provisions an agent and returns its own agent key.

ts
const { agent, api_key } = await operator.createAgent({
  name: 'Trader',
  teamId: 'team_1', // optional
});
// agent: { id, name, org_id, status }
// api_key: 'ag_live_...'

attachTradingFlow(input)

Binds a compiled trading flow to roles within an org.

ts
const { role_assignments } = await operator.attachTradingFlow({
  orgId: 'org_1',
  flow: compiledFlow,                 // CompiledTradingFlow (server-defined)
  roleAssignments: { trader: agent.id },
});

revokeAgent(input)

Suspends an agent and aborts its in-flight decisions.

ts
const res = await operator.revokeAgent({ agentId: agent.id });
// { agent_id, agent_suspended, aborted_decision_ids, committed_decision_ids }

getDecision(decisionId)

Reads the current status of any decision (used for async polling).

ts
const status = await operator.getDecision('cgd_...');
// { decision_id, outcome: 'ALLOW' | 'DENY', status, ... }

Agent method (ag_ key)

authorize(input, options?)

The core call. An x402-payment is routed through the x402 authorize path; anything else goes through the generic action path.

ts
// Payment (from a 402 response):
await asAgent.authorize({
  kind: 'x402-payment',
  agentId: agent.id,
  idempotencyKey: 'idem_1',
  paymentRequired: rawPaymentRequiredBody,
});

// Generic on-chain action:
await asAgent.authorize({
  kind: 'action',
  agentId: agent.id,
  idempotencyKey: 'idem_2',
  /* action fields */
});

// Async opt-in — returns { decisionId } to poll later:
const { decisionId } = await asAgent.authorize(input, { async: true });

NOTE

Sync is the default: authorize returns the ALLOW / DENY body directly. Pass { async: true } to get a decisionId immediately and poll with getDecision.

Idempotency

  • Pass a stable idempotencyKey per logical request when calling authorize directly.
  • Retrying with the same key returns the same decision instead of double-charging.
  • The flip side: reusing one key across two different payments returns the first decision again. createGuardedFetch generates a fresh key per payment for exactly this reason — override idempotencyKey only if you are managing retry semantics yourself.