API reference · v1

BcalScore REST API

Production-grade scoring API. Drop into your CRM, lead-routing, or BD tooling. Stripe-style auth. Idempotent. Webhooks. SOC 2 in audit.

Authentication

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 https://bcalenergy.com/api/score/v1/me
# GET /v1/me — verify your key
curl https://bcalenergy.com/api/score/v1/me \
  -H "Authorization: Bearer bcs_live_abc123"
const res = await fetch("https://bcalenergy.com/api/score/v1/me", {
  headers: { Authorization: "Bearer bcs_live_abc123" }
});
const me = await res.json();
import requests
r = requests.get(
  "https://bcalenergy.com/api/score/v1/me",
  headers={"Authorization": "Bearer bcs_live_abc123"}
)
me = r.json()

Errors & rate limits

Standard HTTP status codes. 429 on rate-limit; backoff on Retry-After. Limits: 60 req/min (Starter), 600 req/min (Growth), unlimited (Enterprise).

CodeMeaningAction
200OK
400Bad requestValidate payload
401Bad / missing keyCheck Authorization header
402Quota exhaustedTop-up plan
404Address not resolvableTry with city/state
422Address ambiguousPick from candidates
429Rate-limitHonor Retry-After
5xxServer errorRetry idempotently

Versioning

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.

POST /v1/score

Score a single US commercial address. Returns a 0-100 score, tier, full dossier, and the decision-maker.

POST https://bcalenergy.com/api/score/v1/score

Request body

FieldTypeNotes
addressstringRequired. Full US street address.
companystringOptional. Improves DM resolution.
icpstringOptional. oem, epc, asset_owner.
rubric_idstringOptional. Use a custom rubric.
idempotency_keystringRecommended. Prevents double-charge on retry.

Example

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"
  }'
const r = await fetch("https://bcalenergy.com/api/score/v1/score", {
  method: "POST",
  headers: {
    Authorization: "Bearer bcs_live_abc123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    address: "345 Spear Street, San Francisco, CA 94105",
    company: "Acme Corp",
    icp: "epc"
  })
});
const dossier = await r.json();
r = requests.post(
  "https://bcalenergy.com/api/score/v1/score",
  headers={
    "Authorization": "Bearer bcs_live_abc123",
    "Content-Type": "application/json",
  },
  json={
    "address": "345 Spear Street, San Francisco, CA 94105",
    "company": "Acme Corp",
    "icp": "epc",
  },
)
dossier = r.json()

Response

{
  "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"
}

POST /v1/score/bulk

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.

POST https://bcalenergy.com/api/score/v1/score/bulk
{
  "addresses": [
    { "address": "345 Spear St, SF, CA" },
    { "address": "500 Oracle Pkwy, Redwood City, CA" }
  ],
  "webhook_url": "https://your-app.com/hooks/bcs"
}

GET /v1/score/{id}

Retrieve a previously computed score. Cached for 30 days.

GET https://bcalenergy.com/api/score/v1/score/bcs_2026_04_a77f

GET /v1/contact

Look up the decision-maker for a company / address pair without running a full score. Cheaper, faster.

GET https://bcalenergy.com/api/score/v1/contact?company=Acme&address=...

POST /v1/webhooks

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_..."
}

Response schema (full)

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.

SDKs

LanguagePackageStatus
Node / TypeScriptnpm i @bcalscore/sdkStable
Pythonpip install bcalscoreStable
Gogo get github.com/bcalscore/goBeta
Rubygem install bcalscoreAlpha