diff --git a/gso/services/provisioning_proxy.py b/gso/services/provisioning_proxy.py
index f18de6c222d309cfe9cf03c5fc91c49890ab52e8..38d3037b33d59cc102d5e9ed02ffc4eb8d964074 100644
--- a/gso/services/provisioning_proxy.py
+++ b/gso/services/provisioning_proxy.py
@@ -7,6 +7,7 @@ import json
 import logging
 from functools import partial
 from http import HTTPStatus
+from typing import Any
 
 import requests
 from orchestrator import step
@@ -84,6 +85,71 @@ _send_put = partial(_send_request, CUDOperation.PUT)
 _send_delete = partial(_send_request, CUDOperation.DELETE)
 
 
+def execute_playbook(
+    playbook_name: str,
+    callback_route: str,
+    inventory: dict[str, Any],
+    extra_vars: dict[str, Any]
+) -> None:
+    """Execute a playbook remotely through the provisioning proxy.
+
+    When providing this method with an inventory, the format should be compatible with the Ansible YAML-based format.
+    For example, an inventory consisting of two hosts, which each a unique host variable assigned to them looks as
+    follows:
+
+    .. code-block:: json
+
+        "inventory": {
+            "_meta": {
+                "vars": {
+                    "host1.local": {
+                        "foo": "bar"
+                    },
+                    "host2.local": {
+                        "key": "value"
+                    }
+                }
+            },
+            "all": {
+                "hosts": {
+                    "host1.local": null,
+                    "host2.local": null
+                }
+            }
+        }
+
+    .. warning::
+       Note the fact that the collection of all hosts is a dictionary, and not a list of strings. Ansible expects each
+       host to be a key-value pair. The key is the :term:`FQDN` of a host, and the value always ``null``.
+
+    The extra vars can be a simple dict consisting of key-value pairs, for example:
+
+    .. code-block:: json
+
+        "extra_vars": {
+            "dry_run": true,
+            "commit_comment": "I am a robot!",
+            "verb": "deploy"
+        }
+
+    :param str playbook_name: Filename of the playbook that is to be executed. It must be present on the remote system
+                              running the provisioning proxy, otherwise it will return an error.
+    :param str callback_route: The endpoint at which :term:`GSO` expects a callback to continue the workflow executing
+                               this step.
+    :param dict[str, Any] inventory: An inventory of machines at which the playbook is targeted. Must be in
+                                     YAML-compatible format.
+    :param dict[str, Any] extra_vars: Any extra variables that the playbook relies on. This can include a subscription
+                                      object, a boolean value indicating a dry run, a commit comment, etc.
+    """
+    parameters = {
+        "playbook_name": playbook_name,
+        "inventory": inventory,
+        "extra_vars": extra_vars
+    }
+
+    _send_post("playbook", parameters, callback_route)
+
+
 def provision_router(
     subscription: RouterProvisioning,
     process_id: UUIDstr,