Skip to content

SigilAgent SDK reference

SigilAgent is the class your agent uses to sign. It carries an as_live_… session token and talks to /v1/agents/* on the Sigil API. Policies are evaluated server-side; the SDK is a thin wrapper.

Install

Terminal window
pnpm add @sigilkeys/sdk

Constructor

import { SigilAgent } from '@sigilkeys/sdk';
const agent = new SigilAgent({
apiBaseUrl: 'https://api.sigilkeys.com',
sessionToken: process.env.SIGIL_AGENT_TOKEN!, // as_live_…
});

The constructor refuses tokens that don’t start with as_live_ — failing fast is better than getting a runtime 401 on the first sign.

await agent.getSession(): Promise<AgentSessionInfo>

Returns the session’s profile: bound wallet, current spend, limits, allowed chains/methods/recipients, expiry. Call this on startup to verify the agent has the budget it expects.

const s = await agent.getSession();
if (BigInt(s.spentNative) >= BigInt(s.maxSpendTotalNative ?? '0')) {
throw new Error('budget exhausted');
}

await agent.signMessage(message, { network })

Signs message for network. Returns the signature in the network’s canonical format (hex for EVM, base58 for Solana, base64 for Bitcoin, etc).

const sig = await agent.signMessage('I am a robot', { network: 'base' });

await agent.signTypedData(typedData, { network })

EVM-only. Standard EIP-712 typed-data signing.

const sig = await agent.signTypedData({
domain: { name: 'MyApp', chainId: 8453 },
types: { Order: [{ name: 'amount', type: 'uint256' }] },
primaryType: 'Order',
message: { amount: '1000' },
}, { network: 'base' });

await agent.sendTransaction(input)

const { signature } = await agent.sendTransaction({
network: 'base',
to: '0x…',
value: '50000000000000000', // 0.05 ETH in wei
data: '0x', // hex calldata
});

This is where the policy engine has the most to say: chain, recipient, native value all get checked before the TEE is asked.

Handling policy rejections

Rejections come back as AgentPolicyError, with a stable reason code:

import { AgentPolicyError } from '@sigilkeys/sdk';
try {
await agent.sendTransaction({ network: 'base', to: addr, value: amount });
} catch (e) {
if (e instanceof AgentPolicyError) {
switch (e.reason) {
case 'chain_not_allowed':
case 'recipient_not_in_allowlist':
case 'tx_value_exceeds_per_tx_limit':
case 'tx_value_exceeds_session_total':
case 'method_not_allowed':
// Don't retry: the policy will keep saying no.
await alertOperator(e.reason);
break;
}
}
throw e;
}

A list of every code lives in Policies.

Inside vs outside policy

AgentPolicyError is the only way the policy engine ever shows up. If the TEE itself fails (network glitch, share retrieval issue), you get a regular Error — those are retryable. Policy errors aren’t.