SDK Quickstart
Go from zero to an agent that asks AgentOps for permission before paying — in your own TypeScript. Two credentials, one package, no new auth to learn.
Prerequisites
- An AgentOps organisation with a funded Casper float and an org guard policy — see the
Quickstartunder Getting Started. - Your AgentOps API base URL, shown in the console.
- An operator key (
sk_...) — issued from the console under Settings. - Node.js 18+ (the SDK uses the global
fetchand is ESM-only).
1. Install
npm install @agops-labs/sdk@0.2.02. Provision an agent (operator key)
Use your sk_ key to create an agent. You get back the agent’s id and its own ag_ key — hand that key to the agent process.
import { createAgentOpsClient } from '@agops-labs/sdk';
const operator = createAgentOpsClient({
baseUrl: 'https://<your-agentops-host>',
apiKey: process.env.AGENTOPS_OPERATOR_KEY!, // sk_live_...
});
const { agent, api_key } = await operator.createAgent({ name: 'Research Agent' });
// agent.id → 'agt_...'
// api_key → 'ag_live_...' (the agent's own credential)NOTE
3. Pay for a service (agent key)
The shortest path is createGuardedFetch — a drop-in fetch that runs the whole x402 handshake for you: call the service, catch the 402, check policy, attach the signed header, retry. You write one call instead of five steps.
import { createGuardedFetch, PaymentDeniedError } from '@agops-labs/sdk';
const guardedFetch = createGuardedFetch({
baseUrl: 'https://<your-agentops-host>',
apiKey: process.env.AGENTOPS_AGENT_KEY!, // ag_live_...
agentId: agent.id, // must be this key's agent
onDecision: (d) => console.log('decision', d.decisionId), // optional audit hook
});
const res = await guardedFetch('https://svc.example/risk-oracle/score', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ pair: 'CSPR-USDC', side: 'buy', size_motes: '1000000000' }),
});
const data = await res.json(); // the paid 200Responses that are not 402 pass through untouched, so this is safe as the only fetch in an agent — free endpoints and errors behave exactly as the platform fetch does. When policy refuses, you get a typed error instead of a confusing 402:
try {
await guardedFetch(SERVICE_URL);
} catch (err) {
if (err instanceof PaymentDeniedError) {
console.log(err.reason); // 'spend_cap_exceeded', 'service_not_allowed', ...
console.log(err.decisionId); // audit id for this refusal
}
}NOTE
PaymentDeniedError means policy worked correctly. PaymentFlowError is the different case where the call never reached policy — a bad key, a tenant mismatch, or a malformed challenge. Idempotency keys are generated per payment automatically.4. Or drive the steps yourself
Prefer explicit control — or authorizing a cspr-trade / casper-deploy action rather than paying for an HTTP resource? Construct a client with the ag_ key and call authorize directly. By default it is synchronous — the ALLOW / DENY body comes straight back.
const asAgent = createAgentOpsClient({
baseUrl: 'https://<your-agentops-host>',
apiKey: process.env.AGENTOPS_AGENT_KEY!, // ag_live_...
});
const result = await asAgent.authorize({
kind: 'x402-payment',
agentId: agent.id,
idempotencyKey: 'req-42', // makes retries safe
paymentRequired: rawBodyFrom402, // the API's 402 response body, verbatim
});
if (result.outcome === 'DENY') {
console.log('blocked:', result.reason); // human-readable, e.g. "Spend cap exceeded…"
} else {
// result.payment_header = { name, value } — attach it and retry the paid request
}Async opt-in
Prefer not to block? Ask for a pollable decision id instead, then read it later with the operator client.
const { decisionId } = await asAgent.authorize(sameInput, { async: true });
const status = await operator.getDecision(decisionId); // { outcome, status, ... }5. What happens on the server
Every authorize call runs the full policy firewall before anything is signed:
- bearer auth → idempotency → kill-switch → action kind → network
- service allowlist → asset type → per-transaction max
- spend cap (atomic) → velocity limit → sign
On ALLOW, a background worker reads settlement from Casper and anchors a SHA-256 fingerprint of the decision into the on-chain GuardRegistry — a tamper-proof receipt.
HEADS UP
sk_ (operator) and ag_ (agent) routes separately — construct two clients if your code needs both.