# ContractorRoster developer quickstart

Canonical human guide: https://contractorroster.com/developers
Last source review: 2026-09-28. Check discovery for current rates and coverage.

## Choose an interface
- Roster Engine REST + npm: https://contractorroster.com/api/re/v1 — multiple business industries, X-API-Key: re_live_…, credits.
- Contractor REST + MCP: https://contractorroster.com/api/v1 and https://contractorroster.com/api/mcp — contractor state/trade/city-or-ZIP searches, Authorization: Bearer cr_live_…, separate prepaid dollar balance.
- Contractor key signup and MCP setup: https://contractorroster.com/mcp
- Contractor REST reference: https://contractorroster.com/api/v1/docs
- Contractor REST OpenAPI (NOT Roster Engine): https://contractorroster.com/api/v1/openapi.yaml

## First request: free, no authentication
```sh
curl --fail-with-body https://contractorroster.com/api/re/v1/rosters
```
Response fields: rosters (coverage snapshot), stats_updated_at (snapshot timestamp), rates.credits_per_record, rates.packs_usd.
Roster IDs: contractors, dentists, chiropractors, restaurants, retail, carriers, towing, movers, home_health, care_facilities. Actual geography and availability vary.

## Free npm discovery (Node.js 18+)
```js
// npm install roster-engine
// Node.js 18+, in an ES module (.mjs)
import RosterEngine from "roster-engine";

const engine = new RosterEngine();
const catalog = await engine.rosters(); // Free. No key needed.
console.log(catalog.rosters, catalog.rates, catalog.stats_updated_at);
```

## Create a Roster Engine key, only with owner approval
```sh
curl --fail-with-body https://contractorroster.com/api/re/v1/keys \
  -H 'Content-Type: application/json' \
  --data '{"email":"you@example.com"}'
```
Replace the example email. The response returns api_key once and free_credits: 0 (new keys have no automatic trial allowance). Store the key privately. A 409 means a key already exists for that email; recover the existing key or contact hello@contractorroster.com. Do not loop key creation.

## Fund the key, then make one intentional metered request
POST /topup with X-API-Key and {"pack_usd":10} to request a checkout URL. The owner completes payment. Check GET /balance before pulling; a new zero-balance key receives 402. Discovery remains free.
```sh
# Metered: up to 1 record, up to 5 credits at the current rate.
# Set ROSTER_ENGINE_API_KEY privately in your server environment first.
curl --fail-with-body \
  'https://contractorroster.com/api/re/v1/rosters/contractors/leads?state=CA&has_both=true&min_verification=licensed&limit=1' \
  -H "X-API-Key: $ROSTER_ENGINE_API_KEY"
```
Shell examples use POSIX syntax; in Windows use WSL/Git Bash or translate to PowerShell.
Response: records, pull_id, credits_charged (including total), balance_remaining, and optional cursor. An empty result is possible.
Current rates per returned record: record_only=1, one_contact=3, both=5 credits. Contact-bearing records are the default. Packs currently start at $10 for 500 credits. Consult discovery before spending.

## Roster Engine endpoints
Base: https://contractorroster.com/api/re/v1
- GET /rosters — No key. Free catalog, coverage snapshot and current credit rates.
- POST /keys — No key. Creates a key; JSON body: {"email":"you@example.com"}. Returned once with free_credits: 0. Fund the key before retrieving records.
- GET /balance — X-API-Key. Free balance check: credits and spend_lifetime.
- GET /rosters/{roster}/leads — X-API-Key. Metered records. Always set an explicit limit (1–500). Default: 50.
- POST /topup — X-API-Key. JSON body: {"pack_usd":10}. Returns a checkout_url; a person completes payment.

## Roster Engine filters
- state / city / zip / zip_prefix: Geography; use a two-letter state code.
- has_both / has_email / has_phone: Set true to require the selected contact fields. has_both=true requires both.
- min_verification: directory, public_record_seed, registered, or licensed. A stored source classification, not a fresh license check.
- min_rating: Minimum stored rating, when available.
- has_contact: Contact-bearing rows are the default. Use any to also allow record-only rows.
- limit / cursor: 1–500 records per call. Continue with the returned cursor and the same filters; each page is metered.

## Agent and spending rules
- Start with free discovery. Read stats_updated_at: coverage counts are a stored snapshot, not a live availability guarantee.
- Choose one API family. re_live_ keys use credits at /api/re/v1; cr_live_ keys use a separate prepaid dollar balance at /api/v1 and /api/mcp. Keys and balances are not interchangeable.
- Get the owner's permission before creating a key, pulling metered records, paginating, or starting a top-up. Keep keys in server-side secrets, never browser code, prompts, URLs or logs.
- Roster Engine leads GET requests spend credits. There is no dry_run mode on that endpoint. Do not add dry_run and assume a request is free.
- Use an explicit small limit and check the balance. At current rates, reserve up to 5 credits per requested record. Do not automatically retry an uncertain metered request: repeat pulls can charge again.
- In npm roster-engine 0.1.0, pullAll checks maxCredits after charging a page. It is not a strict pre-charge spending ceiling; use individually bounded pulls for budget control.
- Contractor MCP count_contractors is a free estimate; search_contractors supports dry_run:true. A paid search requires separate approval. Availability may change between preview and purchase.
- Preserve source, source_id, verification and verified_at where returned. Contact enrichment has its own contact_source. Do not claim every record is licensed or checked in real time.

## Suppression and your own exclusion lists
- Business opt-outs recorded by ContractorRoster are applied automatically to paid API contact results. Records excluded by that check are not charged. A failed policy check stops delivery.
- Your own exclusion list is different: it can help you avoid buying contacts you already hold. Customer-supplied lists are not yet supported by Roster Engine REST/npm or contractor REST/MCP. Do not invent exclusion parameters or assume they will be honored.
- For a website list order, use the list builder's exclusion-file option before checkout. Filtering API results in your own application happens after purchase and does not reduce the charge.
- Keep customer lists out of URLs, agent conversations and support messages. An exclusion list does not establish permission to contact the remaining businesses.
Website list builder: https://contractorroster.com/build

## Errors
- 401: check the API family, key and authentication header.
- 402: insufficient balance; ask the owner before topping up.
- 409 on key creation: key already exists for that email.
- 429: rate limited; back off. Current Roster Engine discovery limit is 30/min/IP, pulls 60/min/IP; key creation 5/hour/IP. These are not capacity guarantees.
- 503 or a non-JSON gateway response: unavailable. Do not treat as no matches. For an uncertain metered request, reconcile rather than blindly retrying.

Support: hello@contractorroster.com. Share an HTTP status and pull_id if available, never your key or customer records.
