Skip to main content

eFax Integration

Medplum provides a first-party integration with eFax Corporate to send and receive faxes directly from your healthcare application. Faxes are stored as FHIR Communication resources, enabling seamless integration with your clinical workflows.

Medplum Team Setup Required

This integration requires setup by the Medplum team. Contact us to enable eFax for your project.

Planning this integration?

The Messaging & Communications Decision Guide walks through requirements questions and FHIR modeling decisions for messaging — thread structure, routing, and external channels — use it alongside these docs.

Overview

The eFax integration allows you to:

  • Send faxes from FHIR Communication resources via the $send-efax operation
  • Receive faxes and store them as Communication resources via the $receive-efax operation
  • Sync outbound delivery status from eFax onto those Communication resources via the $sync-efax-status operation
  • Test connectivity to verify your eFax API credentials via the connection-test bot

Prerequisites

Before using the eFax integration, you must have:

  • The eFax integration enabled on your Medplum project (contact the Medplum team)
  • eFax API credentials configured as project secrets

Configuration

Project Secrets

The following secrets must be configured in your Medplum project:

Secret NameDescription
eFaxAppIdeFax application ID for the group (authenticates API requests)
eFaxApiKeyeFax API key for the group (authenticates API requests)
eFaxUserIdDefault eFax user ID for system-level operations

FHIR Operations

$receive-efax - Receive Faxes

Poll for and receive faxes from eFax, creating Communication resources for each new fax. Depending on how you configure your eFax account, you can call this operation on the system level, on an Organization level, or on a Practitioner level.

For the simplest setup, if you only need one fax number, we recommend calling /fhir/R4/Communication/$receive-efax to start.

EndpointUse CaseUser ID Source
POST /fhir/R4/Communication/$receive-efaxClinic-wide shared faxProject secret eFaxUserId
POST /fhir/R4/Organization/{id}/$receive-efaxDepartment/location faxOrganization's eFax identifier
POST /fhir/R4/Practitioner/{id}/$receive-efaxIndividual practitioner faxPractitioner's eFax identifier

Resource Configuration

For practitioners or organizations to send/receive faxes, add their eFax user ID as an identifier:

{
"resourceType": "Practitioner",
"identifier": [
{
"system": "https://efax.com",
"value": "<EFAX_USER_ID>"
}
],
"telecom": [
{
"system": "fax",
"value": "+15551234567"
}
]
}

$send-efax - Send a Fax

Send a fax from a Communication resource.

EndpointDescription
POST /fhir/R4/Communication/$send-efaxSend a fax from a Communication resource

