TypeScript SDK
Complete reference for `prova-agent-sdk` — the npm package that talks directly to the Anchor program over RPC (writes) and to the REST API (reads). Apache 2.0, no backend intermediary.
Installation & setup
npm install prova-agent-sdk
ProvaClient configuration
import { ProvaClient } from 'prova-agent-sdk';
const client = new ProvaClient({
rpcUrl: 'https://devnet.helius-rpc.com/?api-key=...',
agentKeypair, // signs every action hash (Ed25519)
// programId?: string // defaults to the Devnet deployment
});| Option | Type | Description |
|---|---|---|
rpcUrl | string | Solana RPC endpoint (devnet/mainnet). Helius recommended. |
agentKeypair | Keypair | Agent identity. Signs each action_hash off-chain via Ed25519. |
programId? | string | Prova program ID. Defaults to the Devnet deployment (G11d…). |
Hashing actions
// Static helper — SHA-256 of any string payload → 32-byte Uint8Array const actionHash = await ProvaClient.hashAction(JSON.stringify(payload));
Hash the exact structured payload you would show an auditor. Determinism is the point: the same payload always yields the same hash, making receipts independently recomputable.
On-chain lifecycle
// Register (once per operator)
const reg = await client.registerAgent({ operatorKeypair, policyRoot });
// Attest a single action
const receipt = await client.attest({
operatorKeypair,
actionHash,
actionType: 'ToolCall',
privacyMode: false,
});
// Batch up to 100 actions in one transaction
await client.batchAttest({
operatorKeypair,
attestations: [{ actionHash, actionType: 'Decision' }],
});
// Rotate the policy Merkle root
await client.updatePolicyRoot({ operatorKeypair, newRoot });
// Kill switch — permanently marks the agent as revoked
await client.revokeAgent({ operatorKeypair });| Method | Returns | Notes |
|---|---|---|
registerAgent({ operatorKeypair, policyRoot? }) | { txSignature, agentPda, explorerUrl } | Creates the agent PDA. One per operator; ~0.001 SOL rent. |
attest({ operatorKeypair, actionHash, actionType?, privacyMode? }) | { txSignature, explorerUrl } | actionHash must be exactly 32 bytes. Default type: Transaction. |
batchAttest({ operatorKeypair, attestations }) | { txSignature, explorerUrl } | 1–100 entries; throws BatchLimitExceededError above 100. |
updatePolicyRoot({ operatorKeypair, newRoot }) | { txSignature, explorerUrl } | Rotates the 32-byte policy Merkle root. |
revokeAgent({ operatorKeypair }) | { txSignature, explorerUrl } | Irreversible kill switch. Revoked agents cannot attest. |
Reading on-chain state
// Read the on-chain agent account
const account = await client.getAgentAccount(operator.publicKey);
// → { agentId, policyRoot, attestationCount, createdAt, revoked, ... }
const active = await client.isAgentActive(operator.publicKey);
// Decode recent attestations straight from chain logs (no API needed)
const recent = await client.getRecentAttestations(agentPda, { limit: 25 });
// Derive the agent PDA locally
const [agentPda, bump] = client.deriveAgentPda(operator.publicKey);REST API client
ProvaApiClient queries the indexed layer — use it for dashboards, audits, and verification flows where you read rather than write.
import { ProvaApiClient } from 'prova-agent-sdk';
const api = new ProvaApiClient({
apiUrl: 'https://prova-api.fly.dev',
apiKey: 'prova_...', // only needed for premium endpoints
});
// Public
const { data, pagination } = await api.listAttestations({
agentPda, actionType: 'Transaction', limit: 50, offset: 0,
});
const attestation = await api.getAttestation(pda);
const agent = await api.getAgent(agentId);
const stats = await api.getAgentStats(agentId);
// Premium (API key + x402)
const results = await api.bulkVerify([id1, id2, id3]); // up to 1000
const history = await api.getFullHistory(agentId); // up to 1000 receipts
const report = await api.getForensicReport(agentId);Error handling
import { BatchLimitExceededError } from 'prova-agent-sdk';
try {
await client.batchAttest({ operatorKeypair, attestations });
} catch (e) {
if (e instanceof BatchLimitExceededError) {
// split the batch: max 100 attestations per transaction
}
}All write methods surface Solana transaction errors as-is (e.g. insufficient funds, blockhash expiry) so you can retry with your own policy.