## On this page

When messages need responses — and those responses need to be tracked, assigned, and rerouted — use the FHIR [`Task`](/content/docs/api/fhir/resources/task/index.html) resource alongside [`Communication`](/content/docs/api/fhir/resources/communication/index.html). This separates message content ( [`Communication`](/content/docs/api/fhir/resources/communication/index.html)) from the routing and assignment lifecycle ( [`Task`](/content/docs/api/fhir/resources/task/index.html)), allowing you to reassign work without modifying conversation data.

### Assignment model

Do you need to assign work to named individuals only, to a pool by provider type, or both? That choice drives whether you use `owner`, `performerType`, or both.

### Key concept

[`Task`](/content/docs/api/fhir/resources/task/index.html) is the authoritative source for routing and assignment. `Communication.recipient` is informational — it reflects who should see the thread (for access policy scoping and display), but if there's ever a conflict between `Task.owner` and `Communication.recipient`, the [`Task`](/content/docs/api/fhir/resources/task/index.html) is the source of truth. When rerouting, always update the [`Task`](/content/docs/api/fhir/resources/task/index.html) first, then update `Communication.recipient` to match.

## Communication + Task Relationship

### Focus for Task

- **Task**

Respond to Homer Simpson's lab question

### Thread Header

- Homer Simpson April 10th lab tests

### Patient

- Homer Simpson

## Task Element Reference

| Element   | What It Does |
|-----------|---------------|
| `focus`   | Links the [`Task`](/content/docs/api/fhir/resources/task/index.html) to the [`Communication`](/content/docs/api/fhir/resources/communication/index.html) thread header it's tracking |
| `for`     | The patient this Task is about (mirrors `Communication.subject`) |
| `owner`   | Who is currently responsible — a [`Practitioner`](/content/docs/api/fhir/resources/practitioner/index.html) (individual). Cleared when rerouting to a pool. |
| `performerType` | The type of provider who should handle this Task (e.g. "Health coach"). Used for pool-based routing — providers whose `PractitionerRole.code` matches can claim the Task. |
| `requester` | Who created or triggered the Task |
| `status` | Task lifecycle: `requested` → `accepted` → `completed` (or `cancelled`) |
| `businessStatus` | Custom status for your workflow (e.g. `unassigned`, `claimed`, `escalated`) |
| `priority` | Urgency level: `routine`, `urgent`, `asap`, `stat` |
| `output` | References the response Communication that resolved the Task |

## Create a Task for a Thread

When to create a Task

Does this message require a tracked response? If not, keep it as Communication only. Use `Communication.category` or a Bot to determine which messages need routing.

When a new message arrives that requires action, create a [`Task`](/content/docs/api/fhir/resources/task/index.html) linked to the thread via `focus`. Use `performerType` to route to a provider pool, or set `owner` directly for individual assignment.

```ts
const task = await medplum.createResource({

resourceType: 'Task',

status: 'requested',

intent: 'order',

priority: 'routine',

focus: { reference: `Communication/${threadHeader.id}` },

for: { reference: 'Patient/homer-simpson', display: 'Homer Simpson' },

performerType: [
    {
      coding: [
        {
          system: 'http://snomed.info/sct',
          code: '224535009',
          display: 'Registered nurse',
        },
      ],
    },
  ],

requester: { reference: 'Practitioner/doctor-alice-smith' },

authoredOn: new Date().toISOString(),
});
```

## Claim a Task from the Pool

When a team member picks up the [`Task`](/content/docs/api/fhir/resources/task/index.html), update `status` to `accepted` and set `owner` to the specific [`Practitioner`](/content/docs/api/fhir/resources/practitioner/index.html):

```ts
await medplum.patchResource('Task', task.id, [
  { op: 'replace', path: '/status', value: 'accepted' },
  {
    op: 'replace',
    path: '/owner',
    value: { reference: 'Practitioner/doctor-gregory-house', display: 'Dr. Gregory House' },
  },
]);
```

## To see unclaimed Tasks in a pool, query by performerType:

- TypeScript

```ts
await medplum.search('Task', {
  performer: 'http://snomed.info/sct|224535009',
  status: 'requested',
});
```

- cURL

```bash
curl 'https://api.medplum.com/fhir/R4/Task?performer=http%3A%2F%2Fsnomed.info%2Fsct%7C224535009&status=requested' \
  -H 'authorization: Bearer $ACCESS_TOKEN' \
  -H 'content-type: application/fhir+json'
```

## Reroute to a Different Provider

Are you reassigning to one specific provider or back to a pool? Update `owner` and `Communication.recipient` for an individual; clear `owner`, set `performerType`, and clear `recipient` for a pool.

Update `Task.owner` and `Communication.recipient` to reassign the thread:

```ts
await medplum.patchResource('Task', task.id, [
  {
    op: 'replace',
    path: '/owner',
    value: { reference: 'Practitioner/dr-cardio', display: 'Dr. Cardio' },
  },
  {
    op: 'remove',
    path: '/performerType',
  },
]);

await medplum.patchResource('Communication', threadHeader.id, [
  { op: 'replace', path: '/recipient', value: [{ reference: 'Practitioner/dr-cardio', display: 'Dr. Cardio' }] },
]);
```

## Reroute to a Provider Pool