Request Body: A Communication resource with:

  • medium containing code FAXWRIT from system http://terminology.hl7.org/CodeSystem/v3-ParticipationMode
  • payload with either a contentReference to a DocumentReference (recommended) or an inline contentAttachment containing the document to fax (PDF, JPEG, or PNG)
  • sender reference to a Practitioner or Organization. If that resource has identifier[system=https://efax.com], that user ID is used; otherwise the project secret eFaxUserId is used
  • recipient reference(s) to resources with fax numbers in their telecom

Recipient fax numbers must be in E.164 format: a leading + followed by the country calling code and the subscriber number (for example, +1 for US/Canada, then the number: +15551234567). eFax requires this country code; a local number without it may fail or route incorrectly.

When sending a fax, you need to create multiple FHIR resources:

  1. Binary: The document to fax (PDF, image) - created via medplum.createAttachment()
  2. DocumentReference: Tracks the uploaded document in the chart, wrapping the attachment
  3. Organization: The recipient with fax number
  4. Communication: Links the document and recipient together

Example: Sending a Fax

import { createReference } from '@medplum/core';
import type { Communication, DocumentReference, Organization, Practitioner } from '@medplum/fhirtypes';

// Assuming you have a MedplumClient instance and the sender's Practitioner profile
const profile = (await medplum.getProfile()) as Practitioner;

// Step 1: Upload the file and persist it as a DocumentReference (creates a Binary resource)
// so the faxed document is tracked in the chart, not just embedded on the Communication.
const attachment = await medplum.createAttachment({
data: file, // File object from input
contentType: file.type,
filename: file.name,
});
const documentReference = await medplum.createResource<DocumentReference>({
resourceType: 'DocumentReference',
status: 'current',
author: [createReference(profile)],
date: new Date().toISOString(),
content: [{ attachment }],
});

// Step 2: Create the recipient Organization (fax value must be E.164: + and country code)
const recipient = await medplum.createResource<Organization>({
resourceType: 'Organization',
name: 'Acme Medical Center',
contact: [{ telecom: [{ system: 'fax', value: '+15551234567' }] }],
});

// Step 3: Create the Communication with proper references
const communication = await medplum.createResource<Communication>({
resourceType: 'Communication',
status: 'in-progress',
category: [{ coding: [{ system: 'http://medplum.com/fhir/CodeSystem/fax-direction', code: 'outbound' }] }],
medium: [
{
coding: [
{
system: 'http://terminology.hl7.org/CodeSystem/v3-ParticipationMode',
code: 'FAXWRIT',
},
],
},
],
sender: createReference(profile),
recipient: [createReference(recipient)],
// Reference the DocumentReference via `contentReference`. The operation also accepts
// an inline `contentAttachment` (e.g. `payload: [{ contentAttachment: attachment }]`).
payload: [{ contentReference: createReference(documentReference) }],
});

// Step 4: Call the $send-efax operation
await medplum.post(medplum.fhirUrl('Communication', '$send-efax'), communication);

console.log('Fax submitted. Communication stays in-progress until $sync-efax-status runs.');

$send-efax submits the fax to eFax. On success it stores the eFax fax_id on Communication.identifier (system https://efax.com) and leaves status as in-progress. It does not wait for delivery. See Outbound fax status below.

The recipient Organization (or Practitioner, RelatedPerson, etc.) must store the destination fax in telecom using E.164 (country code required), for example:

{
"resourceType": "Organization",
"name": "Acme Medical Center",
"contact": [
{
"telecom": [
{
"system": "fax",
"value": "+15551234567"
}
]
}
]
}

$sync-efax-status - Sync outbound delivery status

Poll eFax for outbound transmission status and update matching Communication resources.

eFax delivery is not pushed into Medplum in real time. After $send-efax, you must either invoke $sync-efax-status or schedule the sync bot (cron on a bot in your project) so Communications move from in-progress to a terminal status.

EndpointDescriptionRequest body
POST /fhir/R4/$sync-efax-statusPoll eFax outbound notifications and patch CommunicationsOptional FHIR Parameters with period (start / end)

Example request body (optional time window):

{
"resourceType": "Parameters",
"parameter": [
{
"name": "period",
"valuePeriod": {
"start": "2026-01-01T00:00:00Z",
"end": "2026-01-31T23:59:59Z"
}
}
]
}

The operation returns an OperationOutcome. A JSON summary of updated / skipped / failed fax IDs is on extension https://efax.com/sync-status-outcome.

Skipped reasons:

ReasonMeaning
communication_not_foundNo Communication with identifier `https://efax.com
unknown_efax_userThe notification's eFax user_id is not the project eFaxUserId and not on any Practitioner or Organization https://efax.com identifier

Outbound fax status

eFax transmission_statusCommunication.statusMeaning
NEWin-progressAccepted by eFax, not yet transmitting
INPROGRESSin-progressTransmitting
COMPLETEcompletedDelivered
ERRORstoppedFailed (see https://efax.com/fax-error)
CANCELEDnot-doneCanceled

Successful send also sets https://efax.com/fax-status to the raw eFax status when sync runs.

If the fax is delivered in the eFax portal but the Communication is still in-progress, invoke $sync-efax-status (or wait for cron). Seeing the fax on the eFax side does not update Medplum by itself.

Communication Resource Structure

The samples below show the Communication resource only. For outbound sends, the fax number used by eFax comes from the recipient resource’s telecom and must include the country code in E.164 form (e.g. +15551234567), as in the Organization recipient example above.

Outbound Fax (Sent)

{
"resourceType": "Communication",
"status": "in-progress",
"identifier": [
{
"system": "https://efax.com",
"value": "fax-12345"
}
],
"medium": [
{
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v3-ParticipationMode",
"code": "FAXWRIT",
"display": "telefax"
}
]
}
],
"sender": {
"reference": "Practitioner/sender-id"
},
"recipient": [
{
"reference": "Practitioner/recipient-id"
}
],
"sent": "2025-01-15T10:30:00Z",
"category": [
{
"coding": [
{
"system": "http://medplum.com/fhir/CodeSystem/fax-direction",
"code": "outbound"
}
]
}
],
"payload": [
{
"contentReference": {
"reference": "DocumentReference/document-id"
}
}
]
}

Inbound Fax (Received)

{
"resourceType": "Communication",
"status": "completed",
"identifier": [
{
"system": "https://efax.com",
"value": "fax-67890"
}
],
"medium": [
{
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v3-ParticipationMode",
"code": "FAXWRIT",
"display": "telefax"
}
]
}
],
"recipient": [
{
"reference": "Practitioner/recipient-id"
}
],
"sent": "2025-01-15T09:15:00Z",
"payload": [
{
"contentAttachment": {
"url": "Binary/received-fax-id",
"contentType": "application/pdf",
"title": "fax-67890.pdf"
}
}
],
"category": [
{
"coding": [
{
"system": "http://medplum.com/fhir/CodeSystem/fax-direction",
"code": "inbound"
}
]
}
]
}

Troubleshooting

Connection test succeeds, send or receive returns 403.
The connection test only exchanges App ID + API key for a token. Send and receive also send user-id. Confirm eFaxUserId and any https://efax.com identifier on the sender are the eFax portal user ID for a user in that same group, with API access (and send permission for outbound).

Communication stays in-progress after the fax is delivered.
Call POST /fhir/R4/$sync-efax-status. Check the outcome extension: COMPLETE should map to completed; INPROGRESS means eFax is not finished; communication_not_found / unknown_efax_user means the fax_id or user ID is not aligned.

Receive cannot find a user ID.
System-level $receive-efax requires project secret eFaxUserId. Type-level calls require identifier[system=https://efax.com] on that Organization or Practitioner.

Supported Document Types

The following content types are supported for sending faxes:

Content TypeExtension
application/pdf.pdf
image/jpeg.jpg, .jpeg
image/png.png

Example Application

See the medplum-efax-demo example for a complete React application demonstrating the eFax integration.