GitHub fixerprotocol.org →
SDK Reference

SDK Reference

Full reference for the TypeScript and Python SDKs. Both expose the same surface, wallet management, payments, transactions, and spend policies.

TypeScript SDK

The TypeScript SDK is the primary SDK for Fixer Protocol. It targets ES2020+ and ships as both CommonJS and ESM. It has zero runtime dependencies.

Installation

bash
npm install @fixerprotocol/sdk
# or: bun add @fixerprotocol/sdk  |  pnpm add @fixerprotocol/sdk

Requires Node.js ≥ 18 (for the global fetch API). Works with Bun and Deno without any polyfills.

FixerProtocol

The main client class. Exported as FixerProtocol from the package root.

typescript
import { FixerProtocol } from "@fixerprotocol/sdk";

const fixer = new FixerProtocol({
  agentId: "my-agent",
  apiKey:  process.env.FIXER_API_KEY!,
  baseUrl: "https://api.fixerprotocol.org", // optional, this is the default
});

Constructor parameters, FixerConfig

agentId
string
required
A unique identifier for this agent. Maps to a Solana PDA wallet, must be stable across restarts. Use descriptive, slug-like strings: "research-agent-v2", "orchestrator-prod".
apiKey
string
required
Your API key from the dashboard. Sent as a Bearer token on every request. Always load from an environment variable, never hard-code.
baseUrl
string
optional
Override the gateway base URL. Defaults to https://api.fixerprotocol.org. Useful for pointing at a staging environment or a self-hosted instance.

Instance properties

fixer.agentId
string (readonly)
The agentId passed at construction.
fixer.wallet
WalletResource
Wallet operations, get info, check balance, fund. See fixer.wallet.
fixer.transactions
TransactionsResource
List and retrieve transactions. See fixer.transactions.
fixer.policies
PoliciesResource
Get and set spend policies. See fixer.policies.

fixer.pay()

Route a payment to any service endpoint. The gateway detects the required protocol (x402 or MPP) from the target service's response and handles all handshake logic transparently.

typescript
const result: PayResult = await fixer.pay(options: PayOptions);

PayOptions

endpoint
string
required
The full URL of the service to call. Must be HTTPS. This is the upstream API endpoint your agent wants to call, Fixer Protocol intercepts the 402 response and completes the payment.
method
"GET" | "POST" | "PUT" | "PATCH" | "DELETE"
optionaldefault: "GET"
HTTP method to use when calling the endpoint.
body
unknown
optional
Request body for POST/PUT/PATCH calls. Serialized as JSON. Passed through to the upstream API after payment is resolved.
headers
Record<string, string>
optional
Additional headers to forward to the upstream API (e.g. Authorization for services that require both payment and auth). Payment headers are injected automatically.
privacy
PrivacyOptions
optional
Enable ZK privacy for this specific call. See ZK Privacy. If omitted, the payment is transparent (default).
idempotencyKey
string
optional
Client-supplied idempotency key. If a request with the same key has already been processed, the gateway returns the original result instead of reprocessing. Useful for retry logic.

PayResult

status
number
HTTP status code returned by the upstream service (e.g. 200).
txHash
string
Solana transaction hash. Use this to look up the payment on Solana Explorer or via fixer.transactions.get().
amountPaid
{ usdc: number }
The USDC amount deducted from your agent wallet for this call.
protocol
"x402" | "mpp"
Which payment protocol was used to complete this transaction.
data
unknown
The actual response payload from the upstream API service, the data your agent requested.
privateNote
string | undefined
Only present when privacy.mode is "full" or "confidential_amount". An encrypted note for your own records.
disclosureProof
string | undefined
Only present when privacy.disclosureKey was set. A ZK viewing credential openable only by the specified public key holder.

Privacy example

typescript
const result = await fixer.pay({
  endpoint: "https://api.service.com/resource",
  method: "POST",
  body: { query: "..." },
  privacy: {
    mode: "full",                             // hide amount, sender, receiver
    disclosureKey: complianceOfficerPublicKey, // optional: auditor can decrypt
  },
});

console.log(result.txHash);          // Solana nullifier hash — no identity on-chain
console.log(result.privateNote);     // encrypted note for your records
console.log(result.disclosureProof); // openable only by disclosureKey holder

fixer.wallet

Access your agent's Solana wallet. The wallet is created automatically on first use and persists across sessions via the Solana PDA associated with your agentId.

wallet.get()

Returns full wallet info including the on-chain address and USDC balance.

typescript
const wallet: WalletInfo = await fixer.wallet.get();
// {
//   agentId: "my-agent",
//   address: "7xKXtg2eH9sZ7pWbRqTJ3mQfJL...",  // Solana PDA
//   balance: { usdc: 42.50 }
// }

WalletInfo

