diff --git a/swh/web/api/apidoc.py b/swh/web/api/apidoc.py
--- a/swh/web/api/apidoc.py
+++ b/swh/web/api/apidoc.py
@@ -34,6 +34,10 @@
     # httpdomain roles we want to parse (based on sphinxcontrib.httpdomain 1.6)
     parameter_roles = ('param', 'parameter', 'arg', 'argument')
 
+    request_json_object_roles = ('reqjsonobj', 'reqjson', '<jsonobj', '<json')
+
+    request_json_array_roles = ('reqjsonarr', '<jsonarr')
+
     response_json_object_roles = ('resjsonobj', 'resjson', '>jsonobj', '>json')
 
     response_json_array_roles = ('resjsonarr', '>jsonarr')
@@ -53,6 +57,7 @@
         self.data = data
         self.args_set = set()
         self.params_set = set()
+        self.inputs_set = set()
         self.returns_set = set()
         self.status_codes_set = set()
         self.reqheaders_set = set()
@@ -115,9 +120,24 @@
                                                     'type': field_data[1],
                                                     'doc': text})
                         self.params_set.add(field_data[2])
+                # Request data type
+                if (field_data[0] in self.request_json_array_roles or
+                        field_data[0] in self.request_json_object_roles):
+                    # array
+                    if field_data[0] in self.request_json_array_roles:
+                        self.data['input_type'] = 'array'
+                    # object
+                    else:
+                        self.data['input_type'] = 'object'
+                    # input object field
+                    if field_data[2] not in self.inputs_set:
+                        self.data['inputs'].append({'name': field_data[2],
+                                                    'type': field_data[1],
+                                                    'doc': text})
+                        self.inputs_set.add(field_data[2])
                 # Response type
-                if field_data[0] in self.response_json_array_roles or \
-                        field_data[0] in self.response_json_object_roles:
+                if (field_data[0] in self.response_json_array_roles or
+                        field_data[0] in self.response_json_object_roles):
                     # array
                     if field_data[0] in self.response_json_array_roles:
                         self.data['return_type'] = 'array'
@@ -361,6 +381,8 @@
         'urls': [],
         'args': [],
         'params': [],
+        'input_type': '',
+        'inputs': [],
         'resheaders': [],
         'reqheaders': [],
         'return_type': '',
@@ -384,11 +406,22 @@
     # sphinx extension, not needed and raise errors with sphinx >= 1.7)
     elif 'SWH_WEB_DOC_BUILD' not in os.environ:
         _parse_httpdomain_doc(f.__doc__, data)
-        # process returned object info for nicer html display
+        # process input/returned object info for nicer html display
+        inputs_list = ''
         returns_list = ''
+        for inp in data['inputs']:
+            # special case for array of non object type, for instance
+            # :<jsonarr string -: an array of string
+            if inp['name'] != '-':
+                inputs_list += ('\t* **%s (%s)**: %s\n' %
+                                (inp['name'], inp['type'], inp['doc']))
         for ret in data['returns']:
-            returns_list += '\t* **%s (%s)**: %s\n' %\
-                (ret['name'], ret['type'], ret['doc'])
+            # special case for array of non object type, for instance
+            # :>jsonarr string -: an array of string
+            if ret['name'] != '-':
+                returns_list += ('\t* **%s (%s)**: %s\n' %
+                                 (ret['name'], ret['type'], ret['doc']))
+        data['inputs_list'] = inputs_list
         data['returns_list'] = returns_list
 
     return data
diff --git a/swh/web/templates/api/apidoc.html b/swh/web/templates/api/apidoc.html
--- a/swh/web/templates/api/apidoc.html
+++ b/swh/web/templates/api/apidoc.html
@@ -116,6 +116,31 @@
   </div>
 <hr/>
 {% endif %}
+{% if input_type %}
+  <div>
+    <h4> Request data </h4>
+    <dl class="row">
+      <dt class="col col-md-2 text-right"> {{ input_type }} </dt>
+      <dd class="col col-md-9">
+        <p>
+          {% if input_type == 'array' and inputs_list == '' %}
+            {{ inputs.0.doc | safe }}
+          {% elif input_type == 'array' and inputs_list != '' %}
+            an array of objects containing the following keys:
+          {% elif input_type == 'octet stream' %}
+            raw data as an octet stream
+          {% elif input_type == 'object' %}
+            an object containing the following keys:
+          {% endif %}
+          {% if inputs_list != '' %}
+            {{ inputs_list | safe_docstring_display | safe }}
+          {% endif %}
+        </p>
+      </dd>
+    </dl>
+  </div>
+  <hr/>
+{% endif %}
 {% if resheaders and resheaders|length > 0 %}
   <div>
     <h4> Response headers </h4>
@@ -135,14 +160,18 @@
       <dt class="col col-md-2 text-right"> {{ return_type }} </dt>
       <dd class="col col-md-9">
         <p>
-          {% if return_type == 'array' %}
+          {% if return_type == 'array' and returns_list == '' %}
+            {{ returns.0.doc | safe }}
+          {% elif return_type == 'array' and returns_list != '' %}
             an array of objects containing the following keys:
           {% elif return_type == 'octet stream' %}
-            the raw data as an octet stream
-          {% else %}
+            raw data as an octet stream
+          {% elif return_type == 'object' %}
             an object containing the following keys:
           {% endif %}
-          {{ returns_list | safe_docstring_display | safe }}
+          {% if returns_list != '' %}
+            {{ returns_list | safe_docstring_display | safe }}
+          {% endif %}
         </p>
       </dd>
     </dl>
