Bot $execute | Medplum

On this page

The $execute operation runs a Medplum Bot on-demand, allowing you to trigger server-side automation logic via API calls. Bots can process incoming data, integrate with external systems, and return custom responses-making this operation the primary way to leverage Medplum's automation capabilities.

Whether you're processing HL7v2 messages from legacy systems, responding to webhooks, or building custom API endpoints, $execute provides the flexibility to handle virtually any healthcare integration scenario.

Use Cases

Invoke a bot by ID

Invoke a bot by ID when you know the Bot's ID in advance.

Finding your Bot Id

You can find the id of your Bot by clicking on the Details tab of the Bot resource. In this example, it is 43ac3060-ff20-49e8-9682-bf91ab3a5191

Using POST

POST [base]/Bot/[id]/$execute

Examples

The MedplumClient TypeScript class provides a executeBot convenience method

const result = await medplum.executeBot(id, { input: { foo: 'bar' } }, ContentType.JSON);

console.log(result);
medplum login

medplum post 'Bot/[id]/$execute' '{ "foo": "bar" }'
curl 'https://api.medplum.com/fhir/R4/Bot/[id]/$execute' \

-X POST \

-H "Content-Type: application/json" \

-H "Authorization: Bearer $MY_ACCESS_TOKEN" \

-d '{"foo":"bar"}'

Using GET

Query parameters will be passed to the bot as type Record<string, string> (see Content Types below)

GET [base]/Bot/[id]/$execute?params
const getResult = await medplum.get(medplum.fhirUrl('Bot', id, '$execute').toString() + '?foo=bar');

console.log(getResult);
medplum login

medplum get 'Bot/[id]/$execute?foo=bar'
curl 'https://api.medplum.com/fhir/R4/Bot/[id]/$execute?foo=bar' \

-H "Authorization: Bearer $MY_ACCESS_TOKEN"

Invoke a bot by identifier

Sometimes you may not know the Medplum Bot ID in advance. In that case, you can invoke a Bot by Identifier.

This is also useful when the same conceptual bot exists in multiple Medplum projects. Each bot will have a different ID, but they can all have the same identifier.

Using POST

POST [base]/Bot/$execute?identifier=[system]|[code]

Examples

The MedplumClientexecuteBot convenience method supports both id: string and identifier: Identifier:

const result = await medplum.executeBot(

{

system: 'https://example.com/bots',

value: '1234',

},

{

foo: 'bar',

}
);

console.log(result);
medplum login

medplum post 'Bot/[id]/$execute?identifier=https://example.com/bots|1234' '{ "foo": "bar" }'
curl 'https://api.medplum.com/fhir/R4/Bot/$execute?identifier=https://example.com/bots|1234' \

-X POST \
  
  -H "Content-Type: application/json" \
  
  -H "Authorization: Bearer $MY_ACCESS_TOKEN" \
  
  -d '{"foo":"bar"}'

Using GET

GET [base]/Bot/$execute?identifier=[system]|[code]&params
const getResult = await medplum.get(

medplum.fhirUrl('Bot', '$execute').toString() + '?identifier=https://example.com/bots|1234&foo=bar'
);

console.log(getResult);
medplum login

medplum get 'Bot/$execute?identifier=https://example.com/bots|1234'
curl 'https://api.medplum.com/fhir/R4/Bot/$execute?identifier=https://example.com/bots|1234' \

-H "Authorization: Bearer $MY_ACCESS_TOKEN"

Content Types

Medplum Bots support a variety of input content types. Specify the input content type using the standard Content-Type HTTP header, or as an optional parameter to MedplumClient.executeBot().

Content-Type typeof event.input Description
text/plain string <INPUT_DATA> is parsed as plaintext string
application/json Record<string, any> <INPUT_DATA> is parsed as JSON-encoded object
application/x-www-form-urlencoded Record<string, string> <INPUT_DATA> is parsed as URL-encoded string, resulting in a key/value map
application/fhir+json Resource <INPUT_DATA> is parsed as a FHIR Resource encoded as JSON
x-application/hl7-v2+er7 HL7Message <INPUT_DATA> is a string that should be parsed as a pipe-delimited HL7v2 message. HL7v2 is a common text-based message protocol used in legacy healthcare systems

The input data that will be parsed according to CONTENT_TYPE and passed into your Bot as event.input.

Asynchronous Execution

To run bots asynchronously, you can specify the Prefer: respond-async header to move execution of the bot to the background. Asynchronous execution will result in an HTTP 202 Accepted response immediately, and the bot will continue running in the background.

Making an Async Request

Add the Prefer: respond-async header to any bot execution request:

const response = await medplum.executeBot('your-bot-id', { foo: 'bar' }, ContentType.JSON, {

headers: {

Prefer: 'respond-async',

},
});
medplum post 'Bot/[id]/$execute' '{ "foo": "bar" }' --prefer-async
curl 'https://api.medplum.com/fhir/R4/Bot/[id]/$execute' \

-X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $MY_ACCESS_TOKEN" \
  -H "Prefer: respond-async" \
  -d '{"foo":"bar"}'

Checking Job Status

When using async execution, the server returns a 202 Accepted response with a Content-Location header containing the URL to check the job status:

HTTP/1.1 202 Accepted

Content-Location: https://api.medplum.com/fhir/R4/job/[job-id]/status

You can poll this URL to check the status of your bot execution. In general, for long running jobs it's best to poll no more frequently than 1 second.

medplum get 'job/[job-id]/status'
curl 'https://api.medplum.com/fhir/R4/job/[job-id]/status' \
  -H "Authorization: Bearer $MY_ACCESS_TOKEN"

Example Response

When the bot execution completes successfully:

{

resourceType: 'AsyncJob',

id: 'job-id',

status: 'completed',

request: 'https://api.medplum.com/fhir/R4/Bot/:bot-id/$execute',

requestTime: '2023-01-01T00:00:00.000Z',

transactionTime: '2023-01-01T00:00:05.000Z',

output: {

resourceType: 'Parameters',

parameter: [

{

name: 'responseBody',

valueString: 'Bot execution result',

},

],

},

};

When the bot execution fails:

{

resourceType: 'AsyncJob',

id: 'job-id',

status: 'error',

request: 'https://api.medplum.com/fhir/R4/Bot/:bot-id/$execute',

requestTime: '2023-01-01T00:00:00.000Z',

transactionTime: '2023-01-01T00:00:05.000Z',

output: {

resourceType: 'Parameters',

parameter: [

{

name: 'outcome',

resource: {

resourceType: 'OperationOutcome',

issue: [

{

severity: 'error',

code: 'processing',

details: {

text: 'Bot execution failed',

},

},

],

},

},

],

},

};