> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentscore.com/llms.txt
> Use this file to discover all available pages before exploring further.

# AgentScore SDK (TypeScript)

> Official TypeScript/Node.js client for AgentScore.

## Installation

```bash theme={"dark"}
npm install @agent-score/sdk
```

## Quick start

```typescript theme={"dark"}
import { AgentScore } from "@agent-score/sdk";

const client = new AgentScore({ apiKey: process.env.AGENTSCORE_API_KEY });

// Summary lookup (free tier)
const summary = await client.getReputation("0xdb5aa553feeb2c3e3d03e8360b36fb0f7e480671");
console.log(summary.score.value, summary.score.grade);

// On-the-fly assessment with decision
const assessment = await client.assess("0xdb5aa553feeb2c3e3d03e8360b36fb0f7e480671", {
  policy: { require_kyc: true },
});

if (assessment.decision === "deny") {
  console.log("Denied:", assessment.decision_reasons);
}
```

## API reference

### Constructor

```typescript theme={"dark"}
new AgentScore(options: {
  apiKey: string;
  baseUrl?: string;   // default: "https://api.agentscore.com"
  timeout?: number;   // default: 10000 (ms)
  userAgent?: string; // custom prefix prepended to default UA, e.g. "myapp/1.0"
})
```

Set `userAgent` to prepend your app's identifier to outbound requests so AgentScore support can trace traffic back to you:

```typescript theme={"dark"}
const client = new AgentScore({ apiKey, userAgent: "myapp/1.0" });
// Outbound UA: "myapp/1.0 (@agent-score/sdk@x.y.z)"
```

### `client.getReputation(address, options?)`

Look up a wallet's cached reputation profile. Free tier.

```typescript theme={"dark"}
// All chains (operator overview)
const result = await client.getReputation(address);

// Filtered to a specific chain
const baseResult = await client.getReputation(address, { chain: "base" });
```

Returns `ReputationResponse` with top-level `score` (operator-level), `verification_level` (`"none"`, `"wallet_claimed"`, or `"kyc_verified"`), `chains` array (per-chain score and classification), and optionally `operator_score`, `reputation`, and `agents`. Paid plans include full chain details (identity, activity, evidence). When `chain` is provided, the `chains` and `agents` arrays are filtered to that chain.

### `client.assess(address, options?)`

On-the-fly trust assessment with policy evaluation. Available on every tier, gated by monthly quota.

```typescript theme={"dark"}
// With wallet address
const result = await client.assess("0x1234...", {
  policy: { require_kyc: true },
  chain: "base",
  refresh: false,
});

// With operator credential (non-wallet agents)
const result = await client.assess(null, {
  operatorToken: "opc_abc123...",
  policy: { require_kyc: true, min_age: 21 },
});

if (result.decision === "deny") {
  console.log("Denied:", result.decision_reasons);
}
```

Returns `AssessResponse` with `decision`, `decision_reasons`, `identity_method` (`"wallet"` or `"operator_token"`), and all reputation fields (null for credential-based assessments).

### Server-side signer-match + OFAC SDN screening

Pass `signer: { address, network }` to opt into server-side wallet-signer-match and OFAC SDN wallet-address screening in a single round trip:

```typescript theme={"dark"}
const result = await client.assess("0xclaimed...", {
  signer: { address: "0xsigner...", network: "evm" },
  policy: { require_sanctions_clear: true },
});

// Wallet-binding verdict
if (result.signer_match?.kind === "wallet_signer_mismatch") {
  console.log("Mismatch:", result.signer_match.expected_signer, "vs", result.signer_match.actual_signer);
}

// OFAC SDN wallet-address verdict; discriminated union
// { status: 'clear' } | { sanctioned: true, ofac_label, sdn_uid, listed_at } | { status: 'unavailable' }
if (result.signer_sanctions && "sanctioned" in result.signer_sanctions) {
  console.log("OFAC hit:", result.signer_sanctions.ofac_label, result.signer_sanctions.sdn_uid);
}
```

Set `signer.address: null` for rails with no wallet signer (Stripe SPT, card); the response's `signer_match.kind` will be `wallet_auth_requires_wallet_signing`. Wallet-OFAC SDN enforcement on the `signer` block is unconditional whenever a signer is supplied; no `policy.require_sanctions_clear` opt-in required. A `sanctioned: true` OR `status: "unavailable"` verdict flips `decision` to `deny` with `decision_reasons` including `sanctions_flagged` or `sanctions_check_unavailable` respectively (fail-closed; OFAC strict-liability). `policy.require_sanctions_clear` is the separate NAME-based screen on the resolved operator's KYC identity.

## Compliance assessment

Use compliance policy fields to enforce KYC, sanctions, age, and jurisdiction requirements:

```typescript theme={"dark"}
const result = await client.assess("0x1234...", {
  policy: {
    require_kyc: true,
    require_sanctions_clear: true,
    min_age: 21,
    blocked_jurisdictions: ["KP", "IR"],
  },
});

if (result.decision === "deny") {
  console.log("Denied:", result.decision_reasons);
  console.log("Policy checks:", result.policy_result.checks);

  // If denial is resolvable through verification, verify_url is present
  if (result.verify_url) {
    console.log("Verification required:", result.verify_url);
  }
}
```

## Sessions & credentials

