Move files between MultipleStorages

Hello community,

My storage for orthanc files is getting over. I would like to move old files to another storage, I am mounting smb-share for that.
I created api-key via keycloak web-interface for rest-api requests, It’s working fine.

[root@orthanc02 orthanc]# curl -H "api-key: test-admin" ``http://172.19.206.14:8042/plugins/advanced-storage/
{
"Description" : "Provides alternative layout for your storage.",
"ExtendsOrthancExplorer" : false,
"ID" : "advanced-storage",
"Version" : "0.3.1"

But when I try to use move-storage I always get http 403

[root@orthanc02 orthanc]# curl -i -H "api-key: test-admin" ``http://172.19.206.14/orthanc/plugins/advanced-storage/move-storage`` -d '{
"Resources": ["fff2a1c5-47b84488-543eb44e-c52bd3b3-d72e908f"],
"TargetStorageId": "cold"
}'
HTTP/1.1 403 Forbidden
Server: nginx/1.29.8
Date: Thu, 30 Jul 2026 17:48:05 GMT
Content-Length: 0
Connection: keep-alive
X-Content-Type-Options: nosniff

Here is my docker-compose.yml

services:

nginx:
image: orthancteam/orthanc-nginx:latest
depends_on: [orthanc, orthanc-auth-service, keycloak, ohif]
restart: unless-stopped
ports:
- "80:80"
environment:
TZ: "Asia/Yekaterinburg"
ENABLE_ORTHANC: "true"
ENABLE_OHIF: "true"
ENABLE_KEYCLOAK: "true"
ENABLE_ORTHANC_TOKEN_SERVICE: "true"
ENABLE_HTTPS: "false"

orthanc:
image: orthancteam/orthanc:26.6.0
depends_on: [orthanc-db]
restart: unless-stopped
ports:
- "4242:4242"
- "8042:8042"
volumes:
- /var/orthanc/storage/orthanc_container:/var/lib/orthanc/db
- /mnt/archive:/mnt/archive/
environment:
TZ: "Asia/Yekaterinburg"
DICOM_WEB_PLUGIN_ENABLED: "true" # requiers for most of the dicom viewers
STL_PLUGIN_ENABLED: "true"
POSTGRESQL_PLUGIN_ENABLED: "true" # index-database for orthanc
ORTHANC__POSTGRESQL__HOST: "orthanc-db"
ORTHANC__POSTGRESQL__TRANSACTION_MODE: "ReadCommitted"
HOUSEKEEPER_PLUGIN_ENABLED: "true" # improve performances and storage usage
CONNECTIVITY_CHECKS_PLUGIN_ENABLED: "true" # check connectivity to DICOM modalities, DICOMweb servers and Orthanc peers
ADVANCED_STORAGE_PLUGIN_ENABLED: "true" # advanced storage mechanism
VERBOSE_STARTUP: "true" # logs on startup
VERBOSE_ENABLED: "true" # logs while working

  ORTHANC_JSON: |
    {
      "Name": "...",

      "DicomServerEnabled" : true,
      "DicomAet" : "ORTHANC",
      "DicomPort" : 4242,

      "AdvancedStorage": {
        "Enable": true,
        "MultipleStorages": {
          "Storages": {
            "hot": "/var/lib/orthanc/db",
            "cold": "/mnt/archive-orthanc"
          }
        },
      "CurrentWriteStorage": "hot"
      },

      "PostgreSQL": {
        "EnableIndex": true,
        "EnableStorage": false,
        "Port": 5432,
        "Host": "orthanc-db",
        "Database": "...",
        "Username": "...",
        "Password": "..."
      },

      "DicomModalities" : {
        ...
      },

      "OrthancExplorer2": {
        "IsDefaultUI": true,
        "UiOptions": {
          "EnableShares": true,
          "DefaultShareDuration": 0,
          "ShareDurations": [0, 7, 15, 30, 90, 365],
          "EnableOpenInOhifViewer3": true,
          // to use OHIF-plugin:  use http://localhost/orthanc/ohif/
          //"OhifViewer3PublicRoot": "http://localhost/orthanc/ohif/"
          "OhifViewer3PublicRoot": "http://172.19.206.14/ohif/",
          "CustomButtons": {
            "study": [
              {
                "HttpMethod": "GET",
                "Id": "get-jpeg-archive",
                "Tooltip": "Get JPG Archive",
                "Target": "_self",
                "Icon": "bi bi-filetype-jpg",
                "Url": "../../studies/{UUID}/download-as-jpeg-archive?token={study-resource-token/download-instant-link}&preview-level=instance"
              }
            ]
          }
        },
        "Tokens" : {
          "InstantLinksValidity": 3600,
          "ShareType": "ohif-viewer-publication",
          "LandingOptions" : [
            {
              "Type" : "open-viewer-button"
            },
            {
              "Type" : "download-study"
            },
            {
              "Type": "custom",
              "Id": "get-jpeg-archive",
              "Icon": "bi bi-filetype-jpg",
              "Title": "Download study as jpeg Archive",
              "Url": "../../studies/{UUID}/download-as-jpeg-archive?preview-level=instance&filename={StudyInstanceUID}.zip"
            }
          ]
        },
        "Keycloak" : {
          "Enable": true,
          "Url": "http://172.19.206.14/keycloak/",
          "Realm": "orthanc",
          "ClientId": "orthanc"
        }

      },
      "AuthenticationEnabled": false,     // because it is handled by the authorization plugin
      "Authorization": {
        "WebServiceRootUrl": "http://172.19.206.14:8000/",
        "WebServiceUsername": "...",
        "WebServicePassword": "...",
        // to use OHIF-plugin:  make sure to include "ohif" in the list
        "StandardConfigurations" : [
          "osimis-web-viewer",
          "stone-webviewer",
          "orthanc-explorer-2",
          "ohif",
          "stl",
          "advanced-storage"
        ],
        "TokenHttpHeaders" : [ "api-key" ],
        "CheckedLevel": "studies"
      },
      "DicomWeb": {
        "Enable": true,
        "PublicRoot": "/orthanc/dicom-web/"
      }
    }

