CertNode Agent SDK - Accountability for AI agent actions with cryptographic proof
npm install @certnode/agent-sdkAccountability infrastructure for AI agents. Create cryptographic proof of every action your AI agent takes, with human authorization chains.
As AI agents take more autonomous actions, there's growing need to:
- Track what agents do - Immutable audit log of every action
- Prove authorization - Human-granted permissions with scope limits
- Detect violations - Flag actions outside authorized scope
- Enable compliance - RFC 3161 timestamps for regulatory requirements
``bash`
npm install @certnode/agent-sdk
`typescript
import { AgentClient } from '@certnode/agent-sdk'
// Initialize the client
const agent = new AgentClient({
apiKey: process.env.CERTNODE_API_KEY,
agentType: 'claude-agent',
agentName: 'Customer Service Bot',
agentVersion: '1.0.0',
capabilities: ['read_tickets', 'respond_tickets', 'escalate_tickets'],
})
// Create an authorization from a human supervisor
const auth = await agent.createAuthorization({
grantedByUserId: 'supervisor_123',
grantedByName: 'Sarah Chen',
grantedByEmail: 'sarah@company.com',
scope: ['read_tickets', 'respond_tickets'],
prohibitedActions: ['delete_tickets', 'issue_refunds'],
expiresAt: new Date(Date.now() + 8 60 60 * 1000).toISOString(), // 8 hours
reason: 'Weekend shift coverage',
})
// Log an action
const action = await agent.logAction({
authorizationId: auth.id,
actionType: 'respond_tickets',
actionDescription: 'Sent response to ticket #12345',
actionDetails: {
ticketId: '12345',
message: 'Thank you for contacting us...',
},
})
console.log(Action logged: ${action.action.id})Within scope: ${action.action.withinScope}
console.log()Proof URL: https://certnode.io/verify/${action.action.id}
console.log()`
Every agent action must be authorized by a human. Authorizations include:
- Scope: What actions the agent can take
- Constraints: Limits on how actions can be performed
- Prohibited actions: Explicitly forbidden operations
- Time bounds: When the authorization expires
`typescript`
const auth = await agent.createAuthorization({
grantedByUserId: 'user_123',
grantedByName: 'John Doe',
scope: ['analyze_data', 'generate_report'],
constraints: {
maxRecordsPerQuery: 1000,
allowedDatabases: ['analytics', 'reporting'],
},
prohibitedActions: ['delete_data', 'export_pii'],
expiresAt: '2026-01-31T23:59:59Z',
})
Every action is logged with cryptographic proof:
`typescript
const result = await agent.logAction({
authorizationId: auth.id,
actionType: 'analyze_data',
actionDescription: 'Analyzed Q4 sales data',
actionDetails: {
query: 'SELECT region, SUM(revenue) FROM sales GROUP BY region',
rowCount: 45,
},
parentActionId: previousAction.id, // Optional: link to parent action
sessionId: 'session_abc123', // Optional: group related actions
})
// Check if action was within scope
if (!result.action.withinScope) {
console.warn('Scope violation:', result.violations)
}
`
Every action receives:
- SHA-256 content hash - Tamper-evident fingerprint
- JWS signature - ES256 cryptographic signature
- RFC 3161 timestamp - Legally compliant timestamp
`typescript`
// Verify an action
const verification = await agent.verifyAction(actionId)
console.log(verification.valid) // true
console.log(verification.contentHash) // sha256:abc123...
console.log(verification.rfc3161Timestamp) // 2026-01-05T12:00:00Z
`typescript`
new AgentClient(options: AgentClientOptions)
Options:
| Option | Type | Required | Description |
|--------|------|----------|-------------|
| apiKey | string | Yes | Your CertNode API key |agentType
| | string | Yes | Agent type identifier |agentName
| | string | Yes | Human-readable agent name |agentVersion
| | string | No | Semantic version |description
| | string | No | Agent description |capabilities
| | string[] | No | List of capabilities |baseUrl
| | string | No | API base URL (default: https://api.certnode.io) |
`typescript`
agent.createAuthorization(params: CreateAuthorizationParams): Promise
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| grantedByUserId | string | Yes | User ID of grantor |grantedByName
| | string | Yes | Name of grantor |grantedByEmail
| | string | No | Email of grantor |grantedByTitle
| | string | No | Job title of grantor |scope
| | string[] | Yes | Allowed action types |constraints
| | object | No | Action constraints |prohibitedActions
| | string[] | No | Explicitly forbidden actions |validFrom
| | string | No | ISO timestamp (default: now) |expiresAt
| | string | No | ISO timestamp |reason
| | string | No | Reason for authorization |
`typescript`
agent.logAction(params: LogActionParams): Promise
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| authorizationId | string | Yes | Authorization ID |actionType
| | string | Yes | Type of action |actionDescription
| | string | Yes | Human-readable description |actionDetails
| | object | No | Structured action data |parentActionId
| | string | No | Parent action for chaining |sessionId
| | string | No | Session identifier |
`typescript`
agent.listActions(params: ListActionsParams): Promise
Parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| authorizationId | string | Filter by authorization |sessionId
| | string | Filter by session |actionType
| | string | Filter by action type |withinScope
| | boolean | Filter by scope status |limit
| | number | Results per page (default: 50) |offset
| | number | Pagination offset |
`typescript`
agent.revokeAuthorization(authorizationId: string, reason?: string): Promise
`typescript
import { AgentClient } from '@certnode/agent-sdk'
import Anthropic from '@anthropic-ai/sdk'
const agent = new AgentClient({
apiKey: process.env.CERTNODE_API_KEY,
agentType: 'claude-agent',
agentName: 'Content Moderator',
})
const anthropic = new Anthropic()
async function moderateContent(authId: string, content: string) {
// Log the moderation action
const action = await agent.logAction({
authorizationId: authId,
actionType: 'moderate_content',
actionDescription: 'Analyzing content for policy violations',
actionDetails: { contentLength: content.length },
})
// Call Claude
const result = await anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
messages: [{ role: 'user', content: Moderate this: ${content} }],
})
return { action, result }
}
`
`typescript
import { AgentClient } from '@certnode/agent-sdk'
import OpenAI from 'openai'
const agent = new AgentClient({
apiKey: process.env.CERTNODE_API_KEY,
agentType: 'openai-agent',
agentName: 'Data Analyst',
})
const openai = new OpenAI()
async function analyzeData(authId: string, data: object[]) {
const action = await agent.logAction({
authorizationId: authId,
actionType: 'analyze_data',
actionDescription: 'Running data analysis',
actionDetails: { recordCount: data.length },
})
const completion = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [
{ role: 'system', content: 'Analyze the data and provide insights.' },
{ role: 'user', content: JSON.stringify(data) },
],
})
return { action, analysis: completion.choices[0].message.content }
}
`
View all agent activity at certnode.io/dashboard/agents:
- Real-time action feed
- Authorization management
- Scope violation alerts
- Audit log export
`typescript
import { AgentClient, AgentError, AuthorizationExpiredError } from '@certnode/agent-sdk'
try {
await agent.logAction({ ... })
} catch (error) {
if (error instanceof AuthorizationExpiredError) {
// Request new authorization
} else if (error instanceof AgentError) {
console.error('Agent error:', error.code, error.message)
}
}
`
Full TypeScript support with exported types:
`typescript``
import type {
AgentClientOptions,
Authorization,
CreateAuthorizationParams,
LogActionParams,
ActionResult,
AgentAction,
} from '@certnode/agent-sdk'
MIT