agentId
string
The agent identifier this wallet belongs to.
address
string
Solana public key (base58). Send USDC to this address to fund the wallet.
balance
{ usdc: number }
Current confirmed USDC balance on Solana mainnet.

wallet.balance()

Returns only the balance, a convenience shorthand for wallet.get() when you don't need the full wallet info.

typescript
const balance: WalletBalance = await fixer.wallet.balance();
console.log(balance.usdc); // 42.50

wallet.fund()

Programmatically top up the wallet balance.

typescript
const result: FundResult = await fixer.wallet.fund({
  usdc: 100,
  idempotencyKey: "top-up-2026-06-01", // optional
});

console.log(result.txHash);       // Solana tx hash of the funding transaction
console.log(result.amount.usdc);  // 100
console.log(result.balance.usdc); // updated balance after funding

FundOptions

usdc
number
required
USDC amount to deposit. Must be positive and within your plan's allowed range.
idempotencyKey
string
optional
Prevents duplicate funding operations if the same key is submitted twice.

fixer.transactions

transactions.list()

Retrieve a paginated list of transactions for this agent.

typescript
const result: TransactionList = await fixer.transactions.list({
  limit:    50,
  offset:   0,
  protocol: "x402",             // filter by protocol (optional)
  from:     "2026-05-01",       // ISO 8601 date range (optional)
  to:       "2026-05-31",
});

ListTransactionsOptions

limit
number
optionaldefault: 20
Maximum results per page. Maximum value: 100.
offset
number
optionaldefault: 0
Number of records to skip for pagination.
protocol
"x402" | "mpp"
optional
Filter results to a specific protocol.
from
string
optional
Start of date range. ISO 8601 format: "2026-05-01" or "2026-05-01T00:00:00Z".
to
string
optional
End of date range (inclusive). Same format as from.

Transaction object

txHash
string
Solana transaction hash, unique identifier for this payment.
agentId
string
The agent that initiated this payment.
endpoint
string
The service URL that was called.
amount
{ usdc: number }
Amount paid in USDC.
protocol
"x402" | "mpp"
Protocol used for this payment.
timestamp
string
ISO 8601 timestamp of when the payment was settled on Solana.
status
"confirmed" | "pending" | "failed"
Current status on Solana. Most payments confirm in under 1 second.
solanaTxLink
string
Direct URL to the Solana Explorer entry for this transaction.
parentTxHash
string | undefined
Present for sub-agent payments, links this transaction to the orchestrator's call.

transactions.get()

typescript
const tx: Transaction = await fixer.transactions.get("5xGh9...Kj3m");
console.log(tx.status);       // "confirmed"
console.log(tx.solanaTxLink); // "https://explorer.solana.com/tx/5xGh9..."

fixer.policies

policies.get()

Retrieve the currently active spend policy for this agent.

typescript
const policy: SpendPolicy = await fixer.policies.get();
console.log(policy.dailyBudget?.usdc); // 100

policies.set()

Replace the agent's spend policy. All fields are optional, omit a field to leave it unconstrained.

typescript
const saved: SpendPolicy = await fixer.policies.set({
  dailyBudget:    { usdc: 100 },
  perCallLimit:   { usdc: 1.00 },
  allowedDomains: ["api.dune.com", "api.browserbase.com"],
  blockedDomains: ["badactor.com"],
  rateLimit:      { calls: 500, window: "1h" },
});

SpendPolicy fields

dailyBudget
{ usdc: number }
optional
Maximum total USDC spend per calendar day (UTC). Payments that would exceed this are rejected before submission.
perCallLimit
{ usdc: number }
optional
Maximum USDC for any single fixer.pay() call. Acts as a ceiling on individual payment amounts.
allowedDomains
string[]
optional
Whitelist of host names. If non-empty, payments to any host not in this list are blocked. Exact hostname match (no wildcards).
blockedDomains
string[]
optional
Explicit blocklist of hosts. Takes precedence over allowedDomains.
rateLimit
{ calls: number; window: string }
optional
Maximum number of calls within a sliding time window. window is a duration string: "1m", "1h", "24h".

Error Handling

All SDK errors extend FixerError, which extends the built-in Error. Catch specific classes to handle different failure modes.

typescript
import {
  FixerProtocol,
  FixerError,
  AuthenticationError,
  InsufficientFundsError,
  PolicyViolationError,
  RateLimitError,
  APIError,
} from "@fixerprotocol/sdk";

