Skip to content

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
});
OptionTypeDescription
rpcUrlstringSolana RPC endpoint (devnet/mainnet). Helius recommended.
agentKeypairKeypairAgent identity. Signs each action_hash off-chain via Ed25519.
programId?stringProva 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 });
MethodReturnsNotes
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.