ohif:
image: orthancteam/ohif-v3:latest
restart: unless-stopped
volumes:
- ./ohif-app-config.js:/usr/share/nginx/html/app-config.js
environment:
TZ: "Asia/Yekaterinburg"

orthanc-db:
image: postgres:16
restart: unless-stopped
volumes:
- /var/orthanc/storage/orthanc-db_container:/var/lib/postgresql/data
environment:
TZ: "Asia/Yekaterinburg"
POSTGRES_DB: orthanc
POSTGRES_USER: ...
POSTGRES_PASSWORD: ...
healthcheck:
test: ["CMD-SHELL", "pg_isready -U admin -d orthanc"]
interval: 5s
timeout: 5s
retries: 5

orthanc-auth-service: # permissions can be customized in the permissions.json file
image: orthancteam/orthanc-auth-service:latest
depends_on: [keycloak]
restart: unless-stopped
ports:
- "8000:8000"
volumes:
- ./permissions.jsonc:/orthanc_auth_service/permissions.json
environment:
TZ: "Asia/Yekaterinburg"
SECRET_KEY: "..."
ENABLE_KEYCLOAK: "true"
ENABLE_KEYCLOAK_API_KEYS: "true"
KEYCLOAK_CLIENT_SECRET: "..."
PUBLIC_ORTHANC_ROOT: "http://172.19.206.14/orthanc/"
PUBLIC_LANDING_ROOT: "http://172.19.206.14/orthanc/ui/app/token-landing.html"
PUBLIC_OHIF_ROOT: "http://172.19.206.14/ohif/"
USERS: |
{
"...": "..."
}

keycloak:
image: orthancteam/orthanc-keycloak:latest
depends_on:
keycloak-db:
condition: service_healthy
restart: unless-stopped
volumes:
- /var/orthanc/storage/keycloak-container:/usr/tmp
environment:
TZ: "Asia/Yekaterinburg"
ENABLE_KEYCLOAK_API_KEYS: "true"
KC_BOOTSTRAP_ADMIN_USERNAME: "..."
KC_BOOTSTRAP_ADMIN_PASSWORD: "..."
KC_DB: "postgres"
KC_DB_URL: "jdbc:postgresql://keycloak-db:5432/keycloak"
KC_DB_USERNAME: "..."
KC_DB_PASSWORD: "..."
KC_HOSTNAME_URL: "http://172.19.206.14/keycloak"
KC_HOSTNAME_ADMIN_URL: "http://172.19.206.14/keycloak"
KC_HOSTNAME: "http://172.19.206.14/keycloak"

keycloak-db:
image: postgres:14
restart: unless-stopped
volumes:
- /var/orthanc/storage/keycloak_db-container:/var/lib/postgresql/data
environment:
TZ: "Asia/Yekaterinburg"
POSTGRES_DB: "..."
POSTGRES_USER: "..."
POSTGRES_PASSWORD: "..."
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ... -d ...."]
interval: 5s
timeout: 5s
retries: 5

Thank you for any advice!

Hello and welcome!

Could you add this just after the "CheckedLevel": "studies" line (same level) ?

"ExtraPermissions": [["post", "^/plugins/advanced-storage/move-storage$", "admin-permissions"]]

Hope this helps…

Thank you a lot, this helped