Skip to the page
Chapters

Guides

Attachments

Send X-rays, charts and narratives a payer needs to pay a claim: upload JPEG or PNG images to an attachment, close it to get its number, put it on the claim, and answer a payer's request for more.

Many dental claims are paid only when the payer can see an X-ray, a perio chart or a narrative. An attachment holds those: you upload the images once, Claim House sends them through the dental attachment network, and the network gives the attachment a number. A claim that carries the attachment writes that number into its 837D in the two places payers look, so the payer finds the images. When a payer later asks for more about a claim it already has, you answer with a second attachment that carries the payer's reference number.

With a test key, attachments go to the sandbox attachment network, which answers at once. Live attachments are not open yet: a live key gets 503 ATTACHMENTS_UNAVAILABLE. A key needs submit permission to make, fill or close an attachment and read permission to read one; a key with submit only works with the attachments it made.

How it works#

  1. Create an attachment (POST /attachments) for a claim, or on its own with an office, a payer that takes attachments, the patient, the insured and the dates of service. It starts open.
  2. Upload its documents (POST /attachments/{id}/documents), one JPEG or PNG image each, as multipart/form-data.
  3. Close it (POST /attachments/{id}/close). Claim House registers the office with the network if it is not yet, sends the record and each document, and closes it. The answer has the attachment's number and what a claim file carries for it. Nothing changes after closing.
  4. Put it on the claim with the claim's attachments field, then send the claim. Its 837D carries the attachment.

An open attachment you no longer want (the wrong office or patient, or a payer that stopped taking attachments) is discarded with DELETE /attachments/{id}: it goes with its images, a payer request it was answering can be answered again, and the claim it was made for notes it on its timeline. A closed attachment stays; take an attachment off its claim before you discard it.

Limits and files#

LimitValue
Documents in an attachment127
Size of an attachment (all its images)15 MB
Narrative2,000 characters
A payer's reference number30 characters
Attachments on a claim5

JPEG or PNG. The network takes JPEG images, nothing else. Claim House takes a JPEG as it is and converts a PNG to a JPEG when it is uploaded: transparency is put on white, and the document says converted_from: "png" (its file_name stays the name you sent; its size and md5 are those of the JPEG). A PNG's header is checked before the image is decoded. A PNG may have sides of at most 20,000 pixels and at most 20 megapixels in all (160 MB once decoded), or 4 megapixels if it is interlaced, and may not be animated. Save a larger one as a JPEG (or an interlaced one as a non-interlaced PNG). A PNG whose JPEG would be over 15 MB is refused. Claim House converts one PNG at a time on each server: one that has to wait too long is answered 429 (send it again in a moment, with a new Idempotency-Key, since the first answer is kept for its key). PDF is not accepted: export the page as an image (JPEG or PNG) and upload that. A GIF or any other file is refused too, with 422 and the finding on file. A file is judged by its bytes, never by its name or the type the sender gave: a file named .jpg that is not a whole JPEG or PNG is refused. The same PNG uploaded twice converts to the same JPEG, so it is found as the document the attachment already has (while Claim House's image converter stays the same version: after an upgrade the same PNG may convert to other bytes, and uploading it again to an open attachment adds a second document).

