diff --git a/doc/source/dev/vendor-passthru.rst b/doc/source/dev/vendor-passthru.rst
new file mode 100644
index 0000000000..7ab11e98ac
--- /dev/null
+++ b/doc/source/dev/vendor-passthru.rst
@@ -0,0 +1,126 @@
+.. _vendor-passthru:
+
+==============
+Vendor Methods
+==============
+
+This document is a quick tutorial on writing vendor specific methods to
+a driver.
+
+The first thing to note is that the Ironic API supports two vendor
+endpoints: A driver vendor passthru and a node vendor passthru.
+
+* The driver vendor passthru allows drivers to expose a custom top-level
+ functionality which is not specific to a Node. For example, let's say
+ the driver `pxe_ipmitool` exposed a method called `authentication_types`
+ that would return what are the authentication types supported. It could
+ be accessed via the Ironic API like:
+
+::
+
+ GET http://
:/v1/drives/pxe_ipmitool/vendor_passthru/authentication_types
+
+* The node vendor passthru allows drivers to expose custom functionality
+ on per-node basis. For example the same driver `pxe_ipmitool` exposing a
+ method called `send_raw` that would send raw bytes to the BMC, the method
+ also receives a parameter called `raw_bytes` which the value would be
+ the bytes to be sent. It could be accessed via the Ironic API like:
+
+::
+
+ POST {'raw_bytes': '0x01 0x02'} http://:/v1/nodes//vendor_passthru/send_raw
+
+
+Writing Vendor Methods
+======================
+
+Writing a custom vendor method in Ironic should be simple. The first thing
+to do is write a class inheriting from the `VendorInterface`_ class:
+
+.. code-block:: python
+
+ class ExampleVendor(VendorInterface)
+
+ def get_properties(self):
+ return {}
+
+ def validate(self, task, **kwargs):
+ pass
+
+The `get_properties` is a method that all driver interfaces have, it
+should return a dictionary of : telling in the
+description whether that property is required or optional so the node
+can be manageable by that driver. For example, a required property for a
+`ipmi` driver would be `ipmi_address` which is the IP address or hostname
+of the node. We are returning an empty dictionary in our example to make
+it simpler.
+
+The `validate` method is responsible for validating the parameters passed
+to the vendor methods. Ironic will not introspect into what is passed
+to the drivers, it's up to the developers writing the vendor method to
+validate that data.
+
+Let's extend the `ExampleVendor` class to support two methods, the
+`authentication_types` which will be exposed on the driver vendor
+passthru endpoint; And the `send_raw` method that will be exposed on
+the node vendor passthru endpoint:
+
+.. code-block:: python
+
+ class ExampleVendor(VendorInterface)
+
+ def get_properties(self):
+ return {}
+
+ def validate(self, task, method, **kwargs):
+ if method == 'send_raw':
+ if 'raw_bytes' not in kwargs:
+ raise MissingParameterValue()
+
+ @base.driver_passthru(['GET'], async=False)
+ def authentication_types(self, context **kwargs):
+ return {"types": ["NONE", "MD5", "MD2"]}
+
+ @base.passthru(['POST'])
+ def send_raw(self, task, **kwargs):
+ raw_bytes = kwargs.get('raw_bytes')
+ ...
+
+That's it!
+
+Writing a node or driver vendor passthru method is pretty much the
+same, the only difference is how you decorate the methods and the first
+parameter of the method (ignoring self). A method decorated with the
+`@passthru` decorator should expect a Task object as first parameter and
+a method decorated with the `@driver_passthru` decorator should expect
+a Context object as first parameter.
+
+Both decorators accepts the same parameters:
+
+* http_methods: A list of what the HTTP methods supported by that vendor
+ function. To know what HTTP method that function was invoked with, a
+ `http_method` parameter will be present in the `kwargs`. Supported HTTP
+ methods are *POST*, *PUT*, *GET* and *PATCH*.
+
+* method: By default the method name is the name of the python function,
+ if you want to use a different name this parameter is where this name
+ can be set. For example:
+
+.. code-block:: python
+
+ @passthru(['PUT'], method="alternative_name")
+ def name(self, task, **kwargs):
+ ...
+
+* description: A string containing a nice description about what that
+ method is suppose to do. Defaults to "" (empty string).
+
+.. _VendorInterface: ../api/ironic.drivers.base.html#ironic.drivers.base.VendorInterface
+
+* async: A boolean value to determine whether this method should run
+ asynchronously or synchronously. Defaults to True (Asynchronously).
+
+.. WARNING::
+ Please avoid having a synchronous method for slow/long-running
+ operations **or** if the method does talk to a BMC; BMCs are flaky
+ and very easy to break.
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 4f5b700dcb..d504dda75b 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -34,6 +34,7 @@ Introduction
.. toctree::
dev/dev-quickstart
+ dev/vendor-passthru
API References
--------------