```typescript theme={"dark"}
// Create a verification session (for merchant use)
const session = await client.createSession({
  context: "wine_purchase",
  product_name: "Cabernet 2022",
});
// session.verify_url: give to user
// session.poll_url: URL the agent polls
// session.poll_secret: X-Poll-Secret header for the agent's polls

// Optional pre-association: attach the session to a known wallet
// (`address`) or refresh KYC for an existing credential (`operator_token`).
await client.createSession({ address: "0x..." });
await client.createSession({ operator_token: "opc_..." });

// Poll for completion
const poll = await client.pollSession(session.session_id, session.poll_secret);
if (poll.status === "verified") {
  console.log("Credential:", poll.operator_token);
}

// Create a credential directly (if user already KYC'd)
const cred = await client.createCredential({ label: "claude-code", ttl_days: 1 });
console.log("Use this:", cred.credential);

// List and revoke
const list = await client.listCredentials();
await client.revokeCredential(list.credentials[0].id);
```

## Report captured wallets

After an agent paid under a credential, report the signer wallet so AgentScore can build a cross-merchant profile:

```typescript theme={"dark"}
await client.associateWallet({
  operatorToken: "opc_...",
  walletAddress: signerFromPayment, // EIP-3009 `from`, Tempo MPP DID, or Solana pubkey
  network: "evm", // or "solana"
  idempotencyKey: paymentIntentId, // optional, retries of same payment no-op
});
```

Fire-and-forget. Response is `{ associated: true, first_seen: boolean, deduped?: true }`.

## Quota observability

`assess()` responses include an optional `quota` field captured from `X-Quota-Limit` / `X-Quota-Used` / `X-Quota-Reset` headers so callers can monitor approach-to-cap proactively before hitting 429:

```typescript theme={"dark"}
const result = await client.assess("0x1234...", { policy: { require_kyc: true } });
if (result.quota?.limit && result.quota.used != null) {
  const pct = result.quota.used / result.quota.limit;
  if (pct >= 0.95) {
    log.warn(`AgentScore quota at ${Math.round(pct * 100)}%; resets at ${result.quota.reset}`);
  }
}
```

`reset` is an ISO-8601 timestamp or the literal string `"never"` for unlimited tiers; numeric fields are `null` when the API didn't include the header.

## Error handling

The SDK throws typed errors. Subclasses of `AgentScoreError` let callers branch on `instanceof` without parsing `err.code`:

```typescript theme={"dark"}
import {
  AgentScoreError,
  InvalidCredentialError,
  PaymentRequiredError,
  QuotaExceededError,
  RateLimitedError,
  TimeoutError,
  TokenExpiredError,
} from "@agent-score/sdk";

try {
  const result = await client.assess(null, {
    operatorToken: "opc_...",
    signer: { address: "0xs", network: "evm" },
  });
} catch (err) {
  if (err instanceof TokenExpiredError) {
    // 401 token_expired; credential revoked or TTL-expired. The 401 body carries an
    // auto-minted verification session so the agent recovers without an API key.
    console.log("verify_url:", err.verifyUrl, "session_id:", err.sessionId, "poll_secret:", err.pollSecret);
  } else if (err instanceof InvalidCredentialError) {
    // 401 invalid_credential; operator_token doesn't exist (typo, never minted).
  } else if (err instanceof QuotaExceededError) {
    // 429 quota_exceeded; wait for the quota reset window; don't retry.
  } else if (err instanceof RateLimitedError) {
    // 429 rate_limited; short-window backoff. err.retryAfter has the suggested delay.
  } else if (err instanceof PaymentRequiredError) {
    // 402; vendor tier misconfig.
  } else if (err instanceof AgentScoreError) {
    // Anything else: 4xx/5xx + network failures wrap to AgentScoreError with code "network_error"/"timeout"/etc.
    console.log(err.code, err.message, err.status);
  }
}
```

On `wallet_signer_mismatch` responses (verdict, not exception), spread `signer_match.agent_instructions` (a JSON-encoded `{action, steps, user_message}` envelope) directly into a 403 body; the SDK never re-derives recovery copy locally.

`AgentScoreError.details: Record<string, unknown>` carries response-body fields beyond `{code, message}`; `verify_url`, `linked_wallets`, `claimed_operator`, `actual_signer`, `expected_signer`, `reasons`, `agent_memory`; so callers can branch on granular denial codes without re-parsing:

```typescript theme={"dark"}
try {
  await client.assess("0xabc...", { policy: { require_kyc: true } });
} catch (err) {
  if (!(err instanceof AgentScoreError)) throw err;
  if (err.code === "wallet_signer_mismatch") {
    const linked = err.details.linked_wallets as string[] | undefined;
    // re-sign from any address in `linked`, or switch to X-Operator-Token
  }
  if (err.code === "token_expired") {
    const verifyUrl = err.details.verify_url as string | undefined;
    // surface verifyUrl to the user so they can re-verify
  }
}
```

## TypeScript types

The SDK exports all response types:

```typescript theme={"dark"}
import type {
  ReputationResponse,
  AssessResponse,
} from "@agent-score/sdk";
```

## Links

* [npm](https://www.npmjs.com/package/@agent-score/sdk)
* [GitHub](https://github.com/agentscore/node-sdk)
