Build

Follow the whole bill lifecycle

Submission is the beginning, not the end. MindBill normalizes acknowledgments, EORs, payments, denials, reviews, corrected replacements, and closure.

From submission to payment

1

Submitted

MindBill sends the claim through the selected electronic or manual route.

2

Acknowledged

999 and 277CA responses report whether the electronic transaction was structurally accepted. Acceptance is not payment.

3

Adjudicated

The claims administrator issues an EOR explaining allowed amounts, payments, reductions, or denials.

4

Resolved

Record payment, correct a rejection, request review of a disputed amount, or close the bill.

Read status and EORs

The status endpoint is suitable for a case header, receivables list, or background reconciliation job. The EOR endpoint returns normalized line items plus the original PDF when available.

server/read-lifecycle.ts
const { data: status } = await mindbill.getBillStatus(billId);
const { data: eor } = await mindbill.getBillEor(billId);

// Render status.state and status.balanceDue in your application.
// eor.lineItems and eor.documents contain payer response details.

The connected workspace combines that read model with native dialogs for every available action. The remittance surface distinguishes amount billed, payer allowed and reported paid amounts, principal posted to the bill, penalty and interest, total cash received, and remaining balance. Its payment ledger records partial payments, payment references, effective and deposit dates, and EOR source.

ConnectedBillLifecycleSynthetic data · edit and run
import {
  BillActivityTimeline,
  BillExplanationOfReview,
  BillLifecycleActions,
  BillLifecycleProgress,
  BillSnapshotSummary,
} from "@mindbill/react";

const review = {
  bill: {
    id: "bill_demo_1038", billNumber: 1038, status: "Submitted",
    billingMode: "med_legal", dos: "2026-08-26",
    billingSnapshot: {
      billingProvider: { name: "Northstar Evaluations", taxId: "12-3456789", npi: "1023401122", billType: "Professional", phone: "626-555-0194", billingStreet: "236 W Mountain St", billingCity: "Pasadena", billingState: "CA", billingZip: "91103" },
      renderingProvider: { name: "Dr. Morgan Chen", specialty: "Psychiatry", npi: "1023401122", taxonomy: "2084P0800X", licenseNumber: "A140748", licenseState: "CA", isQME: true },
      placeOfService: { name: "West Covina Exam Office", street: "1050 West Lakes Dr, Ste 225", city: "West Covina", state: "CA", zip: "91790", posCode: "11" },
    },
    lineItems: [{ id: "line_1", code: "ML201", modifiers: ["-95"], units: 1, charge: 2015, serviceDate: "2026-08-26" }],
    attachments: [
      { id: "doc_report", filename: "final-report.pdf", documentType: "final_report", description: "Final medical-legal report" },
      { id: "doc_pos", filename: "proof-of-service.pdf", documentType: "proof_of_service", description: "Proof of service" },
    ],
    totalCharge: 2015, totalPaid: 0, balanceDue: 2015,
  },
  patient: { name: "Alex Morgan", firstName: "Alex", lastName: "Morgan", dob: "1988-03-05" },
  injury: { claimNumber: "W8331838-0001", employer: "Northstar Foods", doi: "2025-05-30", adjNumber: "ADJ21439594", claimsAdminId: "payer_republic", claimsAdminName: "Republic Indemnity", claimPatternStatus: { state: "match", label: "Claim pattern matches Republic Indemnity" } },
};

const lifecycle = {
  ...review,
  bill: { ...review.bill, status: "Denied" },
  lifecycle: {
    state: "denied", nativeStatus: "Denied", submittedAt: "2026-07-27",
    agingDays: 29, updatedAt: "2026-08-25",
    actions: [
      { id: "view_eor", label: "View EOR", enabled: true },
      { id: "second_review", label: "Submit second review", enabled: true, primary: true },
      { id: "close", label: "Close bill", enabled: true },
    ],
  },
  eors: [{ id: "eor_1", filename: "EOR-1038.pdf", description: "Explanation of Review", addedAt: "2026-08-25", contentUrl: "#eor" }],
  activity: [
    { id: "evt_3", type: "bill.denied", createdAt: "2026-08-25T17:42:18Z", description: "Medical necessity or frequency" },
    { id: "evt_2", type: "eor.received", createdAt: "2026-08-25T17:41:02Z", description: "EOR-1038.pdf received" },
    { id: "evt_1", type: "bill.submitted", createdAt: "2026-07-27T16:08:00Z", actor: "Taylor R." },
  ],
  payments: [],
  remittance: {
    billedAmount: 2015, expectedAmount: 2015, payerAllowedAmount: 0,
    payerReportedPaid: 0, postedPrincipal: 0, postedAdditional: 0,
    totalPostedCash: 0, balanceDue: 2015,
    denialReason: "Medical necessity or frequency",
  },
  delivery: {
    payerName: "Republic Indemnity",
    contacts: {
      adjusterName: "Jordan Lee", adjusterPhone: "(213) 555-0188",
      adjusterEmail: "jordan.lee@example.test", faxNumber: "(213) 555-0199",
      mailingAddress: "PO Box 19600, Irvine, CA 92623",
    },
  },
};

