PatternIQ API v1

Send a claim (or a batch) and receive the historical benchmark for each submitted field, the sample size behind it, the historical outcome difference and an evidence level. The API is deterministic and has no LLM in the analysis path.

Overview

Base URL: / on the deployed API host. All analysis endpoints are versioned under /api/v1. Interactive OpenAPI docs are served at /docs and the schema at /openapi.json.

EndpointPurpose
GET /healthLiveness and evidence load state
GET /api/v1/metaEvidence version, period, detectors, thresholds
POST /api/v1/analyzeOne claim
POST /api/v1/analyze/batchUp to 10,000 claims, with patterns
POST /api/v1/adapters/fhir/claimOne FHIR Claim resource
POST /api/v1/adapters/837pRaw X12 837P text
POST /api/v1/adapters/csvCSV text with an optional column map

Authentication

Every analysis request uses a bearer API key. Create keys with make key-create NAME=billing PREFIX=piq_live_. Keys are shown once and stored only as a salted SHA-256 hash; revocation is a timestamp, not a delete.

Authorization: Bearer piq_live_<key>
X-Request-ID: optional-correlation-id

Keys may be scoped to piq_test_ or piq_live_. Requests are rate limited per key (see /api/v1/meta for limits); a limited request returns 429. Keys never appear in browser JavaScript — the web app proxies through a server route.

Quick start

curl -X POST "$PATTERNIQ_API_URL/api/v1/analyze" \
  -H "Authorization: Bearer $PATTERNIQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "claim_id": "ABC123",
    "procedure": "99214",
    "primary_diagnosis": "I10",
    "pos": "11",
    "modifiers": ["25"],
    "quantity": 1,
    "charge": 285.00,
    "insurance_type": "HM"
  }'

Analyze one claim

POST /api/v1/analyze

{
  "claim_id": "ABC123",
  "review": true,
  "flag_count": 1,
  "flags": [
    {
      "detector": "modifier",
      "field": "modifier",
      "submitted_value": "25",
      "classification": "UNUSUAL",
      "message": "Verify modifier 25",
      "reason": "This modifier (25) appears on 6.2% of 14,821 comparable historical claims. It is 0.11× as common as the most common configuration for the same procedure and billing context. Comparable claims with this configuration had a 12.0 percentage-point higher historical $0-payment rate.",
      "evidence": {
        "evidence_level": "STRONG",
        "historical_frequency": 0.062,
        "submitted_count": 920,
        "context_count": 14821,
        "comparison_count": 13901,
        "zero_payment_rate": 0.24,
        "comparison_zero_payment_rate": 0.12,
        "zero_payment_difference_pp": 12.0,
        "alternatives": [{"value": "(none)", "count": 12000, "frequency": 0.81}]
      },
      "comparison_context": {
        "procedure": "99214",
        "pos": "11",
        "insurance_type": "HM",
        "primary_diagnosis": "I10",
        "context": "procedure+pos+insurance_type+primary_diagnosis"
      }
    }
  ],
  "detections": ["..."],
  "evidence_version": "v1.0.0",
  "data_vintage": {"from_year": 2016, "through_year": 2025, "population_version": "v1", "detector_version": "v1"}
}

detections carries the evidence for every evaluated field, including fields classified NORMAL, so an integration can log or display the benchmark even when nothing fired.

Analyze a batch

POST /api/v1/analyze/batch

{
  "batch": {
    "claims_analyzed": 20000,
    "claims_flagged": 327,
    "submitted_charges_flagged": 418291.0,
    "detector_counts": {"modifier": 141, "charge": 82, "pos": 51, "diagnosis": 37, "quantity": 16},
    "classification_counts": {"NORMAL": 85000, "UNUSUAL": 400, "HIGHLY_UNUSUAL": 90},
    "evidence_level_counts": {"INSUFFICIENT": 120, "LIMITED": 2100, "GOOD": 30000, "STRONG": 53000},
    "errors": 0
  },
  "patterns": [
    {
      "pattern_id": "modifier|97110|11|XX",
      "detector": "modifier",
      "label": "CPT 97110 + modifier XX",
      "affected_claims": 73,
      "submitted_charges": 94820.0,
      "batch_frequency": 0.314,
      "historical_frequency": 0.021,
      "relative_frequency": 14.95,
      "historical_outcome_difference_pp": 14.8,
      "evidence_level": "STRONG",
      "repeated": true,
      "claim_ids": ["..."]
    }
  ],
  "claims": ["per-claim results, same shape as /analyze"],
  "evidence_version": "v1.0.0",
  "data_vintage": {"...": "..."}
}

submitted_charges_flagged is the sum of submitted charges on flagged claims. It is not a loss estimate, not recoverable revenue, and does not imply the charge would otherwise have been lost.

CSV, FHIR and 837P adapters

Conversion happens at the edge, never inside the analysis engine. The canonical claim is the only shape the detectors see.

CSV

POST /api/v1/adapters/csv
{
  "csv_text": "cpt_code,dx1,place_service,mod1,units,billed,insurance\n99214,I10,11,25,1,285.00,HM",
  "column_map": {"procedure": "cpt_code", "primary_diagnosis": "dx1", "pos": "place_service",
                 "modifiers": "mod1", "quantity": "units", "charge": "billed", "insurance_type": "insurance"}
}

FHIR Claim