Metadata is removed. Before an image is stored, Claim House rewrites it with only what the image needs: EXIF data (with GPS and device details), the EXIF orientation flag, embedded thumbnails, XMP, color profiles, comments and anything after the image are dropped (a PNG's text chunks are not carried into its JPEG either). The size and md5 of a document are those of the image as stored and sent. Because the orientation flag is removed, rotate a photo before you upload it. The segments an image needs (quantization tables, which come before the first scan, Huffman tables, restart interval, frame and scan headers, the JFIF and Adobe headers) are checked against what an image may hold and written again; an image whose segments break those rules is refused as damaged (as is one of more than 64 scans). The values of the tables and the compressed image data are kept as they are: they cannot be cleaned without re-encoding the image. Treat a stored image only as an image.

The name a file is sent with is kept for display only (file_name, without path parts or control characters); the stored image is named by the document's ID, and a name never appears in a URL.

An upload's body may be up to 15 MB, and 64 KiB more for the form's own parts (its own limit: not the 1 MB of other requests). A body that declares a larger size is refused with 413 PAYLOAD_TOO_LARGE before it is read; one sent without a length is read up to the limit, then refused the same way.

Uploads are safe to repeat. The same image uploaded again to an attachment, as a retry with the same Idempotency-Key or as a new request, is answered with the document the attachment has already: an attachment never holds one image twice, and the payer never gets a copy. A retry with the same key and the same file and fields is answered as the first was (Idempotent-Replayed: true), whatever boundary the form was sent with. If a request timed out (504 TIMEOUT), find what it made with GET /attachments?idempotency_key= (or ?request_id= with the request's x-request-id) before you send it again.

Document types#

Each document has a type. An X-ray or a photo (film) also needs the date the image was taken (image_date) and its orientation (left or right). GET /attachments/document_types lists them:

document_typeWhat it isKindNeeds image_date and orientation
periapical_xrayPeriapical X-rayfilmyes
bitewing_xrayBitewing X-rayfilmyes
panoramic_xrayPanoramic X-rayfilmyes
full_mouth_seriesFull-mouth seriesfilmyes
intraoral_photoIntraoral photofilmyes
perio_chartPerio chartpaperno
narrativeNarrativepaperno
eob_primary_payerEOB from the primary payerpaperno
otherOtherpaperno

Send an attachment#

The payer must take attachments. Find one in the directory:

Shell
curl "https://sandbox.myclaimhouse.com/api/v1/payers?supports=attachments&limit=1" \
  -H "Authorization: Bearer $CLAIMHOUSE_KEY"

An attachment is usually for a claim. Here is one to attach to: a draft ("submit": false) for that payer, with a rendering provider as in Claims:

Shell
curl "https://sandbox.myclaimhouse.com/api/v1/providers" \
  -H "Authorization: Bearer $CLAIMHOUSE_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "first_name": "Jordan",
  "last_name": "Example",
  "credential": "DDS",
  "npi": "1999990025",
  "license": { "number": "GA-000001", "state": "GA" }
}
EOF
Shell
curl "https://sandbox.myclaimhouse.com/api/v1/claims" \
  -H "Authorization: Bearer $CLAIMHOUSE_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "office_id": "$OFFICE_ID",
  "payer_id": "$ATTACHMENT_PAYER_ID",
  "rendering_provider_id": "$ATTACHMENT_PROVIDER_ID",
  "subscriber": {
    "first_name": "Sam",
    "last_name": "Sample",
    "date_of_birth": "1980-02-02",
    "gender": "F",
    "member_id": "CH-ACTIVE-FULL",
    "address": { "line1": "1 Sample Street", "city": "Sampleville", "state": "GA", "postal_code": "30301" }
  },
  "lines": [{ "cdt": "D2740", "fee": 1140.00, "service_date": "2026-09-24", "tooth": "3" }],
  "submit": false
}
EOF

Create the attachment for the claim: its office, payer, patient and dates of service are taken from the claim.

Shell
curl "https://sandbox.myclaimhouse.com/api/v1/attachments" \
  -H "Authorization: Bearer $CLAIMHOUSE_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "claim_id": "$CLAIM_ID",
  "narrative": "Fractured distal cusp on tooth 3, shown on the bitewing."
}
EOF

Upload an X-ray, with its type, date and orientation:

Shell
curl -X POST "https://sandbox.myclaimhouse.com/api/v1/attachments/$ATTACHMENT_ID/documents" \
  -H "Authorization: Bearer $CLAIMHOUSE_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F "[email protected];type=image/jpeg" \
  -F "document_type=bitewing_xray" \
  -F "image_date=2026-09-20" \
  -F "orientation=right"

Then close it:

Shell
curl "https://sandbox.myclaimhouse.com/api/v1/attachments/$ATTACHMENT_ID/close" \
  -H "Authorization: Bearer $CLAIMHOUSE_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{}'

The attachment comes back closed, with its number and, in claim_file, what a claim carrying it writes:

JSON
{
  "id": "att_...",
  "object": "attachment",
  "state": "closed",
  "kind": "unsolicited",
  "documents": [{ "id": "doc_...", "document_type": "bitewing_xray", "medium": "film", "image_date": "2026-09-20", "orientation": "right", "file_name": "bitewing.jpg", "size": 1200, "sent_to_network": true }],
  "attachment_number": "100001042",
  "claim_file": { "pwk": "NEA100001042", "nte": "NEA#100001042" },
  "closed_at": "..."
}

Then put it on the claim, and send the claim when it is ready:

Shell
curl -X PATCH "https://sandbox.myclaimhouse.com/api/v1/claims/$CLAIM_ID" \
  -H "Authorization: Bearer $CLAIMHOUSE_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d "{ \"attachments\": [\"$ATTACHMENT_ID\"] }"

Closing is safe to repeat: a closed attachment is returned as it is, with the same number. If the network does not finish (502 ATTACHMENTS_NETWORK_ERROR), nothing is lost: the attachment stays open with what was sent, and closing it again continues from there. While one close is running, another answers 409 CONFLICT. Once sending has begun, the attachment's documents are fixed: none can be added or removed until it is closed. An upload that never finished (its image never arrived) is removed after 15 minutes.

To show an image, ask for a link: GET /attachments/{id}/documents/{document_id}/url gives one that works for 60 seconds. Ask again each time it is shown; do not store, log or share it. Images are readable only by your organization.

On a claim#

Put a closed attachment on a claim with the claim's attachments field, when you create it (POST /claims) or by correcting it (PATCH /claims/{id}), as above. The list you send replaces the claim's; the dashboard's Add and Remove change one attachment at a time.

An attachment on a claim must be of your organization and mode, for the claim's payer, unsolicited, and on no other claim; one that is not is refused with 422, naming it (ATTACHMENT_NOT_FOUND, ATTACHMENT_NOT_USABLE). The list is the claim's content: changing it is an edit (on the claim's timeline, one entry for each attachment added or taken off), and the claim is validated again.

Which claims take attachments. The same claims whose content can change: a draft, a validated claim not yet queued, one that needs_attention, and a rejected one being corrected. A validated claim whose attachments change is validated again at once, so a claim that validated with ATTACHMENT_RECOMMENDED can still take the X-ray before it is queued. Once a claim is queued or sent its attachments are fixed, and making an attachment for it (POST /attachments with its claim_id) is refused with 409 CONFLICT. The payer reviews one attachment per claim: put every document the payer needs for a claim in one attachment.

Validation adds:

  • ATTACHMENT_OPEN (error) for an attachment on the claim that is not closed yet: close it, then send the claim again.
  • ATTACHMENT_REQUIRED (error) when the payer needs an attachment and the claim has no closed one: "The payer needs an attachment for this claim before it is sent. Close an attachment with the X-rays or documents it asks for and put it on the claim."
  • ATTACHMENT_RECOMMENDED (warning) for a claim with none, when it has a procedure payers commonly ask to see before they pay:
CodesProcedures
D2710 to D2799crowns
D4341 to D4342scaling and root planing
D6010 to D6199implants
D6200 to D6999bridges
D7210 to D7250surgical extractions
  • REMARKS_NAME_ATTACHMENT (error) when the remarks start with NEA# and the number of an attachment made through Claim House that is not on this claim: "The remarks start with the number of a Claim House attachment that is not on this claim. Put the attachment on the claim instead of typing its number." The number is read as the claim file writes it (a leading delimiter, an invisible character or full-width letters change nothing; leading zeros are ignored), and checked again when the claim is queued and when its file is built: a number issued after the claim was queued sends it back to needs attention. A number made elsewhere (typed by the office) is sent as typed.

Claim House checks again when the claim is queued and when its file is written: a claim goes out only with attachments that are closed and its own.

Corrections and voids. A correction is the same claim: it keeps its attachments, and its replacement file carries them again. A void transaction carries no attachment and its file has no PWK. When a claim is voided its attachments are taken off it (an entry on its timeline for each), so they can go on the claim you enter in its place, even one made for the voided claim. An attachment's record at the network is made with the patient of the claim it is on when it is closed (else the claim it was made for, else the patient you give it), and the attachment is then added only to a claim of that patient: the same date of birth and family name, or it is refused ("This attachment was sent with another patient’s details, so it cannot go on this claim: make a new attachment for this claim."). Correcting the patient of a claim that already carries the attachment is not refused: the claim is saved, and validation warns ATTACHMENT_PATIENT_DIFFERS (the attachment was sent with the earlier details; if the payer cannot match it, take it off the claim and make a new attachment). One made for a voided claim and still open names no patient until it is on another claim or you give it one (PATCH /attachments/{id} with patient, subscriber and service_dates); one whose sending began before its claim was voided cannot be finished: discard it and make a new one.

What the claim file carries#

For each attachment, in the order of attachments, loop 2300 of the claim's 837D carries a PWK segment and a note (NTE), as the attachment network's rules ask:

Text
CLM*CH4Q7M2K9TRB*1140***11:B:1*Y*A*Y*Y~
PWK*OZ*EL***AC*NEA100001042~
NTE*ADD*NEA#100001042~
NTE*ADD*Remarks follow, as before.~

The notes and the remarks share the 5 notes a claim carries, which is why a claim takes at most 5 attachments: remarks that fit alone but not with the attachments' notes are a TOO_LONG finding on attachments that says the notes are shared. See Claims and the claim's 837D (GET /claims/{id}/x12).

An attachment for no claim#

An attachment can also be made on its own, with an office and a payer, and put on a claim later. The attachment network's record names the patient, the insured and the dates of service, so an attachment made for no claim carries them; one without them is refused, each missing field named (patient.first_name, subscriber.member_id, service_dates.from, ...):

Shell
curl "https://sandbox.myclaimhouse.com/api/v1/attachments" \
  -H "Authorization: Bearer $CLAIMHOUSE_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "office_id": "$OFFICE_ID",
  "payer_id": "$ATTACHMENT_PAYER_ID",
  "patient": { "first_name": "Sam", "last_name": "Sample", "date_of_birth": "1980-02-02" },
  "subscriber": { "first_name": "Sam", "last_name": "Sample", "member_id": "CH-ACTIVE-FULL", "relationship": "self" },
  "service_dates": { "from": "2026-09-24", "to": "2026-09-24" }
}
EOF

Payer requests#

A payer that has a claim may ask for more: an X-ray, a chart, a narrative. A payer request has the payer's reference number, what it asks for, and when it is due. GET /payer_requests lists them (filter by state or claim_id); each arrives with the event payer_request.received and an entry on the claim's timeline. A request that came by letter can be recorded by hand (POST /payer_requests).

JSON
{
  "id": "prq_...",
  "object": "payer_request",
  "state": "open",
  "source": "network",
  "claim_id": "clm_...",
  "reference_number": "PRQ000001042",
  "requested": "A narrative of the treatment and a current periapical X-ray of the tooth treated.",
  "due_date": "2026-10-25"
}

Answer it with POST /payer_requests/{id}/answer. To send new images, first make a solicited attachment for the request (POST /attachments with "kind": "solicited" and payer_request_id), upload them, then answer naming it (attachment_id); to answer in words, send narrative and Claim House makes the attachment. The answering attachment carries the payer's reference number and is sent through the network: about the claim's earlier attachment when it has one, else as a record of its own. The request is then answered, with an entry on the claim's timeline. Nothing is added to the claim file: a payer finds an answer by its reference number.

Offices#

Each office registers once with the attachment network before its first attachment. Closing an attachment registers its office when it is not yet; POST /offices/{id}/register_attachments does it on its own. Registration needs the office's contact name and email, its primary doctor's name, and its address, phone and tax ID (edit the office in the dashboard). The office object shows its registration in attachment_network.

In the sandbox#

Member IDWhat happens
CH-ATTACH-REQUIREDThe claim fails validation with ATTACHMENT_REQUIRED until a closed attachment is on it; then it is sent and accepted.
CH-SOLICITEDThe payer accepts the claim, then sends a payer request 1 minute later.

Events and billing#

attachment.completed is sent when an attachment closes, and payer_request.received when a payer request arrives; both carry IDs and states, never a file name, a narrative or a patient's details. See Events and webhooks. A closed attachment is one usage unit: test_mode (never billed) with a test key.