Production-grade scoring API. Drop into your CRM, lead-routing, or BD tooling. Stripe-style auth. Idempotent. Webhooks. SOC 2 in audit.
BcalScore uses bearer-token auth. Pass your API key as a Authorization: Bearer <key> header on every request. Test keys are prefixed bcs_test_; live keys are prefixed bcs_live_.
# GET /v1/me — verify your key curl https://bcalenergy.com/api/score/v1/me \ -H "Authorization: Bearer bcs_live_abc123"
Standard HTTP status codes. 429 on rate-limit; backoff on Retry-After. Limits: 60 req/min (Starter), 600 req/min (Growth), unlimited (Enterprise).
| Code | Meaning | Action |
|---|---|---|
200 | OK | — |
400 | Bad request | Validate payload |
401 | Bad / missing key | Check Authorization header |
402 | Quota exhausted | Top-up plan |
404 | Address not resolvable | Try with city/state |
422 | Address ambiguous | Pick from candidates |
429 | Rate-limit | Honor Retry-After |
5xx | Server error | Retry idempotently |
The API is versioned in the URL (/v1/). Breaking changes go to /v2/ with a 12-month overlap. Non-breaking additions ship to current version. Subscribe to bcalenergy.com/score/changelog.
Score a single US commercial address. Returns a 0-100 score, tier, full dossier, and the decision-maker.
| Field | Type | Notes |
|---|---|---|
address | string | Required. Full US street address. |
company | string | Optional. Improves DM resolution. |
icp | string | Optional. oem, epc, asset_owner. |
rubric_id | string | Optional. Use a custom rubric. |
idempotency_key | string | Recommended. Prevents double-charge on retry. |
curl -X POST https://bcalenergy.com/api/score/v1/score \ -H "Authorization: Bearer bcs_live_abc123" \ -H "Content-Type: application/json" \ -d '{ "address": "345 Spear Street, San Francisco, CA 94105", "company": "Acme Corp", "icp": "epc" }'
{
"id": "bcs_2026_04_a77f",
"address": "345 Spear Street, San Francisco, CA 94105",
"score": 87,
"tier": "A",
"breakdown": {
"tariff": { "pts": 22, "max": 25 },
"load": { "pts": 23, "max": 25 },
"eligibility": { "pts": 17, "max": 20 },
"infra": { "pts": 14, "max": 15 },
"decision": { "pts": 8, "max": 10 },
"risk": { "pts": 3, "max": 5 }
},
"utility": { "name": "PG&E", "tariff": "B-19", "rate": 0.32 },
"facility": { "type": "Class A office", "annualKwh": 5400000, "peakKw": 920 },
"flags": {
"sgip_step": 5,
"ira_energy_community": true,
"gas_line_ft": 84,
"psps_tier": "Tier 1",
"calenviroscreen_pct": 78
},
"decision_maker": {
"name": "M. Rodriguez",
"title": "VP Real Estate & Facilities",
"email": "m.rodriguez@example.com",
"confidence": 94
},
"sources": ["eia.861", "cpuc.sgip.weekly", "parcel.ca", "contact-graph.v3"],
"computed_at": "2026-04-30T14:11:09Z"
}
Score up to 5,000 addresses in one call. Returns a job ID; poll /v1/jobs/{id} or set a webhook. Counts against quota only on success.
{
"addresses": [
{ "address": "345 Spear St, SF, CA" },
{ "address": "500 Oracle Pkwy, Redwood City, CA" }
],
"webhook_url": "https://your-app.com/hooks/bcs"
}
Retrieve a previously computed score. Cached for 30 days.
Look up the decision-maker for a company / address pair without running a full score. Cheaper, faster.
Register a webhook for score.completed, score.failed, contact.refreshed, tier_a.detected. Signed with HMAC-SHA256; verify with your webhook secret.
{
"url": "https://your-app.com/hooks/bcs",
"events": ["score.completed", "tier_a.detected"],
"secret": "whsec_..."
}
Every score response includes the fields above plus raw (source records), warnings (data caveats), and provenance (per-field source & timestamp). See full JSON Schema for type definitions.
| Language | Package | Status |
|---|---|---|
| Node / TypeScript | npm i @bcalscore/sdk | Stable |
| Python | pip install bcalscore | Stable |
| Go | go get github.com/bcalscore/go | Beta |
| Ruby | gem install bcalscore | Alpha |