diff --git a/retribute_api/providers.py b/retribute_api/providers.py
index a0cd126f9b4b17eade36a60aeca48f892596228d..ebb3069482483c4a087bca8e501de997da43d50a 100644
--- a/retribute_api/providers.py
+++ b/retribute_api/providers.py
@@ -1,4 +1,5 @@
 import re
+import urllib.parse
 
 
 class Registry(object):
@@ -21,8 +22,8 @@ registry = Registry()
 class Provider(object):
     id = None
     additional_ids = []
-    domain_regex = None
-    username_regex = None
+    description = None
+    url = None
 
     def match_by_name(self, value):
         if not value:
@@ -119,3 +120,16 @@ class BandCamp(BasicUsernameInDomainProvider):
     url = "https://bandcamp.com"
 
     username_regex = r"^(\w+)\.bandcamp\.com"
+
+
+@registry.register
+class Custom(Provider):
+    id = "custom"
+    label = "Custom"
+    description = "Any url that contains a 'retribute' query parameter, e.g https://my.shop?retribute"
+
+    def match_from_url(self, parsed_url):
+        params = urllib.parse.parse_qs(parsed_url.query, keep_blank_values=True)
+        for key in params:
+            if key.lower() == "retribute":
+                return {"provider": "custom", "id": parsed_url.geturl()}
diff --git a/retribute_api/search/consumers.py b/retribute_api/search/consumers.py
index 9f382213f69483f258b92cbbc35d8c790131bcb9..e0eeac889f890279b548834c58833cdd94f38c67 100644
--- a/retribute_api/search/consumers.py
+++ b/retribute_api/search/consumers.py
@@ -183,7 +183,7 @@ class ProvidersConsumer(AsyncHttpConsumer):
     @wrapper_500
     async def handle(self, body):
         data = [
-            {"id": p.id, "label": p.label, "url": p.url}
+            {"id": p.id, "label": p.label, "url": p.url, "description": p.description}
             for _, p in sorted(providers.registry, key=lambda v: v[0])
         ]
         await json_response(self, 200, data)
diff --git a/tests/search/test_consumers.py b/tests/search/test_consumers.py
index 956e4776137e45733b926c6bdc569ede4f363045..c59a783f5ee7e691a248637ce83c55a9a12d6ebe 100644
--- a/tests/search/test_consumers.py
+++ b/tests/search/test_consumers.py
@@ -80,7 +80,7 @@ async def test_search_multiple(loop, application, mocker, coroutine_mock, dummyc
 
 async def test_providers(loop, application, mocker, coroutine_mock):
     expected = [
-        {"id": p.id, "label": p.label, "url": p.url}
+        {"id": p.id, "label": p.label, "url": p.url, "description": p.description}
         for _, p in sorted(providers.registry, key=lambda v: v[0])
     ]
     communicator = HttpCommunicator(application, "GET", "/v1/providers")
diff --git a/tests/search/test_means.py b/tests/search/test_means.py
index db189dbe7edbf35e42245b07f6d38c76c47caf00..0a3db70bbd8bff99a8a79b3e50262298656f3e29 100644
--- a/tests/search/test_means.py
+++ b/tests/search/test_means.py
@@ -14,6 +14,10 @@ from retribute_api.search import means
         ("https://www.paypal.me/username", {"provider": "paypal", "id": "username"}),
         ("https://fr.tipeee.com/username", {"provider": "tipeee", "id": "username"}),
         ("https://tipeee.com/username", {"provider": "tipeee", "id": "username"}),
+        (
+            "https://custom.com/username?retribute",
+            {"provider": "custom", "id": "https://custom.com/username?retribute"},
+        ),
         (
             "https://opencollective.com/username",
             {"provider": "opencollective", "id": "username"},