try {
  const result = await fixer.pay({ endpoint: "https://api.service.com/" });
} catch (err) {
  if (err instanceof AuthenticationError) {
    // Invalid API key — check FIXER_API_KEY env var
    console.error("Auth failed:", err.message);
  } else if (err instanceof InsufficientFundsError) {
    // Wallet balance too low
    await topUpWallet();
  } else if (err instanceof PolicyViolationError) {
    // Blocked by a spend policy — log and skip
    console.warn("Policy blocked:", err.message);
  } else if (err instanceof RateLimitError) {
    // Too many calls — back off and retry
    await sleep(60_000);
  } else if (err instanceof APIError) {
    // Gateway returned an unexpected HTTP error
    console.error(`API error ${err.statusCode}:`, err.message);
  } else if (err instanceof FixerError) {
    // Any other Fixer-specific error
    console.error(`${err.code}:`, err.message);
  } else {
    // Network error, JSON parse error, etc.
    throw err;
  }
}

Error classes

FixerError
Base class · code: string · statusCode?: number
All SDK errors extend this class. Check err.code for the machine-readable error type and err.statusCode for the HTTP status.
AuthenticationError
code: "authentication_error" · HTTP 401
The API key is missing, invalid, or revoked. Verify your FIXER_API_KEY environment variable.
InsufficientFundsError
code: "insufficient_funds" · HTTP 402
The agent wallet does not have enough USDC to cover the payment. Fund the wallet and retry.
PolicyViolationError
code: "policy_violation" · HTTP 403
The payment was blocked by an active spend policy, daily budget exceeded, domain not in allowlist, or per-call limit breached. The violation is logged on-chain.
RateLimitError
code: "rate_limit_exceeded" · HTTP 429
The agent has exceeded its configured rate limit. Back off and retry after the window resets.
APIError
code: "api_error" · HTTP 5xx or other
The gateway returned an unexpected error. Check err.statusCode for the HTTP status. Transient 5xx errors are safe to retry with exponential backoff.

TypeScript Types

All types are exported from @fixerprotocol/sdk. Import only what you need.

typescript
import type {
  FixerConfig,
  PayOptions,
  PayResult,
  PrivacyOptions,
  WalletInfo,
  WalletBalance,
  FundOptions,
  FundResult,
  Transaction,
  TransactionList,
  ListTransactionsOptions,
  SpendPolicy,
} from "@fixerprotocol/sdk";

Python SDK

The Python SDK mirrors the TypeScript API with Pythonic naming conventions (snake_case). It requires Python 3.10+ and uses httpx for async HTTP.

Installation

bash
pip install fixerprotocol

Quickstart

python
import os
import asyncio
from fixerprotocol import FixerProtocol

async def main():
    fixer = FixerProtocol(
        agent_id="my-research-agent",
        api_key=os.environ["FIXER_API_KEY"],
    )

    # Make a payment
    result = await fixer.pay(
        endpoint="https://api.fal.ai/v1/inference",
        method="POST",
        body={"model": "flux-pro", "prompt": "A futuristic city skyline"},
    )

    print(f"Status:     {result.status}")
    print(f"Tx hash:    {result.tx_hash}")
    print(f"Amount:     {result.amount_paid['usdc']} USDC")
    print(f"Protocol:   {result.protocol}")

    # Wallet balance
    balance = await fixer.wallet.balance()
    print(f"Balance:    {balance['usdc']} USDC")

    # Spend policies
    await fixer.policies.set(
        daily_budget={"usdc": 50},
        per_call_limit={"usdc": 0.50},
        allowed_domains=["api.fal.ai", "api.dune.com"],
    )

    # Transaction history
    result = await fixer.transactions.list(limit=10)
    for tx in result["transactions"]:
        print(f"  {tx['tx_hash']} — {tx['amount']['usdc']} USDC")

asyncio.run(main())

Error handling (Python)

python
from fixerprotocol import (
    FixerProtocol,
    AuthenticationError,
    InsufficientFundsError,
    PolicyViolationError,
    RateLimitError,
    APIError,
)

try:
    result = await fixer.pay(endpoint="https://api.service.com/")
except AuthenticationError:
    print("Invalid API key")
except InsufficientFundsError:
    print("Wallet balance too low")
except PolicyViolationError as e:
    print(f"Blocked by policy: {e}")
except RateLimitError:
    print("Rate limit hit — back off and retry")
except APIError as e:
    print(f"API error {e.status_code}: {e}")

Python method reference

Python methodTypeScript equivalentDescription
await fixer.pay(...)fixer.pay()Route a payment
await fixer.wallet.get()fixer.wallet.get()Wallet info + balance
await fixer.wallet.balance()fixer.wallet.balance()USDC balance only
await fixer.wallet.fund(...)fixer.wallet.fund()Top up wallet
await fixer.transactions.list(...)fixer.transactions.list()List transactions
await fixer.transactions.get(tx_hash)fixer.transactions.get()Single transaction
await fixer.policies.get()fixer.policies.get()Current policy
await fixer.policies.set(...)fixer.policies.set()Update policy