Clear `Task.owner`, set `Task.performerType` to the role type, and clear `Communication.recipient`. Providers whose `PractitionerRole.code` matches the `performerType` can see and claim the [`Task`](/content/docs/api/fhir/resources/task/index.html).

```ts
await medplum.patchResource('Task', task.id, [
  { op: 'remove', path: '/owner' },
  { op: 'replace', path: '/status', value: 'requested' },
  {
    op: 'add',
    path: '/performerType',
    value: [
      {
        coding: [
          {
            system: 'http://snomed.info/sct',
            code: '17561000',
            display: 'Cardiologist',
          },
        ],
      },
    ],
  },
]);

await medplum.patchResource('Communication', threadHeader.id, [{ op: 'remove', path: '/recipient' }]);
```

To find Tasks routed to a pool:

- TypeScript

```ts
await medplum.search('Task', {
  performer: 'http://snomed.info/sct|17561000',
  'owner:missing': true,
  _include: 'Task:focus',
});
```

- cURL

```bash
curl 'https://api.medplum.com/fhir/R4/Task?performer=http%3A%2F%2Fsnomed.info%2Fsct%7C17561000&owner:missing=true&_include=Task:focus' \
  -H 'authorization: Bearer $ACCESS_TOKEN' \
  -H 'content-type: application/fhir+json'
```

## Tracking Reroute History

Audit trail

Do you need an audit trail of who owned the Task and why it was rerouted? Version history gives who/when; add `Task.note` or `Provenance` for reasons.

When [`Task`](/content/docs/api/fhir/resources/task/index.html) resources are rerouted, you may need an audit trail of who owned them previously, when they were reassigned, and why. [`Task`](/content/docs/api/fhir/resources/task/index.html) version history (`meta.versionId`) automatically captures every state change, so the basic audit trail is always available via `medplum.readHistory('Task', task.id!)`. The question is how to capture the reason for the reroute.

### Free Text Reasons

Use `Task.note` to append a human-readable reason on each reroute. Notes are an array, so each reroute adds an entry with the author and timestamp:

```ts
await medplum.patchResource('Task', task.id, [
  {
    op: 'replace',
    path: '/owner',
    value: { reference: 'Practitioner/dr-cardio', display: 'Dr. Cardio' },
  },
  {
    op: 'add',
    path: '/note/-',
    value: {
      authorReference: { reference: 'Practitioner/doctor-gregory-house' },
      time: new Date().toISOString(),
      text: 'Rerouting to cardiology — patient has new cardiac symptoms',
    },
  },
]);
```

### Structured Reason Codes

If you need standardized, queryable reason codes, create a [`Provenance`](/content/docs/api/fhir/resources/provenance/index.html) resource alongside the [`Task`](/content/docs/api/fhir/resources/task/index.html) update. `Provenance.reason` accepts coded values:

```ts
await medplum.createResource({
  resourceType: 'Provenance',
  target: [{ reference: `Task/${task.id}` }],
  recorded: new Date().toISOString(),
  agent: [
    {
      who: { reference: 'Practitioner/doctor-gregory-house', display: 'Dr. Gregory House' },
    },
  ],
  reason: [
    {
      coding: [
        {
          system: 'https://medplum.com/CodeSystem/reroute-reason',
          code: 'specialty-referral',
          display: 'Specialty referral',
        },
      ],
    },
  ],
});
```

You can then query `Provenance?target=Task/{id}` to get the full reroute history with structured reasons.

### Reroute Visibility

After reroute, should the previous owner still see the Task (e.g. for reference), or only the new owner? That determines whether you update `Task.owner` in place or create a new Task for the new owner.

`Task.owner` is `0..1`, so it can only reference a single [`Practitioner`](/content/docs/api/fhir/resources/practitioner/index.html). When rerouting, you need to decide whether the original owner retains visibility.

#### Update Task in Place

If the original owner does not need to see the Task after reroute, update `Task.owner` directly. The original owner loses access (assuming access policies are scoped to `owner`):

```ts
await medplum.patchResource('Task', task.id, [
  { op: 'replace', path: '/owner', value: { reference: 'Practitioner/dr-cardio' } },
]);
```

#### Create a New Task for the New Owner

If the original owner does need to retain visibility, create a new [`Task`](/content/docs/api/fhir/resources/task/index.html) for the new owner and mark the original as rerouted. Both owners can see their respective [`Task`](/content/docs/api/fhir/resources/task/index.html) resources, and `Task.focus` links both to the same thread:

```ts
const newTask = await medplum.createResource({
  resourceType: 'Task',
  status: 'requested',
  intent: 'order',
  priority: task.priority,
  focus: task.focus,
  for: task.for,
  owner: { reference: 'Practitioner/dr-cardio', display: 'Dr. Cardio' },
  requester: { reference: 'Practitioner/doctor-gregory-house' },
  authoredOn: new Date().toISOString(),
  note: [
    {
      authorReference: { reference: 'Practitioner/doctor-gregory-house' },
      time: new Date().toISOString(),
      text: 'Rerouted from original Task — needs cardiology review',
    },
  ],
});

await medplum.patchResource('Task', task.id, [
  { op: 'replace', path: '/status', value: 'cancelled' },
  {
    op: 'add',
    path: '/note/-',
    value: {
      authorReference: { reference: 'Practitioner/doctor-gregory-house' },
      time: new Date().toISOString(),
      text: 'Rerouted to Dr. Cardio — see new Task',
    },
  },
]);
```
