For Developers

Accounting infrastructure for stablecoin products.

Connect wallets, classify every transaction, and pull audit-ready financial statements over a JSON API. Build books into your product instead of building a ledger.

Instant sandboxSigned webhooksPython & Node SDKsOpenAPI 3
Pull a customer's September P&L
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_4821
import os, requests

r = requests.get(
    "https://app.getshepherd.co/api/v1/financial-statements",
    headers={"Authorization": f"Bearer {os.environ['SHEPHERD_API_KEY']}"},
    params={"start_date": "2026-09-01", "end_date": "2026-09-30",
            "end_user_id": "cust_4821"},
)
print(r.json()["net_income"])
const qs = new URLSearchParams({
  start_date: "2026-09-01",
  end_date: "2026-09-30",
  end_user_id: "cust_4821",
});

const res = await fetch(`https://app.getshepherd.co/api/v1/financial-statements?${qs}`, {
  headers: { Authorization: `Bearer ${process.env.SHEPHERD_API_KEY}` },
});
console.log((await res.json()).net_income);
200 OKapplication/json · 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"
}
Overview

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.

Connect

Wallets on Base, Ethereum, Polygon, Arbitrum, Tempo and Solana. Shepherd pulls the history and keeps scanning.

POST /wallets
Classify

Every transaction gets a GL code from AI, your rules, or your call. Overrides are kept as dated audit entries.

POST /transactions/{{id}}/classify
Report

Income statement and balance sheet, per customer, per entity, or consolidated, with fair value and FX included.

GET /financial-statements
Reconcile

Compare the ledger's computed balance with the live on-chain balance for each wallet.

GET /reconciliation
Book

Opening balances, AR and AP accruals, and links between the two legs of a conversion.

POST /accruals
Separate

Tag activity by end user, or create an entity per customer for separate books with consolidated views.

POST /entities

Base URL: https://app.getshepherd.co/api/v1. All requests and responses are JSON. Dates are YYYY-MM-DD.

Start in the sandbox: an instant key and synthetic data, no conversation needed. Live keys are issued to partners; request access when you're ready.
Quickstart

From key to financial statements in four calls

  1. 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);
  2. 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
    }
  3. 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",
    });
  4. 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_4821
    pnl = 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"
    }
Go deeper

Webhooks, SDKs and the full reference

Authentication, the sandbox, signed webhooks, Python and Node SDKs, every endpoint, and error codes.

Request a Demo

Tell us a bit about your business and we'll follow up to set up a demo.

Request received

Thanks. We'll be in touch shortly to set up a walkthrough.

Get a sandbox key

Instant. Synthetic data, nothing touches a chain.