diff --git a/beat/web/experiments/serializers.py b/beat/web/experiments/serializers.py
index af135eac88f9e2957bd77b40ae3ca4b3d7610186..d59d45e6c846f07d1a29ba65c8e2b176d8ccf558 100755
--- a/beat/web/experiments/serializers.py
+++ b/beat/web/experiments/serializers.py
@@ -25,18 +25,115 @@
 #                                                                             #
 ###############################################################################
 
+import simplejson as json
+
+import beat.core
+
+from datetime import datetime
+
 from rest_framework import serializers
+
 from django.contrib.humanize.templatetags.humanize import naturaltime
 
+from django.db.models import CharField, Value as V
+from django.db.models.functions import Concat
+
 from ..common.serializers import ShareableSerializer
 from ..common.fields import JSONSerializerField
+from ..common.utils import validate_restructuredtext
+from ..common.exceptions import ContributionCreationError
+
 from ..ui.templatetags.markup import restructuredtext
 
+from ..toolchains.models import Toolchain
+
 from .models import Experiment, Block
 
-from datetime import datetime
 
-import simplejson as json
+# ----------------------------------------------------------
+
+
+class ExperimentCreationSerializer(serializers.ModelSerializer):
+    declaration = JSONSerializerField()
+    description = serializers.CharField(required=False, allow_blank=True)
+    fork_of = serializers.JSONField(required=False)
+    toolchain = serializers.CharField()
+
+    class Meta:
+        model = Experiment
+        beat_core_class = beat.core.experiment
+        fields = [
+            "name",
+            "short_description",
+            "description",
+            "declaration",
+            "toolchain",
+            "fork_of",
+        ]
+
+    def toolchain_queryset(self):
+        user = self.context.get("user")
+        return Toolchain.objects.for_user(user, True).annotate(
+            full_name=Concat(
+                "author__username",
+                V("/"),
+                "name",
+                V("/"),
+                "version",
+                output_field=CharField(),
+            )
+        )
+
+    def validate_name(self, name):
+        # sanitize_name is a static method of Versionable models but Experiment
+        # is currently not such a model
+        return Toolchain.sanitize_name(name)
+
+    def validate_description(self, description):
+        if description.find("\\") >= 0:  # was escaped, unescape
+            description = description.decode("string_escape")
+        validate_restructuredtext(description)
+        return description
+
+    def validate_toolchain(self, toolchain):
+        if not self.toolchain_queryset().filter(full_name=toolchain).exists():
+            raise serializers.ValidationError("Invalid toolchain: {}".format(toolchain))
+
+        return toolchain
+
+    def validate(self, data):
+        user = self.context.get("user")
+        name = data["name"]
+        toolchain = data["toolchain"]
+
+        if self.Meta.model.objects.filter(
+            author=user,
+            name=name,
+            toolchain=self.toolchain_queryset().get(full_name=toolchain),
+        ).exists():
+            raise serializers.ValidationError(
+                "{} {} with toolchain {} already exists on this account".format(
+                    self.Meta.model.__name__.lower(), name, toolchain
+                )
+            )
+
+        return data
+
+    def create(self, validated_data):
+        toolchain = self.toolchain_queryset().get(full_name=validated_data["toolchain"])
+
+        experiment, _, errors = Experiment.objects.create_experiment(
+            author=self.context.get("user"),
+            toolchain=toolchain,
+            name=validated_data["name"],
+            short_description=validated_data.get("short_description", ""),
+            description=validated_data.get("description", ""),
+            declaration=validated_data["declaration"],
+        )
+
+        if errors:
+            raise ContributionCreationError(errors)
+        return experiment
 
 
 # ----------------------------------------------------------