Skip to content

Insurance Payments Tracking

The Insurance Payments API provides centralized tracking of insurance payments, aggregating Electronic Remittance Advice (ERA) data from Claim.MD alongside manual payment entries.

Insurance payments come from two sources:

SourceDescriptionOperations
AutomaticCreated from ERA data ingestionRead-only (status updates only)
ManualUser-created entriesFull CRUD

Access to insurance payments requires the following permissions on the provider’s organization membership:

PermissionRequiredDescription
can_see_billingYesAllows viewing billing information
sees_all_billingYesAllows viewing billing across the entire organization

Requests from providers without these permissions will return an Unauthorized error.

type InsurancePayment {
id: ID!
organization_id: ID!
paid_date: ISO8601Date!
paid_amount: Float!
deposit_status: InsurancePaymentsDepositStatusEnum!
source: String!
payer_name: String!
npi: String
ach_check_number: String
era_id: ID
created_by_id: ID
created_at: ISO8601DateTime!
updated_at: ISO8601DateTime!
}
FieldDescription
paid_amountPayment amount as a decimal (e.g., 150.00)
paid_dateDate the payment was made
payer_nameName of the insurance payer
npiNational Provider Identifier (exactly 10 digits)
ach_check_numberCheck number or ACH identifier
deposit_statusStatus of the deposit, e.g. PENDING or DEPOSITED
sourceautomatic (ERA) or manual
era_idAssociated ERA record ID (automatic payments only)
created_by_idProvider who created the payment (manual payments only)
query insurancePayments(
$start_paid_date: ISO8601Date
$end_paid_date: ISO8601Date
$order_by: InsurancePaymentsOrderKeys
$keywords: String
$deposit_status: InsurancePaymentsDepositStatusEnum
$payer: String
$first: Int
$after: String
) {
insurancePayments(
start_paid_date: $start_paid_date
end_paid_date: $end_paid_date
order_by: $order_by
keywords: $keywords
deposit_status: $deposit_status
payer: $payer
first: $first
after: $after
) {
page_info {
has_next_page
end_cursor
}
total_count
nodes {
id
paid_date
paid_amount
payer_name
npi
ach_check_number
deposit_status
source
era_id
}
}
}
ArgumentTypeDescription
start_paid_dateISO8601DateFilter payments on or after this date
end_paid_dateISO8601DateFilter payments on or before this date
order_byInsurancePaymentsOrderKeysSort order (default: PAID_DATE_DESC)
keywordsStringSearch NPI, ACH check number, or payer name
deposit_statusInsurancePaymentsDepositStatusEnumFilter by PENDING or DEPOSITED
payerStringFilter by exact payer name
firstIntNumber of records to return (forward pagination)
afterStringCursor for fetching the next page of results
lastIntNumber of records to return (backward pagination)
beforeStringCursor for fetching the previous page of results

The order_by argument accepts:

OptionDescription
PAID_DATE_DESCPayment date, newest first (default)
PAID_DATE_ASCPayment date, oldest first
PAID_AMOUNT_DESCAmount, highest first
PAID_AMOUNT_ASCAmount, lowest first
PAYER_NAME_DESCPayer name, Z-A
PAYER_NAME_ASCPayer name, A-Z
NPI_DESCNPI, descending
NPI_ASCNPI, ascending
ACH_CHECK_NUMBER_DESCCheck/ACH number, descending
ACH_CHECK_NUMBER_ASCCheck/ACH number, ascending
SOURCE_DESCSource, descending
SOURCE_ASCSource, ascending
CREATED_AT_DESCCreated date, newest first
CREATED_AT_ASCCreated date, oldest first
UPDATED_AT_DESCUpdated date, newest first
UPDATED_AT_ASCUpdated date, oldest first

The insurancePayments query uses cursor-based pagination and returns an InsurancePaymentConnection type with the following structure:

FieldTypeDescription
nodes[InsurancePayment]Array of insurance payment records
page_infoPageInfoPagination metadata
page_info.has_next_pageBooleanWhether more results are available
page_info.end_cursorStringCursor for the next page
total_countIntTotal number of records matching the filters

To fetch the first 20 payments:

query {
insurancePayments(
first: 20
order_by: PAID_DATE_DESC
) {
page_info {
has_next_page
end_cursor
}
total_count
nodes {
id
paid_date
paid_amount
payer_name
deposit_status
}
}
}

Use the end_cursor from the previous response to fetch the next page:

query {
insurancePayments(
first: 20
after: "eyJpZCI6MTIzNDV9"
order_by: PAID_DATE_DESC
) {
page_info {
has_next_page
end_cursor
}
nodes {
id
paid_date
paid_amount
}
}
}

Continue fetching pages while has_next_page is true.

For more information, refer to the Connection-based Cursor Pagination

mutation createInsurancePayment(
$paid_date: ISO8601Date!
$npi: String!
$paid_amount: Float!
$deposit_status: InsurancePaymentsDepositStatusEnum!
$payer_name: String!
$ach_check_number: String
) {
createInsurancePayment(
input: {
paid_date: $paid_date
npi: $npi
paid_amount: $paid_amount
deposit_status: $deposit_status
payer_name: $payer_name
ach_check_number: $ach_check_number
}
) {
insurance_payment {
id
paid_amount
payer_name
source
}
messages {
field
message
}
}
}
InputRequiredDescription
paid_dateYesDate of the payment (YYYY-MM-DD)
npiYesNational Provider Identifier (exactly 10 digits)
paid_amountYesPayment amount (must be > 0)
deposit_statusYesPENDING or DEPOSITED
payer_nameYesInsurance payer name
ach_check_numberNoCheck or ACH identifier
{
"paid_date": "2024-01-20",
"npi": "1234567890",
"paid_amount": 150.00,
"deposit_status": "PENDING",
"payer_name": "Blue Cross Blue Shield",
"ach_check_number": "CHK-789012"
}

Use updateManualInsurancePayment to modify manual payments. This mutation cannot modify automatic (ERA) payments.

mutation updateManualInsurancePayment(
$payment_id: ID!
$paid_date: ISO8601Date
$npi: String
$ach_check_number: String
$paid_amount: Float
$deposit_status: InsurancePaymentsDepositStatusEnum
) {
updateManualInsurancePayment(
input: {
payment_id: $payment_id
paid_date: $paid_date
npi: $npi
ach_check_number: $ach_check_number
paid_amount: $paid_amount
deposit_status: $deposit_status
}
) {
insurance_payment {
id
paid_amount
deposit_status
updated_at
}
messages {
field
message
}
}
}

Use updateInsurancePaymentDepositStatus to change the deposit status of any payment, including automatic payments.

mutation updateInsurancePaymentDepositStatus(
$payment_id: ID!
$deposit_status: InsurancePaymentsDepositStatusEnum!
) {
updateInsurancePaymentDepositStatus(
input: {
payment_id: $payment_id
deposit_status: $deposit_status
}
) {
insurance_payment {
id
deposit_status
updated_at
}
messages {
field
message
}
}
}

Use deleteManualInsurancePayment to soft-delete a manual payment. Automatic payments cannot be deleted.

mutation deleteManualInsurancePayment($payment_id: ID!) {
deleteManualInsurancePayment(input: { payment_id: $payment_id }) {
insurance_payment {
id
}
messages {
field
message
}
}
}

Query pending payments within a date range to reconcile with bank deposits:

query {
insurancePayments(
start_paid_date: "2024-01-01"
end_paid_date: "2024-01-31"
deposit_status: PENDING
first: 50
) {
total_count
nodes {
id
paid_amount
paid_date
payer_name
ach_check_number
era_id
}
}
}

After reconciling with bank deposits, update the status:

mutation {
updateInsurancePaymentDepositStatus(
input: {
payment_id: "123"
deposit_status: DEPOSITED
}
) {
insurance_payment {
id
deposit_status
}
}
}
query {
insurancePayments(
keywords: "Blue Cross"
order_by: PAID_DATE_DESC
first: 20
) {
total_count
nodes {
id
paid_amount
paid_date
payer_name
npi
ach_check_number
source
deposit_status
}
}
}

Attempting to update or delete an automatic payment (or a non-existent payment) returns:

{
"data": {
"updateManualInsurancePayment": {
"insurance_payment": null,
"messages": [
{
"field": null,
"message": "Payment not found"
}
]
}
}
}

The system prevents duplicate ERA payments using the unique era_id constraint.