export default function App() {
  return <main className="review-demo">
    <BillLifecycleProgress {...lifecycle.lifecycle} appearance={{ preset: "orange-bright" }} />
    <BillSnapshotSummary {...lifecycle} appearance={{ preset: "orange-bright" }} />
    <BillExplanationOfReview
      remittance={lifecycle.remittance}
      eors={lifecycle.eors}
      payments={lifecycle.payments}
      submittedAt={lifecycle.lifecycle.submittedAt}
      onOpenEor={(eor) => alert("Preview " + eor.filename)}
      appearance={{ preset: "orange-bright" }}
    />
    <BillLifecycleActions actions={lifecycle.lifecycle.actions} onAction={() => {}} appearance={{ preset: "orange-bright" }} />
    <BillActivityTimeline events={lifecycle.activity} appearance={{ preset: "orange-bright" }} />
  </main>;
}

Take the next action

Read lifecycle.actions instead of reproducing payer rules in your application. MindBill returns only the actions that make sense for the current bill and explains why an unavailable action is disabled.

Bill stateTypical next actions
rejectedSubmit a new corrected snapshot, or close.
accepted / processedTrack the response, or close.
denied / partially_paidView EOR, post payment, request Second Bill Review, or close.
second_reviewTrack SBR; request IBR when MindBill reports eligibility.
paid / closedRead EOR and history; no collection action remains.
BillLifecycleActionsSynthetic data · edit and run
import { useState } from "react";
import { BillLifecycleActions } from "@mindbill/react";

const actions = [
  { id: "view_eor", label: "View EOR", enabled: true },
  { id: "second_review", label: "Submit second review", enabled: true, primary: true },
  { id: "post_payment", label: "Post payment", enabled: false, reason: "No payable EOR line remains." },
  { id: "close", label: "Close bill", enabled: true },
];

export default function App() {
  const [message, setMessage] = useState("Choose an available action.");
  return <main className="demo">
    <h2>Denied · $2,015.00 due</h2>
    <p>{message}</p>
    <BillLifecycleActions
      actions={actions}
      showUnavailable
      appearance={{ preset: "orange-bright" }}
      onAction={(action) => setMessage(action.label + " selected")}
    />
  </main>;
}
server/bill-actions.ts
// Payment received after an EOR.
await mindbill.performBillAction(billId, {
  action: "post_payment",
  amount: 650,
  method: "eft",
  depositDate: "2026-09-04",
}, "payment-bill-123-1");

// Close a bill at any stage.
await mindbill.performBillAction(
  billId,
  { action: "close", reason: "Resolved outside billing" },
  "close-bill-123",
);
Correct a rejected bill

Use the resubmit action on the original bill. It preserves the logical bill ID and creates a new immutable submission attempt. Send the full corrected bill and the documents selected for that attempt; this is not a partial update or a new unrelated bill.

server/correct-bill.ts
// correctedBill is the full, reviewed bill payload.
const response = await fetch(
  `https://app.mindbill.org/partner/v2/bills/${billId}/actions`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.MINDBILL_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": "correct-bill-123-attempt-2",
    },
    body: JSON.stringify({
      action: "resubmit",
      actorName: authorizedUser.displayName,
      reason: "Corrected the rejected claim number",
      bill: correctedBill,
      documents: selectedBillingDocuments,
    }),
  },
);
if (!response.ok) throw new Error(`Correction failed: ${response.status}`);

This server-side example assumes your application has authenticated authorizedUser, checked their access to billId, and prepared the bill and document payloads. The action endpoint also accepts browser credentials. The connected lifecycle component provides the correction dialog for you.

Show bill history

The connected lifecycle response includes newest-first activity. BillActivityTimeline renders it directly, or accepts the same records from your own webhook-backed store.

In React 0.48.0 and later, submission cards open the selected submission's Bill details; Bill history remains a separate, explicit tab. Custom interfaces can read lifecycle.submissionDetails, matching both attemptId and billId. A submission_snapshot is the captured outgoing detail, bill_record is a labeled legacy fallback, and unavailable means no trustworthy detail exists. Do not replace missing historical data with today's bill or turn unrecorded historical payment amounts into zero.

BillActivityTimelineSynthetic data · edit and run
import { BillActivityTimeline } from "@mindbill/react";

