https://github.com/agentscore/node-sdk
TypeScript client for the AgentScore trust and reputation API
https://github.com/agentscore/node-sdk
agentscore ai-agent blockchain erc-8004 reputation sdk trust typescript x402
Last synced: 20 days ago
JSON representation
TypeScript client for the AgentScore trust and reputation API
- Host: GitHub
- URL: https://github.com/agentscore/node-sdk
- Owner: agentscore
- License: mit
- Created: 2026-03-20T12:02:07.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-03-31T06:31:10.000Z (2 months ago)
- Last Synced: 2026-03-31T08:41:58.697Z (2 months ago)
- Topics: agentscore, ai-agent, blockchain, erc-8004, reputation, sdk, trust, typescript, x402
- Language: TypeScript
- Homepage: https://docs.agentscore.sh
- Size: 109 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Security: SECURITY.md
Awesome Lists containing this project
README
# @agent-score/sdk
[](https://www.npmjs.com/package/@agent-score/sdk)
[](LICENSE)
TypeScript/Node.js client for the [AgentScore](https://agentscore.sh) APIs.
## Install
```bash
npm install @agent-score/sdk
# or
bun add @agent-score/sdk
```
## Quick Start
```typescript
import { AgentScore } from "@agent-score/sdk";
const client = new AgentScore({ apiKey: "as_live_..." });
// Look up cached reputation (free)
const rep = await client.getReputation("0x1234...");
console.log(rep.score.value, rep.score.grade);
// Filter to a specific chain
const baseRep = await client.getReputation("0x1234...", { chain: "base" });
console.log(baseRep.agents); // only Base agents
// Identity gate with policy (paid)
const gated = await client.assess("0x1234...", {
policy: {
require_kyc: true,
require_sanctions_clear: true,
min_age: 21,
},
});
if (gated.decision === "deny") {
console.log(gated.decision_reasons); // ["kyc_required"]
console.log(gated.verify_url); // URL for operator verification
}
// Check verification level on reputation
const verified = await client.getReputation("0x1234...");
console.log(verified.verification_level); // "none" | "wallet_claimed" | "kyc_verified"
```
### Credential-Based Identity
Agents without wallets can use operator credentials for identity:
```typescript
// Assess with an operator credential instead of a wallet address
const result = await client.assess(null, { operatorToken: "opc_..." });
console.log(result.decision); // "allow" | "deny"
```
### Verification Sessions
Bootstrap identity for first-time agents. The success body carries structured `next_steps` (with `action: "deliver_verify_url_and_poll"`) and a cross-merchant `agent_memory` hint. Poll responses carry `next_steps.action` from the typed `NextStepsAction` union (`continue_polling`, `retry_merchant_request_with_operator_token`, `use_stored_operator_token`, `create_new_session`, `verification_failed`, `contact_support`).
```typescript
// Create a session — returns a verify_url for the user and a poll_url for the agent
const session = await client.createSession();
console.log(session.verify_url, session.poll_url, session.poll_secret);
console.log(session.next_steps.action); // "deliver_verify_url_and_poll"
// Poll until the user completes verification
const status = await client.pollSession(session.session_id, session.poll_secret);
if (status.status === "verified") {
console.log(status.operator_token); // "opc_..." — use for future requests
}
// Optional pre-association: attach the session to a known wallet or refresh KYC
// for an existing operator credential.
await client.createSession({ address: "0x..." });
await client.createSession({ operator_token: "opc_..." }); // KYC refresh
```
### Wallet resolution
`assess()` responses include `resolved_operator` and `linked_wallets[]` — all same-operator sibling wallets (claimed via SIWE or captured via prior `associateWallet`). The list may mix EVM addresses (`0x...` lowercased) and Solana addresses (base58, case-preserved) for cross-chain operators; merchants doing wallet-signer-match checks should accept a payment signed by any address in the list, regardless of chain. The `address` parameter on `assess()` and `getReputation()` accepts either format — network is auto-detected from the address shape.
### Server-side signer-match + sanctions screening
Pass `signer: { address, network }` on `assess()` to opt into server-side wallet-signer-match and OFAC SDN wallet-address screening on the same call. The response carries two new verdicts:
```typescript
const result = await client.assess("0xclaimed...", {
signer: { address: "0xsigner...", network: "evm" },
policy: { require_sanctions_clear: true },
});
// signer_match: wallet-binding verdict
// kind: 'pass' | 'wallet_signer_mismatch' | 'wallet_auth_requires_wallet_signing'
// plus claimed_operator / signer_operator / expected_signer / actual_signer / linked_wallets / agent_instructions
if (result.signer_match?.kind === "wallet_signer_mismatch") {
// signer wallet resolves to a different operator than the claimed address
}
// signer_sanctions: 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);
}
```
Wallet-OFAC SDN enforcement on the `signer` block is unconditional whenever a signer is supplied — no `policy.require_sanctions_clear` opt-in required. The API flips `decision` to `deny` when `signer_sanctions` is `sanctioned: true` OR `status: 'unavailable'`, 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.
Pass `signer.address: null` for rails without a wallet signer (Stripe SPT, card-only). The API responds with `signer_match.kind = 'wallet_auth_requires_wallet_signing'` and a parsed `agent_instructions` block telling the agent to switch to `X-Operator-Token` auth — spread the block directly into a 403 body.
### Credential Management
```typescript
const cred = await client.createCredential({ label: "my-agent", ttl_days: 7 });
console.log(cred.credential); // shown once
const list = await client.listCredentials();
console.log(list); // active, non-expired credentials
await client.revokeCredential(cred.id);
```
### Report an Agent's Wallet (Cross-Merchant Attribution)
After an agent authenticated via `operator_token` completes a payment, report the signer wallet so AgentScore can build a cross-merchant credential↔wallet profile. Fire-and-forget — `first_seen` is informational only. `network` is the key-derivation family: `"evm"` for any EVM chain (Base, Tempo, Ethereum, …) or `"solana"` for Solana.
```typescript
await client.associateWallet({
operatorToken: "opc_...",
walletAddress: signerFromPayment, // e.g. EIP-3009 `from` or Tempo MPP DID address
network: "evm",
idempotencyKey: paymentIntentId, // optional — agent retries of the same payment no-op
});
```
## Configuration
| Option | Type | Default | Description |
| ----------- | -------- | --------------------------- | ------------------------ |
| `apiKey` | `string` | --- | API key from [agentscore.sh](https://agentscore.sh) |
| `baseUrl` | `string` | `https://api.agentscore.sh` | API base URL |
| `timeout` | `number` | `10000` | Request timeout in ms |
| `userAgent` | `string` | --- | Prepended to the default `User-Agent` as `"{userAgent} (@agent-score/sdk@{version})"`. Use to attribute API calls to your app. |
## Error Handling
```typescript
import { AgentScore, AgentScoreError } from "@agent-score/sdk";
try {
await client.getReputation("0xinvalid");
} catch (err) {
if (err instanceof AgentScoreError) {
console.error(err.code, err.message, err.status);
}
}
```
`AgentScoreError.details` carries the rest of the response body — `verify_url`, `linked_wallets`, `claimed_operator`, `actual_signer`, `expected_signer`, `reasons`, `agent_memory` — so callers can branch on granular denial codes without re-parsing.
### Typed error classes
For status-code-specific recovery, the SDK throws typed subclasses of `AgentScoreError`. All inherit from `AgentScoreError` so existing `catch (err) { if (err instanceof AgentScoreError) ... }` still works.
| Class | Triggered by | What it adds |
|---|---|---|
| `PaymentRequiredError` | HTTP 402 | The endpoint is not enabled for this account |
| `TokenExpiredError` | HTTP 401 with `error.code = "token_expired"` | Parsed body fields exposed on the instance: `verifyUrl`, `sessionId`, `pollSecret`, `pollUrl`, `nextSteps`, `agentMemory` — recover without re-parsing `details` |
| `InvalidCredentialError` | HTTP 401 with `error.code = "invalid_credential"` | Permanent — switch tokens or restart |
| `QuotaExceededError` | HTTP 429 with `error.code = "quota_exceeded"` | Account-level cap reached; don't retry |
| `RateLimitedError` | HTTP 429 with `error.code = "rate_limited"` | Per-second sliding-window cap; retry after `Retry-After` |
| `TimeoutError` | Request aborted before a response arrived | Distinct from generic network errors |
```typescript
import {
AgentScore, AgentScoreError, TokenExpiredError, QuotaExceededError, TimeoutError,
} from "@agent-score/sdk";
try {
await client.assess("0xabc...", { policy: { require_kyc: true } });
} catch (err) {
if (err instanceof TokenExpiredError) {
console.log("Verify at:", err.verifyUrl, "poll with:", err.pollSecret);
} else if (err instanceof QuotaExceededError) {
console.log("Account quota reached — surface to user; don't retry.");
} else if (err instanceof TimeoutError) {
console.log("Network timeout — retry with backoff.");
} else if (err instanceof AgentScoreError) {
console.error(err.code, err.message);
}
}
```
## Quota observability
`assess()` responses include an optional `quota` field captured from `X-Quota-Limit` / `X-Quota-Used` / `X-Quota-Reset` response headers. Use it to monitor approach-to-cap proactively (warn at 80%, alert at 95%) before a 429:
```typescript
const result = await client.assess("0xabc...", { policy: { require_kyc: true } });
if (result.quota && result.quota.limit && result.quota.used) {
const pct = (result.quota.used / result.quota.limit) * 100;
if (pct > 80) console.warn(`AgentScore quota at ${pct.toFixed(1)}% — resets ${result.quota.reset}`);
}
```
`quota` is `undefined` when the API doesn't emit the headers (Enterprise / unlimited tiers). On a 429 response the SDK throws `QuotaExceededError` / `RateLimitedError` instead of returning a body, so `quota` is only readable on successful calls — drive proactive alerting off the success-path field.
## Telemetry
`telemetrySignerMatch(payload)` is a fire-and-forget POST to `/v1/telemetry/signer-match` so AgentScore can track aggregate signer-binding behavior across merchants. Used internally by `@agent-score/commerce`'s gate; available directly for custom integrations that perform their own wallet-signer-match checks.
## Documentation
- [API Reference](https://docs.agentscore.sh)
## License
[MIT](LICENSE)