diff --git a/swh/web/tests/api/test_apidoc.py b/swh/web/tests/api/test_apidoc.py
--- a/swh/web/tests/api/test_apidoc.py
+++ b/swh/web/tests/api/test_apidoc.py
@@ -13,10 +13,10 @@
 from swh.web.api.apiurls import api_route
 from swh.web.common.exc import BadInputExc, ForbiddenExc, NotFoundExc
 from swh.web.common.utils import reverse
-from swh.web.tests.django_asserts import assert_template_used
+from swh.web.tests.django_asserts import assert_template_used, assert_contains
 
 
-httpdomain_doc = """
+_httpdomain_doc = """
 .. http:get:: /api/1/revision/(sha1_git)/
 
     Get information about a revision in the archive.
@@ -33,6 +33,10 @@
     :resheader Content-Type: this depends on :http:header:`Accept` header
         of request
 
+    :<json int n: sample input integer
+    :<json string s: sample input string
+    :<json array a: sample input array
+
     :>json object author: information about the author of the revision
     :>json object committer: information about the committer of the revision
     :>json string committer_date: ISO representation of the commit date
@@ -67,7 +71,7 @@
 """
 
 
-exception_http_code = {
+_exception_http_code = {
     BadInputExc: 400,
     ForbiddenExc: 403,
     NotFoundExc: 404,
@@ -115,13 +119,13 @@
     """
     Sample doc
     """
-    for e in exception_http_code.keys():
+    for e in _exception_http_code.keys():
         if e.__name__ == exc_name:
             raise e('Error')
 
 
 def test_apidoc_error(api_client):
-    for exc, code in exception_http_code.items():
+    for exc, code in _exception_http_code.items():
         url = reverse('api-1-test-error',
                       url_args={'exc_name': exc.__name__})
         rv = api_client.get(url)
@@ -181,13 +185,15 @@
         'params': [],
         'resheaders': [],
         'reqheaders': [],
+        'input_type': '',
+        'inputs': [],
         'return_type': '',
         'returns': [],
         'status_codes': [],
         'examples': []
     }
 
-    _parse_httpdomain_doc(httpdomain_doc, doc_data)
+    _parse_httpdomain_doc(_httpdomain_doc, doc_data)
 
     expected_urls = [{
         'rule': '/api/1/revision/ **\\(sha1_git\\)** /',
@@ -256,10 +262,36 @@
     assert 'status_codes' in doc_data
     assert doc_data['status_codes'] == expected_statuscodes
 
+    expected_input_type = 'object'
+
+    assert 'input_type' in doc_data
+    assert doc_data['input_type'] == expected_input_type
+
+    expected_inputs = [
+        {
+            'name': 'n',
+            'type': 'int',
+            'doc': 'sample input integer'
+        },
+        {
+            'name': 's',
+            'type': 'string',
+            'doc': 'sample input string'
+        },
+        {
+            'name': 'a',
+            'type': 'array',
+            'doc': 'sample input array'
+        },
+    ]
+
+    assert 'inputs' in doc_data
+    assert doc_data['inputs'] == expected_inputs
+
     expected_return_type = 'object'
 
     assert 'return_type' in doc_data
-    assert doc_data['return_type'] in expected_return_type
+    assert doc_data['return_type'] == expected_return_type
 
     expected_returns = [
         {
@@ -333,3 +365,67 @@
 
     assert 'examples' in doc_data
     assert doc_data['examples'] == expected_examples
+
+
+@api_route(r'/post/endpoint/', 'api-1-post-endpoint',
+           methods=['POST'])
+@api_doc('/post/endpoint/', post_only=True)
+def apidoc_test_post_endpoint(request):
+    """
+    .. http:post:: /api/1/post/endpoint/
+
+        Endpoint documentation
+
+        :<jsonarr string -: Input array of pids
+
+        :>jsonarr string type: swh object type
+        :>jsonarr string sha1_git: swh object sha1_git
+        :>jsonarr boolean found: whether the object was found or not
+
+    """
+    pass
+
+
+def test_apidoc_input_output_doc(client):
+    url = reverse('api-1-post-endpoint-doc')
+    rv = client.get(url, HTTP_ACCEPT='text/html')
+    assert rv.status_code == 200, rv.content
+    assert_template_used(rv, 'api/apidoc.html')
+
+    input_html_doc = (
+        '   <dl class="row">\n'
+        '      <dt class="col col-md-2 text-right"> array </dt>\n'
+        '      <dd class="col col-md-9">\n'
+        '        <p>\n'
+        '          \n'
+        '            Input array of pids\n'
+        '          \n'
+        '          \n'
+        '        </p>\n'
+        '      </dd>\n'
+        '    </dl>\n'
+    )
+
+    output_html_doc = (
+        '    <dl class="row">\n'
+        '      <dt class="col col-md-2 text-right"> array </dt>\n'
+        '      <dd class="col col-md-9">\n'
+        '        <p>\n'
+        '          \n'
+        '            an array of objects containing the following keys:\n'
+        '          \n'
+        '          \n'
+        '            <div class="swh-rst"><ul class="simple">\n'
+        '<li><p><strong>type (string)</strong>: swh object type</p></li>\n'
+        '<li><p><strong>sha1_git (string)</strong>: swh object sha1_git</p></li>\n' # noqa
+        '<li><p><strong>found (boolean)</strong>: whether the object was found or not</p></li>\n' # noqa
+        '</ul>\n'
+        '</div>\n'
+        '          \n'
+        '        </p>\n'
+        '      </dd>\n'
+        '    </dl>'
+    )
+
+    assert_contains(rv, input_html_doc)
+    assert_contains(rv, output_html_doc)