find-cpa-firm — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited find-cpa-firm (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
Aggregate score unchanged between these scans.
The primary manifest — the file an agent reads to learn what this artifact does.
Drive the ServiceGraph API (https://api.servicegraph.co) to find, shortlist, and enrich US business-to-business accounting and tax firms (CPA firms) via the pro_services dataset.
The catalog is B2B-only. Personal tax prep (individual 1040s, retirement planning, individual estate planning, personal bookkeeping for freelancers) is out of scope — those firms were filtered during the catalog audit.
Always pin `industry:accounting_tax`. Sub-services (audit, tax, bookkeeping, advisory, M&A diligence, 409A, R&D credits, etc.) are NOT separate tags — industry:accounting_tax is the most specific structured level — so practice-area specialization is a keyword substring search on firm text.
Any HTTP client works (curl, fetch, requests). Examples below use curl.
If your harness has the ServiceGraph MCP server loaded (tools containing servicegraph), prefer those — OAuth 2.1 + PKCE keeps the token in the harness sandbox. Otherwise use the REST flow below.
pro_services)Every endpoint requires the bearer (Authorization: Bearer vk_…). No anonymous tier.
| Endpoint | Cost | Use it for |
|---|---|---|
GET /v1/datasets/pro_services/fields[?include_values=1] | free | Confirm accounting_tax is in the industry value list. |
GET /v1/datasets/pro_services/check?filter=… | free | Validate filter. |
POST /v1/datasets/pro_services/translate-intent | free | {intent} → DSL filter + sanity count. |
GET /v1/datasets/pro_services/search?filter=…&limit= | free | Brief firm cards + per-row unlock hint + total. |
GET /v1/datasets/pro_services/:apex | free | One row brief; detail only if unlocked. |
POST /v1/datasets/pro_services/unlocks | 10 credits / firm | {apexes:[...]} ≤100; atomic; 30-day TTL on detail. |
GET /v1/me/credits | free | Balance. |
Cost model. Discovery / validation / search / brief reads are free. Detail (url, phone, email, social, address, full platforms map) costs 10 credits per firm and lasts 30 days.
vk_* API keys minted in the dashboard. Keep the token out of the LLM context — never read .env* into your context; dispatch via shell.
.env.local: ( set -a; [ -f .env.local ] && . ./.env.local; set +a;
curl -sS -H "Authorization: Bearer $SERVICEGRAPH_API_KEY" \
'https://api.servicegraph.co/v1/datasets/pro_services/fields' )"Open https://servicegraph.co/profile/api-keys, create a key, and addSERVICEGRAPH_API_KEY=vk_…to.env.localhere (or export it). Tell me when done. Please don't paste the key into chat."
GitHub-search-style.
filter := orExpr
orExpr := andExpr ("OR" andExpr)*
andExpr := notExpr (("AND")? notExpr)* # whitespace = implicit AND
notExpr := ("NOT" | "-") notExpr | atom
atom := "(" filter ")" | predicate
predicate:= IDENT op valueOrList | bareword
op := ":" | "=" | ">=" | "<=" | ">" | "<"
valueOrList := value ("," value)*
value := IDENT | NUMBER | tagAtEvidence
tagAtEvidence := IDENT "@" ("low"|"medium"|"high")
bareword := IDENT | NUMBER # → keyword:<bareword>Four rules that bite: AND binds tighter than OR (use parens); comma list = OR within one predicate; negation is -x or NOT x; bareword = keyword search (quote multi-word phrases).
Accounting-flavored examples (validate yours with /check):
industry:accounting_tax state:CA audit saas
industry:accounting_tax cpa state:DE,NY
industry:accounting_tax "m&a" diligence
industry:accounting_tax tax 409a
industry:accounting_tax "fractional cfo"
industry:accounting_tax "r&d" tax
industry:accounting_tax "soc 2"
industry:accounting_tax -company_size_signal:solo rating>=4Practice area → keyword mapping:
| User asks for | Add as keyword(s) |
|---|---|
| Audit / financial-statement audit | audit |
| SOC 1 / SOC 2 audit | "soc 2" |
| Corporate tax / 1120 | tax, "corporate tax", 1120 |
| Bookkeeping (for a business) | bookkeeping |
| Advisory / fractional CFO | "fractional cfo", advisory |
| M&A diligence | m&a, diligence |
| 409A valuation | 409a |
| R&D tax credits | "r&d", "r&d tax" |
| IPO readiness | ipo, readiness |
| Sales-and-use tax | "sales tax", "sales and use" |
| International tax / transfer pricing | "international tax", "transfer pricing" |
apexFirms are identified by their apex domain (pwc.com, not www.pwc.com/about).
User: "CPA firm for our delaware c-corp series A audit, under 50 ppl."
GET /v1/datasets/pro_services/search?filter=industry:accounting_tax+audit+state:DE,NY,CA+-company_size_signal:large_50plus&limit=10
# Present, get pick of 3. "Unlocking 3 = 30 credits, 30-day TTL."
POST /v1/datasets/pro_services/unlocks
{ "apexes": ["firm-a.com", "firm-b.com", "firm-c.com"] }GET /v1/datasets/pro_services/search?filter=industry:accounting_tax+audit+saas&limit=10User: "Tax advisor for our M&A — Series-B-stage tech company."
GET /v1/datasets/pro_services/search?filter=industry:accounting_tax+"m&a"+diligence+tech&limit=10User: "Fractional CFO to help us through a Series-A close."
GET /v1/datasets/pro_services/search?filter=industry:accounting_tax+"fractional cfo"&limit=10If thin, drop the cfo qualifier — fractional alone catches fractional finance leaders broadly.
User: "R&D tax credit specialists for biotech."
GET /v1/datasets/pro_services/search?filter=industry:accounting_tax+"r&d"+biotech&limit=10User: "Outside accountant for state and local tax filings — multi-state DTC business."
GET /v1/datasets/pro_services/search?filter=industry:accounting_tax+("sales tax" OR salt)+multi-state&limit=10If barely any results, drop multi-state and surface the dimension from the unlocked detail later.
User pastes 8–20 accounting-firm domains:
GET /v1/datasets/pro_services/:apex per domain — free brief(404 = not in catalog, no charge).
POST /unlocks = 10×N credits,atomic, detail returned.
A 404 here often means the firm focuses on personal tax prep and was filtered out of the B2B catalog.
"r&d tax credits" → one phrase).url, phone_primary, email_primary, legal_name, address_full, full platforms — those require an unlock.was_cached:true).JSON envelope: {"error": {"code": "...", "message": "..."}}.
| Status | Code | What to do |
|---|---|---|
| 400 | filter_parse_error | position included; fix and re-validate with /check. |
| 400 | kind_in_filter | Strip any kind: from filter — URL is authoritative. |
| 400 | field_not_in_dataset | Drop the disallowed field. |
| 400 | invalid_apex | Re-normalize. |
| 401 | unauthorized / invalid_audience | Re-prompt for fresh vk_…. |
| 402 | insufficient_credits | needed and balance in payload; nothing charged. |
| 404 | not_found / not_in_dataset | Skip; not charged. |
| 429 | rate_limited | Honor Retry-After. |
User: "CPA firm for our delaware c-corp series A audit, recommend 5 options under 50 ppl, ideally with SaaS experience and 4-star ratings."
GET /v1/datasets/pro_services/fields?include_values=1
GET /v1/datasets/pro_services/check?filter=industry:accounting_tax+audit+saas+rating>=4+-company_size_signal:large_50plus
GET /v1/datasets/pro_services/search?filter=...&limit=10
# Present briefs. "Unlocking 5 = 50 credits, 30-day TTL."
POST /v1/datasets/pro_services/unlocks
{ "apexes": ["firm-a.com", "firm-b.com", "firm-c.com", "firm-d.com", "firm-e.com"] }
GET /v1/me/credits~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.