POST /api/v1/adapters/fhir/claim
{ "resourceType": "Claim", "id": "fhir-1", "item": [{"productOrService": {"coding": [{"code": "99214"}]}, ...}], ... }

837P

Send the raw interchange as the request body. Add ?insurance_type=HM: 837P carries no insurance category, only a payer identity.

curl -X POST "$PATTERNIQ_API_URL/api/v1/adapters/837p?insurance_type=HM" \
  -H "Authorization: Bearer $PATTERNIQ_API_KEY" \
  -H "Content-Type: text/plain" \
  --data-binary @batch.837p

Request schema (canonical claim)

FieldTypeNotes
procedurestringCPT/HCPCS, required
posstringPlace of service, required
insurance_typestringInsurance category code, required
primary_diagnosisstring?ICD-10; optional
additional_diagnosesstring[]Accepted and echoed; not used by V1 detectors
modifiersstring[]Only the first is evaluated in V1
quantitynumber?Must be > 0
chargenumber?Must be > 0; submitted billed amount
claim_idstring?Opaque caller identifier, echoed back

Response schema

FieldMeaning
reviewTrue when at least one field is UNUSUAL or HIGHLY_UNUSUAL
flag_countNumber of flagged fields
flags[]One entry per flagged field, with evidence and context
detections[]Every evaluated field, including NORMAL
evidence_versionThe historical benchmark version used
data_vintageYears, population version, detector version
warnings[]Unknown codes, skipped checks

Detector definitions

DetectorQuestionComparison context (field removed)
modifierHow common is this modifier configuration among comparable claims?procedure + pos + insurance (+ primary diagnosis), falling back to procedure + pos
posGiven the procedure, insurance and diagnosis, how common is this POS?procedure + insurance (+ diagnosis), falling back to procedure + insurance
quantityGiven the procedure and POS, how common is this billed quantity?procedure + pos
chargeWhere does the submitted charge sit in the historical billed-charge distribution?procedure + pos (99 quantiles)
diagnosisGiven the procedure and billing context, how common is this primary diagnosis?procedure + pos + insurance

The evaluated field is removed from its own comparison context, so a POS check never asks “among claims with this POS”. That avoids target leakage.

Classifications

ClassificationMeaning
NORMALConsistent with the benchmark for comparable claims
UNUSUALMaterially less common than the typical configuration, or a charge in the 1st–5th / 95th–99th percentile
HIGHLY_UNUSUALFar rarer than the typical configuration, or a charge beyond the 1st/99th percentile

Classification is deterministic and documented, not a score. It uses the relative frequency (this value vs the most common value in the same context) plus absolute frequency, with a large historical outcome difference escalating severity. Sparse cohorts are capped. There is no risk_score field.

Evidence levels

LevelComparison context size
INSUFFICIENTbelow the evidence floor (25) — the detector returns NORMAL with no claim of precision
LIMITED25–99
GOOD100–999
STRONG1,000 or more

A LIMITED cohort cannot produce a HIGHLY_UNUSUAL classification. THRESHOLDS are published in /api/v1/meta and travelled with every response by evidence version.

Error codes

StatusMeaning
400Malformed JSON body
401Missing, invalid or revoked API key
413Batch exceeds the configured limit, or body too large
422Validation failure; detail.errors lists the fields
429Rate limit exceeded; retry after a minute
500Internal error; response carries only request_id and status

Code examples

JavaScript

const res = await fetch(`${process.env.PATTERNIQ_API_URL}/api/v1/analyze`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.PATTERNIQ_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ procedure: "99214", pos: "11", insurance_type: "HM",
                         primary_diagnosis: "I10", modifiers: ["25"], charge: 285 }),
});
const result = await res.json();
if (result.review) console.log(result.flags[0].message);

Python

import os, httpx

response = httpx.post(
    f"{os.environ['PATTERNIQ_API_URL']}/api/v1/analyze",
    headers={"Authorization": f"Bearer {os.environ['PATTERNIQ_API_KEY']}"},
    json={"procedure": "99214", "pos": "11", "insurance_type": "HM",
          "primary_diagnosis": "I10", "modifiers": ["25"], "charge": 285},
    timeout=30,
)
response.raise_for_status()
result = response.json()
for flag in result["flags"]:
    print(flag["message"], flag["evidence"]["historical_frequency"])

Integration architecture

EHR / PM / billing / clearinghouse
        |
        v
  PatternIQ API  ->  canonical claim  ->  historical benchmark artifact
        |
        v
  flags + evidence + repeated patterns

The API holds no customer claim warehouse and no source-data access. Every request reads the precomputed evidence artifact, which is versioned and reproducible.

Privacy and retention

Default philosophy: analyze the claim, return the result, forget the claim.

  • Raw claim payloads are not persisted and are not written to logs or analytics.
  • No claim payload is sent to an LLM, telemetry, or a third-party logging service.
  • Operational metadata may be retained: request id, API key id, timestamp, latency, number of claims, number of flags, API version, evidence version and status code.
  • Customer-supplied claim IDs are opaque and are echoed back only.

This is an engineering posture, not a legal conclusion: PatternIQ does not claim HIPAA exemption or compliance. A compliance review is required before processing live PHI.

Versioning

The API version is in the path (/api/v1). The historical benchmark carries its own evidence_version, population_version and detector_version, all returned with every response, so an old result can always be tied to the exact benchmark that produced it. Changing the population definition bumps population_version; changing a detector or threshold bumps evidence_version or detector_version.