What the API does
Shepherd turns on-chain and bank activity into a classified general ledger. The API exposes that ledger: you connect the accounts your customers use, Shepherd keeps the books, and you read the statements back.
Wallets on Base, Ethereum, Polygon, Arbitrum, Tempo and Solana. Shepherd pulls the history and keeps scanning.
POST /walletsEvery transaction gets a GL code from AI, your rules, or your call. Overrides are kept as dated audit entries.
POST /transactions/{{id}}/classifyIncome statement and balance sheet, per customer, per entity, or consolidated, with fair value and FX included.
GET /financial-statementsCompare the ledger's computed balance with the live on-chain balance for each wallet.
GET /reconciliationOpening balances, AR and AP accruals, and links between the two legs of a conversion.
POST /accrualsTag activity by end user, or create an entity per customer for separate books with consolidated views.
POST /entitiesBase URL: https://app.getshepherd.co/api/v1. All requests and responses are JSON. Dates are YYYY-MM-DD.
From key to financial statements in four calls
Get a sandbox key
One call, no signup form. You get a
shep_test_key and a seeded demo customer. Get one now. Live keys (shep_live_) are issued to partners and created on the Admin page of the Shepherd app.curl -X POST https://app.getshepherd.co/api/v1/sandbox/signup \ -H "Content-Type: application/json" \ -d '{"email": "you@company.com"}' # => { "api_key": "shep_test_...", "seeded": { "end_user_id": "cust_demo", ... } } export SHEPHERD_API_KEY="shep_test_..."# pip install shepherd-sdk from shepherd import Shepherd shep = Shepherd.create_sandbox(email="you@company.com") print(shep.sandbox_info["api_key"])// npm install @getshepherd/sdk import { Shepherd } from "@getshepherd/sdk"; const shep = await Shepherd.createSandbox({ email: "you@company.com" }); console.log(shep.sandboxInfo.api_key);Connect a wallet
Pass your own identifier for the customer as
end_user_id. Shepherd pulls the wallet's history, prices it, and auto-classifies what it can.curl -X POST https://app.getshepherd.co/api/v1/wallets \ -H "Authorization: Bearer $SHEPHERD_API_KEY" \ -H "Content-Type: application/json" \ -d '{"address": "0xYourWalletAddress", "chain": "base", "end_user_id": "cust_4821", "end_user_name": "Acme Payments"}'wallet = shep.wallets.connect( "0xYourWalletAddress", "base", end_user_id="cust_4821", end_user_name="Acme Payments", ) print(wallet["transactions_needing_review"])const wallet = await shep.wallets.connect({ address: "0xYourWalletAddress", chain: "base", end_user_id: "cust_4821", end_user_name: "Acme Payments", }); console.log(wallet.transactions_needing_review);Response · 201{ "wallet_id": 17, "address": "0xYourWalletAddress", "chain": "base", "end_user_id": "cust_4821", "transactions_found": 214, "transactions_saved": 214, "transactions_classified": 188, "transactions_needing_review": 26 }Review what needs a human
Anything the AI wasn't confident about stays unclassified. List it, then set the GL code. Reclassifications are kept as dated audit entries.
curl -G https://app.getshepherd.co/api/v1/transactions \ -H "Authorization: Bearer $SHEPHERD_API_KEY" \ -d end_user_id=cust_4821 -d gl_code=Unclassified curl -X POST https://app.getshepherd.co/api/v1/transactions/9041/classify \ -H "Authorization: Bearer $SHEPHERD_API_KEY" \ -H "Content-Type: application/json" \ -d '{"gl_code": "6200 - Software & SaaS", "counterparty": "Vercel"}'todo = shep.transactions.list(end_user_id="cust_4821", gl_code="Unclassified") shep.transactions.classify( todo[0]["id"], "6200 - Software & SaaS", counterparty="Vercel", )const todo = await shep.transactions.list({ end_user_id: "cust_4821", gl_code: "Unclassified" }); await shep.transactions.classify(todo[0].id, { gl_code: "6200 - Software & SaaS", counterparty: "Vercel", });Pull the statements
Filter by date range and by end user, entity, or wallet.
curl -G https://app.getshepherd.co/api/v1/financial-statements \ -H "Authorization: Bearer $SHEPHERD_API_KEY" \ -d start_date=2026-09-01 \ -d end_date=2026-09-30 \ -d end_user_id=cust_4821pnl = shep.statements.income( start_date="2026-09-01", end_date="2026-09-30", end_user_id="cust_4821", ) print(pnl["net_income"])const pnl = await shep.statements.income({ start_date: "2026-09-01", end_date: "2026-09-30", end_user_id: "cust_4821", }); console.log(pnl.net_income);Response · 200 · abridged{ "revenue": { "4100 - Revenue - Services": 48250.00 }, "expenses": { "6110 - Payroll": 21400.00, "6300 - Cloud Infrastructure": 3120.55 }, "total_revenue": 48250.00, "total_expenses": 24520.55, "fv_gain_loss": 0.00, "net_income": 23729.45, "transaction_count": 312, "classified_count": 306, "unpriced_count": 0, "functional_currency": "USD" }
Webhooks, SDKs and the full reference
Authentication, the sandbox, signed webhooks, Python and Node SDKs, every endpoint, and error codes.