Agent SDK
Full reference for the HoodLayerAgent class. Reach for this when your AI agent needs to pay for services.
Installation
npm install @hoodlayerorg/sdk
HoodLayerAgent
import { HoodLayerAgent } from "@hoodlayerorg/sdk";
const agent = new HoodLayerAgent(config: HoodLayerAgentConfig);
HoodLayerAgentConfig
| Option | Type | Required | Description |
|---|---|---|---|
wallet |
Signer |
Yes | A viem account, ethers wallet, or compatible signer |
network |
"mainnet" \| "testnet" |
Yes | Which Robinhood Chain network to use |
rpcUrl |
string |
No | A custom RPC endpoint for Robinhood Chain |
facilitatorUrl |
string |
No | Facilitator URL override (default: HoodLayer’s hosted Facilitator) |
defaultToken |
string |
No | Token address used by default (default: USDC) |
Wallets
Two kinds of value work for wallet:
- A viem local account or an ethers wallet
- Anything that implements the
Signerinterface:{ address: Address, signTypedData(typedData): Promise<string> }
In practice that means signers from Privy, Dynamic, Turnkey, and other embedded wallet providers all work.
// viem local account
import { privateKeyToAccount } from "viem/accounts";
const account = privateKeyToAccount(process.env.WALLET_PRIVATE_KEY as `0x${string}`);
const agent = new HoodLayerAgent({ wallet: account, network: "mainnet" });
// embedded wallet from Privy
const agent = new HoodLayerAgent({ wallet: privySigner, network: "mainnet" });
Methods
agent.pay()
Sends a one-time payment through the x402 flow, covering the whole request-402-pay-retry cycle for you.
const result = await agent.pay(options: PayOptions): Promise<PayResult>
PayOptions
| Option | Type | Required | Description |
|---|---|---|---|
url |
string |
Yes | URL of the resource you’re paying for |
method |
string |
No | HTTP verb to use (default: "GET") |
body |
object |
No | Body to send with POST requests |
headers |
object |
No | Extra headers for the request |
maxAmount |
number |
No | Ceiling on what you’ll pay, in token base units. The call rejects if the service asks for more. |
token |
string |
No | Address of the token to pay with (default: USDC) |
PayResult
| Field | Type | Description |
|---|---|---|
data |
any |
The API’s response body, parsed |
status |
number |
Status code of the HTTP response |
headers |
object |
Headers from the response |
txHash |
string |
Hash of the Robinhood Chain transaction |
amountPaid |
number |
What was actually paid, in token base units |
const result = await agent.pay({
url: "https://api.example.com/v1/data",
maxAmount: 1_000_000, // bail out if the service wants more than 1 USDC
});
console.log(result.data); // the response body
console.log(result.txHash); // proof on-chain
agent.subscribe()
Opens an on-chain subscription to a plan, handing billing authority over to the service provider.
const sub = await agent.subscribe(options: SubscribeOptions): Promise<Subscription>
SubscribeOptions
| Option | Type | Required | Description |
|---|---|---|---|
planId |
string |
Yes | Id of the plan on-chain |
maxOveragePerCycle |
number |
No | Per-cycle cap on metered overage spend |
token |
string |
No | Use a different token than the plan’s default |
Returns: a Subscription object. The full structure is documented in Subscriptions.
const sub = await agent.subscribe({
planId: "0x7f3a...plan_id",
maxOveragePerCycle: 10_000_000, // allow overage up to 10 USDC
});
console.log(sub.id); // id of the subscription record on-chain
console.log(sub.status); // either "ACTIVE" or "TRIAL"
console.log(sub.nextBillingAt); // a Unix timestamp
agent.cancelSubscription()
Ends an active subscription. Happens on-chain, and takes effect right away.
await agent.cancelSubscription(options: { subscriptionId: string }): Promise<void>
agent.listSubscriptions()
Fetches every subscription tied to the agent’s wallet.
const subs = await agent.listSubscriptions(
options?: { status?: SubscriptionStatus }
): Promise<Subscription[]>
agent.createAllowance()
Sets up a metered spend cap. Details in Allowances.
const allowance = await agent.createAllowance(options: AllowanceOptions): Promise<Allowance>
AllowanceOptions
| Option | Type | Required | Description |
|---|---|---|---|
grantee |
string |
Yes | Address of the service wallet being authorized |
maxAmount |
number |
Yes | The overall spend cap, in token base units |
token |
string |
No | Which token contract (default: USDC) |
expiresAt |
number |
No | Expiry, as a Unix timestamp |
agent.revokeAllowance()
Pulls an allowance back before it expires.
await agent.revokeAllowance(options: { allowanceId: string }): Promise<void>
agent.getAllowance()
Reads the current state of an allowance.
const status = await agent.getAllowance(
options: { allowanceId: string }
): Promise<Allowance>
Error handling
Every failure case surfaces as a typed error thrown by the SDK:
import {
InsufficientFundsError,
PaymentRejectedError,
AllowanceExhaustedError,
FacilitatorError,
} from "@hoodlayerorg/sdk/errors";
try {
await agent.pay({ url: "...", maxAmount: 1_000_000 });
} catch (e) {
if (e instanceof InsufficientFundsError) {
console.error("Wallet needs more USDC", e.required, e.available);
} else if (e instanceof PaymentRejectedError) {
console.error("Service rejected payment proof", e.reason);
} else if (e instanceof FacilitatorError) {
console.error("Facilitator error", e.statusCode, e.message);
}
}
| Error class | Cause |
|---|---|
InsufficientFundsError |
The wallet holds less than the required amount |
PaymentRejectedError |
The service turned down the payment proof |
MaxAmountExceededError |
The service asked for more than maxAmount |
AllowanceExhaustedError |
The spend cap has been used up |
SubscriptionNotActiveError |
The subscription is cancelled or paused |
FacilitatorError |
The Facilitator responded with an error |
ChainTransactionError |
A transaction failed on-chain |