diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..156b436d2d6af8298dbce57eadca9e4c55828d47
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,19 @@
+variables:
+  PIP_CACHE_DIR: "$CI_PROJECT_DIR/pip-cache"
+
+stages:
+  - test
+
+test_schemas:
+  stage: test
+  image: python:3
+  cache:
+    key: "$CI_PROJECT_ID__pip_cache"
+    paths:
+      - "$PIP_CACHE_DIR"
+  before_script:
+    - pip3 install .[dev]
+  script:
+    - pytest tests/
+  tags:
+    - docker
diff --git a/schemas/0.1/example.json b/schemas/0.1/example.json
new file mode 100644
index 0000000000000000000000000000000000000000..cf8d8935909eaa7fd89825a28ce8ac6840fff13c
--- /dev/null
+++ b/schemas/0.1/example.json
@@ -0,0 +1,25 @@
+{
+  "version": "0.1",
+  "means": [
+    {
+      "provider": "flattr",
+      "id": "Alice",
+      "weight": 0,
+      "url": "https://flattr.com/@Alice"
+    },
+    {
+      "provider": "custom",
+      "id": "sendmecash",
+      "name": "Cash",
+      "weight": 1,
+      "description": "I live here, you can send me money directly"
+    },
+    {
+      "provider": "unkown",
+      "id": "freetips",
+      "name": "Tip me on freetips",
+      "weight": 2,
+      "description": "This is the best place to tip me"
+    }
+  ]
+}
diff --git a/schemas/0.1/schema.json b/schemas/0.1/schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..8a4e6debf58e82b6cc78cdeccd8a92184389c57c
--- /dev/null
+++ b/schemas/0.1/schema.json
@@ -0,0 +1,63 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "id": "http://retribute.me/ns/schema/0.1.json",
+  "description": "Retribute.me schema version 0.1",
+  "type": "object",
+  "additionalProperties": false,
+  "required": [
+    "version",
+    "means"
+  ],
+  "properties": {
+    "version": {
+      "description": "The schema version, must be 0.1.",
+      "enum": [
+        "0.1"
+      ]
+    },
+    "means": {
+      "description": "A list of retribution means",
+      "type": "array",
+      "items": { "$ref": "#/definitions/mean" }
+    }
+  },
+  "definitions": {
+    "mean": {
+      "description": "A single retribution mean",
+      "type": "object",
+      "required": ["provider", "id", "weight"],
+      "minItems": 1,
+      "properties": {
+        "provider": {
+          "type": "string",
+          "description": "A provider id",
+          "examples": [
+            "flattr",
+            "liberapay",
+            "patreon",
+            "tipeee",
+            "paypal",
+            "wiretransfer",
+            "bitcoin",
+            "wiretransfer",
+            "custom"
+          ]
+        },
+        "id": {
+          "type": "string"
+        },
+        "name": {
+          "type": "string"
+        },
+        "description": {
+          "type": "string"
+        },
+        "weight": {
+          "type": "integer",
+          "minimum": 0,
+          "description": "Weight of the retribution mean. Higher values mean this mean is preferred to others"
+        }
+      }
+    }
+  }
+}
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..6ec92edc4c74ba52cad007b9b9477f4b366a2a22
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,39 @@
+[metadata]
+name = retribute-me
+description = "Utils around the retribute.me specification"
+version = 0.1.dev0
+author = Eliot Berriot
+author_email = contact@eliotberriot.com
+url = https://dev.funkwhale.audio/retribute.me/spec
+long_description = file: README.md
+license = AGPL3
+keywords = downloader, network, archive
+classifiers =
+    Development Status :: 3 - Alpha
+    License :: OSI Approved :: AGPL
+    Natural Language :: English
+    Programming Language :: Python :: 3.6
+
+[options]
+zip_safe = True
+include_package_data = True
+packages = find:
+install_requires =
+    jsonschema
+
+
+[options.extras_require]
+dev =
+    ipdb
+    pytest
+
+
+[options.packages.find]
+exclude =
+    tests
+
+[bdist_wheel]
+universal = 1
+
+[tool:pytest]
+testpaths = tests
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000000000000000000000000000000000000..43deb57b914ef9490c453292cb01e1df8a4b68dd
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+from setuptools import setup
+
+setup()
diff --git a/tests/test_schemas.py b/tests/test_schemas.py
new file mode 100644
index 0000000000000000000000000000000000000000..005c4482d251c300ab8bfbc10e6b2c4f28b946a4
--- /dev/null
+++ b/tests/test_schemas.py
@@ -0,0 +1,19 @@
+import json
+import jsonschema
+import pytest
+import os
+
+
+SCHEMAS_DIR = os.path.join(
+    os.path.dirname(os.path.abspath(os.path.dirname(__file__))),
+    'schemas'
+)
+@pytest.mark.parametrize('version', ['0.1'])
+def test_schema_validation(version):
+    with open(os.path.join(SCHEMAS_DIR, version, 'schema.json')) as f:
+        schema = json.loads(f.read())
+
+    with open(os.path.join(SCHEMAS_DIR, version, 'example.json')) as f:
+        example = json.loads(f.read())
+
+    assert jsonschema.validate(instance=example, schema=schema) is None