shadowkey-agent-sdk
v1.2.0
Published
Official SDK for integrating AI agents with ShadowKey privacy vault
Downloads
28
Maintainers
Readme
ShadowKey Agent SDK
Official SDK for integrating AI agents with ShadowKey's privacy-preserving data vault on Base.
Features
- HMAC-SHA256 Request Signing — Every request is cryptographically signed to prevent replay attacks
- Automatic Retry — Exponential backoff on server errors (skips retries on 4xx client errors)
- Approval Polling — Built-in
waitForApproval()with configurable timeout and interval - Node.js 18+ & Browser — Works in both environments using
globalThis.crypto - TypeScript-First — Full type definitions included (CJS + ESM +
.d.ts) - Zero Dependencies — No external deps, minimal bundle size (4.8 KB ESM)
- Debug Mode — Logs requests/responses with automatic redaction of sensitive fields
Installation
npm install shadowkey-agent-sdkQuick Start
import { ShadowKeyClient } from 'shadowkey-agent-sdk';
const client = new ShadowKeyClient({
apiUrl: 'https://your-project.supabase.co/functions/v1',
apiKey: 'sk_your_api_key_here',
debug: true,
});
// 1. Request access to user's vault data
const response = await client.requestAccess({
agentId: 'shopping-bot-001',
agentName: 'Smart Shopping Assistant',
requestedFields: ['shipping_address', 'billing_name', 'card_last4'],
purpose: 'Complete purchase of wireless headphones ($89.99)',
category: 'payment',
});
console.log('Request ID:', response.requestId);
// → User receives notification in their ShadowKey dashboard
// 2. Wait for user to approve/deny (polls every 2s, max 5 min)
const result = await client.waitForApproval(response.requestId);
if (result.status === 'approved') {
console.log('Scoped access granted:', result.grantedFields);
console.log('Data:', result.grantedData);
// → Only the fields the user approved — nothing more
} else {
console.log('Access denied:', result.message);
}How It Works
Your Agent ShadowKey SDK User's Vault
| | |
|-- requestAccess() ---------> | |
| |-- POST /sdk-access-request ->|
| | (HMAC-signed) |
| |<---- requestId, pending -----|
|<---- requestId --------------| |
| | |
|-- waitForApproval() -------> | |
| |-- GET /sdk-access-status --> |
| | (polls every 2s) |
| | User approves fields
| |<---- approved, grantedData --|
|<---- grantedData ------------| |
| | |
| Only approved fields received. Denied fields never leave the vault.API Reference
Constructor
new ShadowKeyClient(config: ShadowKeyConfig)| Option | Type | Default | Description |
|--------|------|---------|-------------|
| apiUrl | string | required | Supabase project URL + /functions/v1 |
| apiKey | string | required | API key from ShadowKey Settings page |
| timeout | number | 30000 | Request timeout in ms |
| retryAttempts | number | 3 | Max retries on server errors |
| debug | boolean | false | Enable debug logging (redacts sensitive fields) |
requestAccess(request): Promise<AccessResponse>
Request scoped access to a user's vault data. Creates a pending disclosure request that the vault owner must approve.
const response = await client.requestAccess({
agentId: 'my-agent-001', // Your agent's unique ID
agentName: 'My AI Assistant', // Human-readable name (shown to user)
requestedFields: ['email', 'phone'], // Fields you need
purpose: 'Send order confirmation', // Why (shown to user)
category: 'identity', // Optional: payment, identity, health, etc.
expiresIn: 300, // Optional: seconds until request expires (default 300)
});checkStatus(requestId): Promise<DisclosureStatus>
Check the current status of an access request.
const status = await client.checkStatus(response.requestId);
// status.status → 'pending' | 'approved' | 'denied' | 'expired'waitForApproval(requestId, maxWaitMs?, pollIntervalMs?): Promise<AccessResponse>
Poll for user approval with automatic timeout.
| Param | Default | Description |
|-------|---------|-------------|
| requestId | required | From requestAccess() |
| maxWaitMs | 300000 (5 min) | Max time to wait |
| pollIntervalMs | 2000 (2s) | Time between polls |
const result = await client.waitForApproval(response.requestId, 120000, 3000);submitReverseDisclosure(request): Promise<ReverseDisclosureResponse>
Submit data to a user's vault (reverse data flow — services sending data to users).
const receipt = await client.submitReverseDisclosure({
serviceId: 'acme-corp',
serviceName: 'Acme Corporation',
dataOffered: [
{ field: 'loyalty_points', value: '4,250', category: 'preferences' },
{ field: 'member_since', value: '2024-01-15', category: 'identity' },
],
purpose: 'Share your loyalty program data',
});Integration Examples
Both examples import directly from shadowkey-agent-sdk:
OpenRouter AI Agent (/examples/openrouter/)
An AI shopping agent that uses OpenRouter's free models with 4-model automatic failover:
import { ShadowKeyClient } from 'shadowkey-agent-sdk';
const shadowKey = new ShadowKeyClient({
apiUrl: `${process.env.SUPABASE_URL}/functions/v1`,
apiKey: process.env.SHADOWKEY_API_KEY,
});
// AI determines needed fields → SDK requests access → user approves → AI completes taskExpress.js Server (/examples/node-express/)
A REST API backend that wraps the SDK for multi-agent architectures:
import { ShadowKeyClient } from 'shadowkey-agent-sdk';
const shadowKey = new ShadowKeyClient({ ... });
app.post('/api/request-data', async (req, res) => {
const response = await shadowKey.requestAccess({ ... });
res.json(response);
});Error Handling
try {
const response = await client.requestAccess({ ... });
} catch (error) {
if (error.message.includes('timeout')) {
// Request timed out — check network or increase timeout
} else if (error.message.includes('401')) {
// Invalid or expired API key
} else if (error.message.includes('404')) {
// No vault found for this API key's user
} else {
// Server error — SDK auto-retried and all attempts failed
}
}Security
- HMAC-SHA256 signing — Every request includes timestamp, nonce, and signature headers
- 5-minute timestamp window — Rejects requests with stale timestamps (prevents replay attacks)
- Sensitive field redaction — Debug logs automatically redact
grantedData,grantedFields, andresponse_data - No secrets in transit — SDK receives only the fields the user approved, never the full vault
Links
- npm: shadowkey-agent-sdk
- Live Demo: shadowkey-ai.vercel.app/agent-demo
- Dashboard: shadowkey-ai.vercel.app
- Smart Contract: Basescan (Verified)
- GitHub: kimboltpro3-create/shadowkey
- Issues: GitHub Issues
License
MIT
