diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApi.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApi.java
index 373684999714fadd99c323f4364e7d8b128523dd..a4c4f996d165ade3c66df09109b5bab80674a2c3 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApi.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApi.java
@@ -39,6 +39,7 @@ import ch.ethz.sis.openbis.generic.server.api.v3.executor.experiment.IDeleteExpe
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.experiment.IMapExperimentByIdExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.experiment.ISearchExperimentExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.experiment.IUpdateExperimentExecutor;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.material.IDeleteMaterialExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.material.IMapMaterialByIdExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.sample.ICreateSampleExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.sample.IDeleteSampleExecutor;
@@ -64,6 +65,7 @@ import ch.ethz.sis.openbis.generic.shared.api.v3.IApplicationServerApi;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.deletion.Deletion;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.deletion.dataset.DataSetDeletionOptions;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.deletion.experiment.ExperimentDeletionOptions;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.deletion.material.MaterialDeletionOptions;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.deletion.sample.SampleDeletionOptions;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.deletion.space.SpaceDeletionOptions;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.dataset.DataSet;
@@ -174,6 +176,9 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi>
     @Autowired
     private ISearchSpaceExecutor searchSpaceExecutor;
 
+    @Autowired
+    private IDeleteMaterialExecutor deleteMaterialsExecutor;
+
     @Autowired
     private ISearchExperimentExecutor searchExperimentExecutor;
 
@@ -599,6 +604,10 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi>
     }
 
     @Override
+    @Transactional
+    @DatabaseCreateOrDeleteModification(value = { ObjectKind.DATA_SET, ObjectKind.DELETION })
+    @RolesAllowed({ RoleWithHierarchy.SPACE_POWER_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @Capability("DELETE_DATA_SET")
     public IDeletionId deleteDataSets(String sessionToken, List<? extends IDataSetId> dataSetIds, DataSetDeletionOptions deletionOptions)
     {
         Session session = getSession(sessionToken);
@@ -615,6 +624,27 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi>
         }
     }
 
+    @Override
+    @Transactional
+    @DatabaseCreateOrDeleteModification(value = { ObjectKind.MATERIAL, ObjectKind.DELETION })
+    @RolesAllowed({ RoleWithHierarchy.INSTANCE_ADMIN, RoleWithHierarchy.INSTANCE_ETL_SERVER })
+    @Capability("DELETE_MATERIAL")
+    public void deleteMaterials(String sessionToken, List<? extends IMaterialId> materialIds, MaterialDeletionOptions deletionOptions)
+    {
+        Session session = getSession(sessionToken);
+        OperationContext context = new OperationContext(session);
+        try
+        {
+            deleteMaterialsExecutor.delete(context, materialIds, deletionOptions);
+        } catch (Throwable t)
+        {
+            throw ExceptionUtils.create(context, t);
+        } finally
+        {
+            getDAOFactory().getSessionFactory().getCurrentSession().clear();
+        }
+    }
+
     @Override
     @Transactional
     @DatabaseCreateOrDeleteModification(value = { ObjectKind.SAMPLE, ObjectKind.DELETION })
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApiLogger.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApiLogger.java
index d77147dedc1f46fbc98aae47933d8a7f6f663308..2a920046ecc98b751a3378af6ef285bb1c33725c 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApiLogger.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApiLogger.java
@@ -23,6 +23,7 @@ import ch.ethz.sis.openbis.generic.shared.api.v3.IApplicationServerApi;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.deletion.Deletion;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.deletion.dataset.DataSetDeletionOptions;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.deletion.experiment.ExperimentDeletionOptions;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.deletion.material.MaterialDeletionOptions;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.deletion.sample.SampleDeletionOptions;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.deletion.space.SpaceDeletionOptions;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.dataset.DataSet;
@@ -262,4 +263,10 @@ public class ApplicationServerApiLogger extends AbstractServerLogger implements
         logAccess(sessionToken, "confirm-deletions", "DELETION_IDS(%s)", deletionIds);
     }
 
