diff --git a/src/mol-plugin/context.ts b/src/mol-plugin/context.ts
index 0d43b9b3985c80982c91b430d8e57c5c4170e050..588fc0dc6212d1502a7db970819c1ff4ccc2b7f7 100644
--- a/src/mol-plugin/context.ts
+++ b/src/mol-plugin/context.ts
@@ -103,8 +103,8 @@ export class PluginContext {
      * This should be used in all transform related request so that it could be "spoofed" to allow
      * "static" access to resources.
      */
-    fetch(url: string, type: 'string' | 'binary' = 'string'): Task<string | Uint8Array> {
-        return ajaxGet({ url, type });
+    fetch(url: string, type: 'string' | 'binary' = 'string', body?: string): Task<string | Uint8Array> {
+        return ajaxGet({ url, type, body });
         // const req = await fetch(url, { referrerPolicy: 'origin-when-cross-origin' });
         // return type === 'string' ? await req.text() : new Uint8Array(await req.arrayBuffer());
     }
diff --git a/src/mol-util/data-source.ts b/src/mol-util/data-source.ts
index 8545b93979ce9163a34f147389061f8b33955822..05730c20f0c7c8c296bfb35462928624b425a26a 100644
--- a/src/mol-util/data-source.ts
+++ b/src/mol-util/data-source.ts
@@ -19,6 +19,7 @@ export interface AjaxGetParams {
     type: 'string' | 'binary',
     title?: string,
     compression?: DataCompressionMethod
+    body?: string
 }
 
 export function readStringFromFile(file: File) {
@@ -42,9 +43,11 @@ export function ajaxGetUint8Array(url: string, title?: string) {
 }
 
 export function ajaxGet(params: AjaxGetParams) {
-    return <Task<string | Uint8Array>>ajaxGetInternal(params.title, params.url, params.type === 'binary', params.compression === DataCompressionMethod.Gzip);
+    return <Task<string | Uint8Array>>ajaxGetInternal(params.title, params.url, params.type === 'binary', params.compression === DataCompressionMethod.Gzip, params.body);
 }
 
+export type AjaxTask = (url: string, type: 'string' | 'binary') => Task<string | Uint8Array>
+
 function decompress(buffer: Uint8Array): Uint8Array {
     // TODO
     throw 'nyi';
@@ -160,7 +163,7 @@ async function processAjax(ctx: RuntimeContext, asUint8Array: boolean, decompres
     }
 }
 
-function ajaxGetInternal(title: string | undefined, url: string, asUint8Array: boolean, decompressGzip: boolean): Task<string | Uint8Array> {
+function ajaxGetInternal(title: string | undefined, url: string, asUint8Array: boolean, decompressGzip: boolean, body?: string): Task<string | Uint8Array> {
     let xhttp: XMLHttpRequest | undefined = void 0;
     return Task.create(title ? title : 'Download', async ctx => {
         try {
@@ -170,9 +173,9 @@ function ajaxGetInternal(title: string | undefined, url: string, asUint8Array: b
 
             xhttp = RequestPool.get();
 
-            xhttp.open('get', url, true);
+            xhttp.open(body ? 'post' : 'get', url, true);
             xhttp.responseType = asUint8Array ? 'arraybuffer' : 'text';
-            xhttp.send();
+            xhttp.send(body);
 
             ctx.update({ message: 'Waiting for server...', canAbort: true });
             const e = await readData(ctx, 'Downloading...', xhttp, asUint8Array);