Skip to navigation

Agent & LLM Guide

This page is an AGENTS.md-style guide for using an AI coding agent — Claude Code, Cursor, Copilot, or any LLM — to explore and query Candid Data Share. It’s a router: it tells the agent which docs to read and how to reason about the data, without duplicating the per-table schemas that already live in this section.

Point your agent here

Give your agent a link to this page or its Markdown version — append .md to the URL:

https://docs.joincandidhealth.com/data-share/agents.md

Every page in these docs has a .md twin, so an agent can fetch clean Markdown for any table reference below.

What Candid Data Share is

Candid Data Share gives you direct BigQuery access to a set of export_* tables describing encounters, service lines, claims, and the financial transaction ledger behind them. It is documentation-and-data only: these docs describe schema and structure; the dataset itself is your organization’s own data in BigQuery. Access is via service-account credentials (usable directly or through tools like Fivetran/Airbyte) — see the Overview.

Read these first

  1. Data Model & Grain — the entity hierarchy (Encounter → Service Line → Charge → Transaction), the grain of every table (current-state, version history, or transaction ledger), void handling, and join paths. Read this before writing any aggregation.
  2. FAQ — the interpretation gotchas (claim status vs. X12 status code, payments vs. adjustments, diagnosis representation, CARC/RARC codes, patient credits, external IDs, refresh cadence).
  3. Per-table column references — the tables below, for exact column names, types, and meanings.

How an agent should work with this data

  • Ground every column and join in the reference pages below — do not invent column names. If a column isn’t documented, say so rather than guessing.
  • Respect grain before aggregating. export_transaction is the only table with amounts to aggregate: sum amount_cents per charge_id, service_line_id, or encounter_id, optionally split by counter_party_type. The detail tables (export_charge_details, export_payment_details, export_adjustment_details) annotate ledger rows and carry no amounts to sum. Current-state tables (export_encounter, export_service_line, the financial summaries) have one row per entity — don’t dedupe by updated_at. Version history tables (export_patient_insurance_history, export_patient_non_insurance_payer_history, export_patient_note_history) have one row per version — filter on the latest-record flag for current state.
  • Exclude voids when computing live financials: voids_transaction_id IS NULL AND voided_by_transaction_id IS NULL.
  • Don’t treat any table as append-only. Existing rows can change — for example, voided_by_transaction_id is filled in on a transaction after it’s voided. For incremental ingestion, pull rows by updated_at daily and run a full refresh weekly.
  • This dataset is not real-time and not for invoicing. It is refreshed on a nightly cadence. For patient balances/invoicing use the patient invoicing integration guide.
  • Handle PHI carefully. Many tables carry patient identifiers (name, DOB, address, member IDs). When helping a user query their own live data, keep example output minimal and relevant — do not dump full rows or PHI-heavy columns into chat unless the user specifically needs them for their own debugging.
  • Escalate the unknowns. Exact enum values (plan/insurance type), CARC/RARC descriptor text, and access requests are not derivable from these docs — direct the user to support@joincandidhealth.com.

Table map

Encounters & Service Lines

TableGrainReference
export_encounterone row per encounter_id (claim flattened on)docs
export_service_lineone row per service_line_id (claim procedure line item)docs
export_financial_summaryone row per encounter_id (computed rollup)docs
export_claim_submission_historyone row per claim_submission_id (many per claim)docs
export_service_line_financial_summaryone row per service_line_id (computed rollup)docs
export_service_line_projected_financialsone row per service_line_id (projected)docs

Financial Transactions

TableGrainReference
export_transactionone row per transaction_id (the ledger — carries amount_cents)docs
export_charge_detailsone row per transaction_id (CHARGE details)docs
export_payment_detailsone row per transaction_id (PAYMENT details)docs
export_adjustment_detailsone row per transaction_id (ADJUSTMENT details)docs
export_informational_adjustment_detailsone row per adjustment_detail_id (non-balance-impacting)docs
export_batch_detailsone row per batch_id (accounting period)docs

Patients & Payers

TableGrainReference
export_patientone row per patient_id (current state; join to encounters on mrn = patient_external_id)docs
export_patient_insurance_historyone row per patient_insurance_history_pk (coverage version; is_latest_record for current)docs
export_patient_non_insurance_payer_historyone row per patient_non_insurance_payer_history_pk (patient version × non-insurance payer)docs
export_patient_note_historyone row per patient_note_history_pk (note version)docs
export_patient_appointmentsone row per appointment_id (includes deactivated)docs
export_patient_referralsone row per referral_iddocs
export_patient_authorizationsone row per authorization_iddocs
export_patient_mergeone row per patient_merge_id (MRN mapping)docs
export_payerone row per payer_uuid (reference)docs

A minimal, grain-correct example

Current balance per service line — starts from the service line and sums every live ledger row (charges, payments, adjustments, balance transfers) against it:

SELECT
sl.service_line_id,
sl.procedure_code,
SUM(t.amount_cents) AS balance_cents
FROM export_service_line sl
LEFT JOIN export_transaction t
ON t.service_line_id = sl.service_line_id
AND t.voids_transaction_id IS NULL
AND t.voided_by_transaction_id IS NULL
GROUP BY 1, 2
  • The void filter sits in the ON clause so service lines with no live transactions still return a row. Their balance is NULL, which distinguishes them from settled service lines (balance 0).
  • Add t.counter_party_type to the SELECT and GROUP BY to split the balance by who owes it (PAYER, PATIENT, or THIRD_PARTY_PAYER). Balance transfers move amounts between counterparties and net to zero across them.
  • Transactions posted at the claim level (target_type = 'CLAIM' — mostly payments and balance transfers) have no service_line_id or charge_id, so they don’t appear here. Roll up by encounter_id to include them.