const events = [
  { id: "evt_4", type: "bill.denied", createdAt: "2026-08-25T17:42:18Z", description: "Medical necessity or frequency" },
  { id: "evt_3", type: "eor.received", createdAt: "2026-08-25T17:41:02Z", description: "EOR-1038.pdf received" },
  { id: "evt_2", type: "bill.accepted", createdAt: "2026-08-13T09:16:00Z" },
  { id: "evt_1", type: "bill.submitted", createdAt: "2026-08-12T16:08:00Z", actor: "Taylor R." },
];

export default function App() {
  return <main className="demo">
    <BillActivityTimeline
      events={events}
      appearance={{ preset: "clinical-blue" }}
    />
  </main>;
}

When retained transmission files exist, each submission detail includes artifacts with opaque IDs, labels, kind, and content type. Keep the lifecycle client configured with the original bill ID and call client.getSubmissionArtifact(attemptId, artifactId) to receive a Blob. The connected component downloads the selected submission's exact electronic bill or attachments, not a packet regenerated from today's records. The equivalent server-key route is GET /partner/v2/bills/{billId}/submissions/{attemptId}/artifacts/{artifactId}, with bills:read.

Second Bill Review before IBR

California payment disputes generally begin with Second Bill Review. If the dispute remains eligible after SBR, the provider may proceed to Independent Bill Review. Medical-legal SBR uses the DWC SBR-1 process and supporting documents.

server/second-review.ts
const { data: secondReview } = await mindbill.createBillReview(
  billId,
  {
    type: "second_review",
    reason: "The report satisfies the medical-legal criteria.",
    payerClaimControlNumber: "PCCN-88421",
    disputedAmount: 2015,
    attachmentIds: [reportId, eorId],
  },
  "create-sbr-bill-123",
);

await mindbill.submitBillReview(
  billId,
  secondReview.id,
  "submit-sbr-bill-123",
);

The connected Second Review dialog can correct a selected service line's units, modifiers, and charge for the new submission. Review the charge explicitly: changing units or modifiers does not automatically reprice the bill. For a custom browser UI using @mindbill/browser 0.29.0 or later, submitSecondReview accepts lineItems[].correction with all three absolute values: units, modifiers, and charge. Omit the correction to preserve that line. This lifecycle-action payload differs from the review-record example above; both endpoints accept server or browser credentials.

Team notes and courtesy copies

ConnectedBillLifecycle includes team notes and Forward copy on the current bill. Notes are workspace-only and do not enter the outgoing bill packet. Historical submission views remain read-only. Server actions require bills:write; browser actions require an origin-bound session with bills:act and access to the bill.

The lifecycle response includes notes with id, body, author, createdAt, and pinned. The connected component renders these notes with their author and time by default. Read the canonical bill lifecycle when switching submission attempts, so notes remain part of the bill conversation rather than a host-only copy.

server/add-bill-note.ts
// authenticatedUser comes from your trusted host session.
await mindbill.performBillAction(billId, {
  action: "add_note",
  note: "Reviewed the corrected claim number with the billing team.",
  actorName: authenticatedUser.displayName,
}, "note-bill-123-review-1");
// Reuse the same key when retrying this same note. Reload lifecycle.notes.
// Without actorName the API uses the generic author "Partner team".

Forward copy previews a combined PDF containing the mandatory submission cover sheet, the optional CMS-1500, and selected bill documents. The user reviews recipients, message, and packet before confirming. MindBill uses the workspace inbox for sender and reply routing. Forwarding is for the recipient's records: it neither submits the claim nor changes its billing status.

Partners can supply their own case-contact options through the courtesyCopyRecipientOptions prop on ConnectedBillLifecycle, or the getCourtesyCopyRecipientOptions callback on ConnectedBillingWorkspace. These named email suggestions appear in the To/CC chooser; users can also enter an address manually. Suggestions do not grant permission to disclose the packet, trigger a send, or enroll contacts in automatic notifications.

Use events for durable synchronization

Component callbacks keep the current screen responsive. Signed webhooks should update your database in the background. Store the event ID before processing so a retry is harmless.

Verified console members can opt into their own status and aging emails in the developer console's Settings → Notifications. Preferences are separate for each workspace and environment; sandbox previews never send email. Opting in does not send historical catch-up messages. These notices contain no patient or bill details.

bill.denied.json
{
  "id": "evt_0189",
  "sequence": "4217",
  "type": "bill.denied",
  "apiVersion": "2026-08-01",
  "createdAt": "2026-08-25T17:42:18Z",
  "data": {
    "billId": "bill_123",
    "balanceDue": 2015,
    "reason": "Medical necessity or frequency"
  }
}