+    @Override
+    public void deleteMaterials(String sessionToken, List<? extends IMaterialId> materialIds, MaterialDeletionOptions deletionOptions)
+    {
+        logAccess(sessionToken, "delete-materials", "MATERIAL_IDS(%s) DELETION_OPTIONS(%s)", materialIds, deletionOptions);
+    }
+
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/material/DeleteMaterialExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/material/DeleteMaterialExecutor.java
new file mode 100644
index 0000000000000000000000000000000000000000..5247135ec4ec7cdc51c1cfef8d1e964599777199
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/material/DeleteMaterialExecutor.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2014 ETH Zuerich, Scientific IT Services
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.ethz.sis.openbis.generic.server.api.v3.executor.material;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Resource;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.deletion.material.MaterialDeletionOptions;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.material.IMaterialId;
+import ch.systemsx.cisd.openbis.generic.server.ComponentNames;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.ICommonBusinessObjectFactory;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.IMaterialBO;
+import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.generic.shared.dto.MaterialPE;
+
+/**
+ * @author Jakub Straszewski
+ */
+@Component
+public class DeleteMaterialExecutor implements IDeleteMaterialExecutor
+{
+
+    @Resource(name = ComponentNames.COMMON_BUSINESS_OBJECT_FACTORY)
+    ICommonBusinessObjectFactory businessObjectFactory;
+
+    @Autowired
+    IMapMaterialByIdExecutor mapMaterialByIdExecutor;
+
+    @Override
+    public void delete(IOperationContext context, List<? extends IMaterialId> materialIds, MaterialDeletionOptions deletionOptions)
+    {
+        if (context == null)
+        {
+            throw new IllegalArgumentException("Context cannot be null");
+        }
+        if (materialIds == null)
+        {
+            throw new IllegalArgumentException("Space ids cannot be null");
+        }
+        if (deletionOptions == null)
+        {
+            throw new IllegalArgumentException("Deletion options cannot be null");
+        }
+        if (deletionOptions.getReason() == null)
+        {
+            throw new IllegalArgumentException("Deletion reason cannot be null");
+        }
+
+        IMaterialBO materialBO = businessObjectFactory.createMaterialBO(context.getSession());
+        Map<IMaterialId, MaterialPE> materialMap = mapMaterialByIdExecutor.map(context, materialIds);
+
+        for (Map.Entry<IMaterialId, MaterialPE> entry : materialMap.entrySet())
+        {
+            MaterialPE material = entry.getValue();
+
+            materialBO.deleteByTechId(new TechId(material.getId()), deletionOptions.getReason());
+        }
+    }
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/material/IDeleteMaterialExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/material/IDeleteMaterialExecutor.java
new file mode 100644
index 0000000000000000000000000000000000000000..0b71caf772bd68c24a253ae4aa23d7b18c6ee056
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/material/IDeleteMaterialExecutor.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2015 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.ethz.sis.openbis.generic.server.api.v3.executor.material;
+
+import java.util.List;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.deletion.material.MaterialDeletionOptions;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.material.IMaterialId;
+
+/**
+ * @author Jakub Straszewski
+ */
+public interface IDeleteMaterialExecutor
+{
+    public void delete(IOperationContext context, List<? extends IMaterialId> materialIds, MaterialDeletionOptions deletionOptions);
+
+}
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/AbstractDeletionTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/AbstractDeletionTest.java
index edcc4f6901407cef7525b01301268d9c8792a8bc..cffda5d2c1c68084ed32bb752ea2e741cfd9d369 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/AbstractDeletionTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/AbstractDeletionTest.java
@@ -26,16 +26,19 @@ import junit.framework.Assert;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.deletion.Deletion;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.experiment.Experiment;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.experiment.ExperimentCreation;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.material.Material;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.sample.Sample;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.sample.SampleCreation;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.fetchoptions.deletion.DeletionFetchOptions;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.fetchoptions.experiment.ExperimentFetchOptions;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.fetchoptions.material.MaterialFetchOptions;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.fetchoptions.sample.SampleFetchOptions;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.dataset.DataSetPermId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.deletion.IDeletionId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.entitytype.EntityTypePermId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.experiment.ExperimentPermId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.experiment.IExperimentId;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.material.IMaterialId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.project.ProjectIdentifier;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.ISampleId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.SamplePermId;
@@ -122,6 +125,23 @@ public class AbstractDeletionTest extends AbstractTest
         Assert.assertEquals(exists ? 1 : 0, map.size());
     }
 
+    protected void assertMaterialExists(IMaterialId materialId)
+    {
+        assertMaterialExists(materialId, true);
+    }
+
+    protected void assertMaterialDoesNotExist(IMaterialId materialId)
+    {
+        assertMaterialExists(materialId, false);
+    }
+
+    private void assertMaterialExists(IMaterialId materialId, boolean exists)
+    {
+        String sessionToken = v3api.login(TEST_USER, PASSWORD);
+        Map<IMaterialId, Material> map = v3api.mapMaterials(sessionToken, Collections.singletonList(materialId), new MaterialFetchOptions());
+        Assert.assertEquals(exists ? 1 : 0, map.size());
+    }
+
     protected void assertDataSetExists(DataSetPermId dataSetId)
     {
         assertDataSetExists(dataSetId, true);
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/DeleteMaterialsTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/DeleteMaterialsTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..814d1085095838113e452f9e97de8ed320af821a
--- /dev/null
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/DeleteMaterialsTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2015 ETH Zuerich, Scientific IT Services
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.ethz.sis.openbis.systemtest.api.v3;
+
+import java.util.Collections;
+
+import org.testng.annotations.Test;
+
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.deletion.material.MaterialDeletionOptions;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.material.MaterialPermId;
+import ch.systemsx.cisd.common.action.IDelegatedAction;
+
+/**
+ * @author Jakub Straszewski
+ */
+public class DeleteMaterialsTest extends AbstractDeletionTest
+{
+
+    private static MaterialDeletionOptions options;
+
+    public static MaterialDeletionOptions getOptions()
+    {
+        if (options == null)
+        {
+            options = new MaterialDeletionOptions();
+            options.setReason("Just for testing");
+        }
+        return options;
+    }
+
+    @Test
+    public void testDeleteMaterial()
+    {
+        String sessionToken = v3api.login(TEST_USER, PASSWORD);
+        MaterialPermId materialId = new MaterialPermId("796", "GENE");
+        v3api.deleteMaterials(sessionToken, Collections.singletonList(materialId), getOptions());
+        assertMaterialDoesNotExist(materialId);
+    }
+
+    @Test
+    public void testDeleteMaterialLinkedAsAProperty()
+    {
+        final String sessionToken = v3api.login(TEST_USER, PASSWORD);
+        final MaterialPermId materialId = new MaterialPermId("BACTERIUM-X", "BACTERIUM");
+
+        assertUserFailureException(new IDelegatedAction()
+            {
+
+                @Override
+                public void execute()
+                {
+                    v3api.deleteMaterials(sessionToken, Collections.singletonList(materialId), getOptions());
+                }
+            }, "BACTERIUM-X (BACTERIUM) is being used. Delete all connected data  first.");
+
+    }
+}