curl --request GET \
--url https://api.maxcare.ai/v3/bills \
--header 'Authorization: Bearer <token>' \
--header 'X-Organization-Id: <x-organization-id>'import requests
url = "https://api.maxcare.ai/v3/bills"
headers = {
"X-Organization-Id": "<x-organization-id>",
"Authorization": "Bearer <token>"
}
response = requests.get(url, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {'X-Organization-Id': '<x-organization-id>', Authorization: 'Bearer <token>'}
};
fetch('https://api.maxcare.ai/v3/bills', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.maxcare.ai/v3/bills",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"X-Organization-Id: <x-organization-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.maxcare.ai/v3/bills"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-Organization-Id", "<x-organization-id>")
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.maxcare.ai/v3/bills")
.header("X-Organization-Id", "<x-organization-id>")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.maxcare.ai/v3/bills")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-Organization-Id"] = '<x-organization-id>'
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"code": "success",
"data": {
"bills": [
{
"id": "bil_9a8b7c6d5e4f3a2b1c0de9f8a7b6c5d4",
"dateOfService": "2025-01-15",
"billingType": "professional",
"isCosmetic": false,
"isBillable": true,
"virtualEncounter": false,
"isEmCodingEnabled": true,
"patientId": "pat_c56103bcd39c46d39f3138dd2b5e05f6",
"patientFirstName": "Sarah",
"patientLastName": "Johnson",
"patientDob": "1985-03-15",
"primaryProviderName": "Dr. James Wilson",
"billUnderName": "Dr. James Wilson",
"facilityId": "fac_b2c3d4e5f6a74b8c9d0e1f2a3b4c5d6e",
"facilityName": "West LA Dermatology",
"specialty": "Dermatology",
"codingGroups": [
{
"id": "cgr_f6a7b8c9d0e14f2a3b4c5d6e7f8a9b0c",
"status": "finalized",
"createdAt": "2025-01-15T09:30:00.000Z",
"updatedAt": "2025-01-20T14:22:00.000Z",
"diagnoses": [
{
"id": "dgn_a7b8c9d0e1f24a3b4c5d6e7f8a9b0c1d",
"code": "L70.0",
"description": "Acne vulgaris",
"position": 1,
"codeRevision": "ICD-10-CM"
}
],
"lineItems": [
{
"id": "lit_b8c9d0e1f2a34b4c5d6e7f8a9b0c1d2e",
"code": "99213",
"codeType": "CPT",
"description": "Office/outpatient visit, est patient, low complexity",
"units": "1",
"charge": "150.00",
"totalCharge": "150.00",
"balance": "30.00",
"paidAmount": "142.35",
"allowedAmount": "180.00",
"modifiers": [
{
"code": "25",
"name": "Significant, Separately Identifiable E/M Service"
}
],
"position": 1,
"linkedDiagnoses": [
{
"code": "L70.0",
"description": "Acne vulgaris",
"position": 1
}
],
"ndcCode": "00069-3150-83",
"ndcQualifier": "N4",
"ndcQuantity": "1.0",
"ndcProcedureDescription": "<string>"
}
]
}
],
"primaryInsurance": "Blue Cross Blue Shield",
"secondaryInsurance": null,
"createdAt": "2025-01-15T09:30:00.000Z",
"updatedAt": "2025-01-20T14:22:00.000Z"
}
],
"pagination": {
"page": 1,
"pageSize": 100,
"totalCount": 250,
"totalPages": 3
}
}
}{
"code": "bad_request",
"message": "'id' must be a valid UUID",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}{
"code": "unauthorized",
"message": "Invalid or missing API key",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}{
"code": "forbidden",
"message": "Insufficient scope",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}{
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Maximum 1000 requests per 60 seconds.",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}List bills
Returns a paginated list of bills. Requires read:bills scope. pagination.totalCount and pagination.totalPages are populated by default; pass includeTotals=false to skip them, which avoids a second aggregate over the whole filtered set that is recomputed on every page of a walk. Opt out only if you do not use the count — see includeTotals.
curl --request GET \
--url https://api.maxcare.ai/v3/bills \
--header 'Authorization: Bearer <token>' \
--header 'X-Organization-Id: <x-organization-id>'import requests
url = "https://api.maxcare.ai/v3/bills"
headers = {
"X-Organization-Id": "<x-organization-id>",
"Authorization": "Bearer <token>"
}
response = requests.get(url, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {'X-Organization-Id': '<x-organization-id>', Authorization: 'Bearer <token>'}
};
fetch('https://api.maxcare.ai/v3/bills', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.maxcare.ai/v3/bills",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"X-Organization-Id: <x-organization-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.maxcare.ai/v3/bills"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-Organization-Id", "<x-organization-id>")
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.maxcare.ai/v3/bills")
.header("X-Organization-Id", "<x-organization-id>")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.maxcare.ai/v3/bills")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-Organization-Id"] = '<x-organization-id>'
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"code": "success",
"data": {
"bills": [
{
"id": "bil_9a8b7c6d5e4f3a2b1c0de9f8a7b6c5d4",
"dateOfService": "2025-01-15",
"billingType": "professional",
"isCosmetic": false,
"isBillable": true,
"virtualEncounter": false,
"isEmCodingEnabled": true,
"patientId": "pat_c56103bcd39c46d39f3138dd2b5e05f6",
"patientFirstName": "Sarah",
"patientLastName": "Johnson",
"patientDob": "1985-03-15",
"primaryProviderName": "Dr. James Wilson",
"billUnderName": "Dr. James Wilson",
"facilityId": "fac_b2c3d4e5f6a74b8c9d0e1f2a3b4c5d6e",
"facilityName": "West LA Dermatology",
"specialty": "Dermatology",
"codingGroups": [
{
"id": "cgr_f6a7b8c9d0e14f2a3b4c5d6e7f8a9b0c",
"status": "finalized",
"createdAt": "2025-01-15T09:30:00.000Z",
"updatedAt": "2025-01-20T14:22:00.000Z",
"diagnoses": [
{
"id": "dgn_a7b8c9d0e1f24a3b4c5d6e7f8a9b0c1d",
"code": "L70.0",
"description": "Acne vulgaris",
"position": 1,
"codeRevision": "ICD-10-CM"
}
],
"lineItems": [
{
"id": "lit_b8c9d0e1f2a34b4c5d6e7f8a9b0c1d2e",
"code": "99213",
"codeType": "CPT",
"description": "Office/outpatient visit, est patient, low complexity",
"units": "1",
"charge": "150.00",
"totalCharge": "150.00",
"balance": "30.00",
"paidAmount": "142.35",
"allowedAmount": "180.00",
"modifiers": [
{
"code": "25",
"name": "Significant, Separately Identifiable E/M Service"
}
],
"position": 1,
"linkedDiagnoses": [
{
"code": "L70.0",
"description": "Acne vulgaris",
"position": 1
}
],
"ndcCode": "00069-3150-83",
"ndcQualifier": "N4",
"ndcQuantity": "1.0",
"ndcProcedureDescription": "<string>"
}
]
}
],
"primaryInsurance": "Blue Cross Blue Shield",
"secondaryInsurance": null,
"createdAt": "2025-01-15T09:30:00.000Z",
"updatedAt": "2025-01-20T14:22:00.000Z"
}
],
"pagination": {
"page": 1,
"pageSize": 100,
"totalCount": 250,
"totalPages": 3
}
}
}{
"code": "bad_request",
"message": "'id' must be a valid UUID",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}{
"code": "unauthorized",
"message": "Invalid or missing API key",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}{
"code": "forbidden",
"message": "Insufficient scope",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}{
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Maximum 1000 requests per 60 seconds.",
"trace_id": "550e8400-e29b-41d4-a716-446655440000"
}Authorizations
Marketplace API key
Headers
Target clinic organization ID
Query Parameters
Filter from date (ISO 8601)
"2025-01-01"
Filter to date (ISO 8601)
"2025-12-31"
Filter by facility ID
Filter by patient ID
Filter by provider ID
Filter by integration status
Filter by billing type
Filter to bills containing a line item with any of these procedure codes (CPT/HCPCS, comma-separated). Exact match, case-insensitive on both the value you send and the code as stored — nothing normalizes a procedure code on write, so a case-sensitive match would answer ?code=j3245 with an empty page and a 200, which reads as 'this practice bills no J3245'. Same folding as /v4/claims and /v4/era-service-lines. Composable with dateFrom/dateTo for windowed cohort pulls. Supplying the parameter with NO values — ?code= or ?code=, — is a 400, not an empty filter: build the query string so an empty cohort OMITS the parameter, because silently dropping it would return every bill in the organization for a request that asked for a few.
"J3245,J0717,J2357"
Filter by workflow status (comma-separated). Values: synced, reviewed, posted. Bills in status 'new' (not yet synced) and archived bills are never returned by this API. Supplying the parameter with NO values — ?status= or ?status=, — is a 400, not an empty filter: omit the parameter when you have no statuses to filter on.
"posted"
Only return bills whose record was created or modified at/after this timestamp (ISO 8601). When set, results are ordered by updatedAt ascending. Page through to the end, then use the LAST row's updatedAt as the next cursor; do not advance the cursor mid-pagination. Rows sharing the boundary updatedAt re-deliver on the next pull, since the bound is inclusive — dedupe on id. Caveat: this endpoint is offset-paged, and ascending order alone does not make the walk safe. If a bill on an early page is re-synced while you are paging, it moves within (or out of) the result set, the rows after it shift one position toward the front, and the offset for your next page steps over one of them — with every page still coming back full, so there is no short page to warn you. Keep includeTotals on and treat a totalCount that shrinks between pages as a walk you must not trust, then re-read the window. (/patients, /insurance-policies and /appointments take a cursorId instead and have no offset to invalidate; the same is planned here.)
"2025-06-01T00:00:00.000Z"
Only return bills whose record was last modified at/before this timestamp (ISO 8601).
"2025-06-30T23:59:59.999Z"
Populate pagination.totalCount and pagination.totalPages. Defaults to true — this endpoint has shipped totals since v1 and some consumers use them as an exhaustiveness interlock before pruning local rows, so the default cannot change under them. Pass includeTotals=false to skip them: the totals need a second aggregate over the whole filtered set (not just the page) which re-runs identically on every page of a walk, and it is the dominant cost of this endpoint. With includeTotals=false both fields are null and you page until a short page instead.
true
