Skip to main content

Message Attachments

Communication.payload supports three content types. You can combine multiple entries in a single message.

Content TypeUse CaseExample
contentStringPlain text messages"The specimen has been received."
contentAttachmentFiles (images, PDFs, documents)Lab report PDF, wound photo
contentReferenceReferences to other FHIR resourcesLink to a DiagnosticReport or DocumentReference
note

If you use @medplum/react, ThreadChat uploads files with medplum.createDocumentReference() and adds payload[].contentReference pointing at that DocumentReference. The same FHIR pattern works from any client: create a DocumentReference, then reference it on the payload so each file is a first-class, searchable document (query by patient, type, and other document fields). The sections below focus on createAttachment() + contentAttachment, which attaches a file on the message without creating a separate DocumentReference resource.

Upload a file

To attach a file to a message, use medplum.createAttachment() to upload the file and get an Attachment object, then pass it to contentAttachment. The next section shows the full example. For more on binary uploads and the difference between createBinary() and createAttachment(), see Binary data.

Send a message with an attachment

Use medplum.createAttachment() to upload the file and get an Attachment, then pass it to payload[].contentAttachment. See Referencing a Binary in an Attachment for more detail.

const document = await medplum.createAttachment({
data: myFile,
filename: 'test.pdf',
contentType: 'application/pdf',
});

const communication = await medplum.createResource({
resourceType: 'Communication',
status: 'completed',
payload: [{ contentAttachment: document }],
});
note

If you already have a Binary resource (e.g. from createBinary()), use url: getReferenceString(binary) in the attachment. For new uploads in messages, we recommend createAttachment() so you get an Attachment object to pass directly to contentAttachment.

Send a message with both text and an attachment

Create the attachment with createAttachment() as above, then include multiple entries in the payload array (e.g. contentString plus contentAttachment):

const attachment = await medplum.createAttachment({
data: file,
filename: 'lab-report.pdf',
contentType: 'application/pdf',
});

const mixedMessage = await medplum.createResource({
resourceType: 'Communication',
status: 'in-progress',
partOf: [{ reference: `Communication/${threadHeader.id}` }],
topic: threadHeader.topic,
subject: threadHeader.subject,
sender: { reference: 'Practitioner/doctor-alice-smith' },
recipient: [{ reference: 'Practitioner/doctor-gregory-house' }],
payload: [{ contentString: 'Here are the lab results we discussed.' }, { contentAttachment: attachment }],
sent: new Date().toISOString(),
});
caution

contentAttachment stores metadata and a URL reference — not the file bytes themselves. The binary lives as a separate Binary resource. If you delete the Binary, the attachment URL will return a 404.

In your UI

When rendering messages, iterate over the payload array and render each entry based on its type:

  • contentString — render as text
  • contentAttachment — render as a download link, inline image, or file preview based on contentType
  • contentReference — resolve the referenced resource and render appropriately; for a linked DocumentReference, render from content

For displaying or downloading attachment content (presigned URLs, media tags, and the download helper), see Consuming a FHIR Binary in an Application.

If using @medplum/react, the BaseChat component handles attachment rendering. For other frameworks, check contentType to decide how to display each attachment.

See Also