Skip to content

How We Use the API: From Health Score to DCMA

Bellator Team2 min read

How We Use the API: From Health Score to DCMA

This is the integration pattern we recommend to teams embedding Bellator Schedule Intelligence into PMIS tools, document controllers, or internal “schedule QA” bots. It is deliberately boring: normalize once, triage fast, gate hard, forensics on demand.

Pipeline overview

Native file (XER / MSP XML)
        │
        ▼
 POST /api/v1/import/xer  (or /import/mpp)
        │  normalized_schedule + conversion report
        ▼
 POST /api/v1/health/score          ← fail-fast UX
        │
        ▼
 POST /api/v1/health/dcma-14-point   ← compliance gate (Starter+)
        │
        ├──► logic-audit / progress-audit
        ├──► baseline-compare / delay-analysis
        └──► schedule-risk-index

All Track A calls are stateless. You hold the schedule; we return intelligence.

Stage 0 — Auth and environment

  • API key via x-api-key (authentication)
  • Base URL: https://api.bellatorsi.com (sandbox host for non-prod keys as documented)
  • Never call forensics from the browser with a privileged key—proxy through your backend

Stage 1 — Import and classify

import requests

BASE = "https://api.bellatorsi.com/api/v1"
H = {"x-api-key": "YOUR_API_KEY"}

def import_xer(path: str) -> dict:
    with open(path, "rb") as fh:
        r = requests.post(
            f"{BASE}/import/xer",
            headers=H,
            files={"file": fh},
            data={
                "auto_classify_task_types": "true",
                "use_prefix_classification": "true",
            },
            timeout=180,
        )
    r.raise_for_status()
    data = r.json()["data"]
    report = data.get("conversion_report") or data.get("warnings")
    if report:
        print("conversion:", report)
    return data["normalized_schedule"]

Gate: abort if activity count is 0 or classification looks empty when you expected LOE/milestones. Details: XER best practices.

Stage 2 — Health triage (Tier 1)

def health_score(schedule: dict) -> dict:
    r = requests.post(f"{BASE}/health/score", headers=H, json=schedule, timeout=60)
    r.raise_for_status()
    return r.json()

Product UX ideas:

  • Show score + grade on upload
  • List top 3 signals only for free users
  • Block “Submit to customer” if grade ≤ D

Reading guide: How to read a CPM schedule health score.

Stage 3 — DCMA compliance gate (Tier 2)

Enrich the normalized schedule with analysis context your importer may not have inferred:

def dcma_assess(schedule: dict, status_date: str, target_finish: str | None = None) -> dict:
    body = {
        **schedule,  # if schedule already is {tasks: [...], ...}
        "status_date": status_date,
    }
    # Depending on schema, target may be top-level or inside options — see API reference.
    if target_finish:
        body["target_finish_date"] = target_finish

    r = requests.post(
        f"{BASE}/health/dcma-14-point",
        headers=H,
        json=body,
        timeout=120,
    )
    r.raise_for_status()
    return r.json()

Gate examples:

Policy Rule
Soft Warn on any failed check
Standard Fail build if open-end or CP tests fail
Strict Require all 14 checks pass before external submit

Conceptual background: DCMA 14-Point overview · fixes: common findings.

Stage 4 — On-demand forensics

Only spend complexity when the gate says so:

Need Endpoint family
Logic defects detail /health/logic-audit
Progress anomalies /health/progress-audit
Slip ownership /forensics/delay-analysis (name the AACE method)
Fragility before sim /health/schedule-risk-index

Async pattern (>1,000 tasks)

Sync analysis is capped for responsiveness. On Starter+ tiers, large schedules should use async health (and other async routes where offered) with polling or webhooks:

curl -X POST "https://api.bellatorsi.com/api/v1/health/score/async" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d @large-schedule.json

Then GET /api/v1/jobs/{job_id} or receive the webhook. See webhooks.

End-to-end sketch

def qa_pipeline(xer_path: str, status_date: str) -> None:
    schedule = import_xer(xer_path)
    health = health_score(schedule)
    print("health", health.get("score"), health.get("grade"))

    if float(health.get("score") or 0) < 60:
        raise SystemExit("Refuse DCMA: repair structure first")

    dcma = dcma_assess(schedule, status_date=status_date)
    failed = [
        c for c in (dcma.get("data") or {}).get("check_results", [])
        if c.get("passed") is False
    ]
    # Fallback if envelope shape differs — inspect keys in your environment
    print("dcma failed checks:", len(failed) or dcma.get("summary"))

Wire this to CI, a “Validate schedule” button, or a nightly PMO batch.

Testing without burning quota

  • Use the Playground and sandbox fixtures for deterministic demos
  • Keep golden XERs small for unit tests; run full customer files in staging only
  • Assert on check ids / finding codes, not English strings alone

Billing-aware design

Successful completed analyses are the billable events in Bellator’s model—not 202 Accepted polling. Structure retries so you do not double-submit identical large jobs after a client timeout without checking job status first.

Next steps

Sources

Share