diff --git a/docs/_static/js/main.js b/docs/_static/js/main.js
index 48decb767f28..11b8202481a0 100755
--- a/docs/_static/js/main.js
+++ b/docs/_static/js/main.js
@@ -3,20 +3,21 @@ $('.nav-current').click(function(){
 });
 
 $('.faq-btn').click(function(){
-	$(this).toggleClass('open');
+  $(this).toggleClass('open');
 });
 
 $('.headerlink').parent().each(function() {
-	$(this).hover(
-		function() { $(this).children('.headerlink').show(); },
-		function() { $(this).children('.headerlink').hide(); }
-	);
+  $(this).hover(
+    function() { $(this).children('.headerlink').show(); },
+    function() { $(this).children('.headerlink').hide(); }
+  );
 });
 
 $('.side-nav').children('ul:nth-child(2)').children().each(function() {
   var itemName = $(this).text();
-	if (itemName !== 'Datastore' && itemName !== 'Storage') {
-    $(this).css('padding-left','2em');
+    if (itemName !== 'Datastore' && itemName !== 'Storage' &&
+        itemName !== 'Pub/Sub') {
+      $(this).css('padding-left','2em');
   }
 });
 
diff --git a/docs/index.rst b/docs/index.rst
index 7994c5aa55a6..1c9dbd83ee58 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -15,6 +15,9 @@
   storage-buckets
   storage-acl
   pubsub-api
+  pubsub-surface
+  pubsub-subscription
+  pubsub-topic
 
 
 Getting started
diff --git a/docs/pubsub-api.rst b/docs/pubsub-api.rst
index 73708ed90fcb..2f6e609b6526 100644
--- a/docs/pubsub-api.rst
+++ b/docs/pubsub-api.rst
@@ -1,251 +1,30 @@
-``gcloud.pubsub`` API
-=====================
+.. toctree::
+  :maxdepth: 1
+  :hidden:
 
-Connection / Authorization
---------------------------
+Pub/Sub
+-------
 
-- Inferred defaults used to create connection if none configured explicitly:
+:mod:`gcloud.pubsub`
+~~~~~~~~~~~~~~~~~~~~~~~
 
-  - credentials (derived from GAE / GCE environ if present).
+.. automodule:: gcloud.pubsub.__init__
+  :members:
+  :undoc-members:
+  :show-inheritance:
 
-  - ``project_id`` (derived from GAE / GCE environ if present).
+Connections
+~~~~~~~~~~~
 
-  - ``scopes``
+.. automodule:: gcloud.pubsub.connection
+  :members:
+  :undoc-members:
+  :show-inheritance:
 
+Interacting with the API
+~~~~~~~~~~~~~~~~~~~~~~~~
 
-Manage topics for a project
----------------------------
-
-Create a new topic for the default project:
-
-.. doctest::
-
-   >>> from gcloud.pubsub.topic import Topic
-   >>> topic = Topic('topic_name')
-   >>> topic.create()  # API request
-
-Create a new topic for an explicit project:
-
-.. doctest::
-
-   >>> from gcloud.pubsub.topic import Topic
-   >>> topic = Topic('topic_name', project_id='my.project')
-   >>> topic.create()  # API request
-
-Check for the existance of a topic:
-
-.. doctest::
-
-   >>> from gcloud.pubsub.topic import Topic
-   >>> topic = Topic('topic_name')
-   >>> topic.exists()  # API request
-   True
-
-List topics for the default project:
-
-.. doctest::
-
-   >>> from gcloud import pubsub
-   >>> [topic.name for topic in pubsub.list_topics()]  # API request
-   ['topic_name']
-
-List topics for an explicit project:
-
-.. doctest::
-
-   >>> from gcloud import pubsub
-   >>> topics = pubsub.list_topics(project_id='my.project')  # API request
-   >>> [topic.name for topic in topics]
-   ['topic_name']
-
-Delete a topic:
-
-.. doctest::
-
-   >>> from gcloud.pubsub.topic import Topic
-   >>> topic = Topic('topic_name')
-   >>> topic.delete()  # API request
-
-
-Publish messages to a topic
----------------------------
-
-Publish a single message to a topic, without attributes:
-
-.. doctest::
-
-   >>> from gcloud.pubsub.topic import Topic
-   >>> topic = Topic('topic_name')
-   >>> topic.publish('this is the message_payload')  # API request
-   <message_id>
-
-Publish a single message to a topic, with attributes:
-
-.. doctest::
-
-   >>> from gcloud.pubsub.topic import Topic
-   >>> topic = Topic('topic_name')
-   >>> topic.publish('this is another message_payload',
-   ...               attr1='value1', attr2='value2')  # API request
-   <message_id>
-
-Publish a set of messages to a topic (as a single request):
-
-.. doctest::
-
-   >>> from gcloud.pubsub.topic import Topic
-   >>> topic = Topic('topic_name')
-   >>> with topic.batch() as batch:
-   ...     batch.publish('this is the first message_payload')
-   ...     batch.publish('this is the second message_payload',
-   ...                   attr1='value1', attr2='value2')
-   >>> list(batch)
-   [<message_id1>, <message_id2>]
-
-.. note::
-
-   The only API request happens during the ``__exit__()`` of the topic
-   used as a context manager.
-
-
-Manage subscriptions to topics
-------------------------------
-
-Create a new pull subscription for a topic:
-
-.. doctest::
-
-   >>> from gcloud.pubsub.topic import Topic
-   >>> from gcloud.pubsub.subscription import Subscription
-   >>> topic = Topic('topic_name')
-   >>> subscription = Subscription('subscription_name', topic)
-   >>> subscription.create()  # API request
-
-Create a new pull subscription for a topic with a non-default ACK deadline:
-
-.. doctest::
-
-   >>> from gcloud.pubsub.topic import Topic
-   >>> from gcloud.pubsub.subscription import Subscription
-   >>> topic = Topic('topic_name')
-   >>> subscription = Subscription('subscription_name', ack_deadline=90)
-   >>> subscription.create()  # API request
-
-Create a new push subscription for a topic:
-
-.. doctest::
-
-   >>> ENDPOINT = 'https://example.com/hook'
-   >>> from gcloud.pubsub.topic import Topic
-   >>> from gcloud.pubsub.subscription import Subscription
-   >>> topic = Topic('topic_name')
-   >>> subscription = Subscription('subscription_name', push_endpoint=ENDPOINT)
-   >>> subscription.create()  # API request
-
-Check for the existence of a subscription:
-
-.. doctest::
-
-   >>> from gcloud.pubsub.topic import Topic
-   >>> from gcloud.pubsub.subscription import Subscription
-   >>> topic = Topic('topic_name')
-   >>> subscription = Subscription('subscription_name', topic)
-   >>> subscription.exists()  # API request
-   True
-
-Convert a pull subscription to push:
-
-.. doctest::
-
-   >>> ENDPOINT = 'https://example.com/hook'
-   >>> from gcloud.pubsub.topic import Topic
-   >>> from gcloud.pubsub.subscription import Subscription
-   >>> topic = Topic('topic_name')
-   >>> subscription = Subscription('subscription_name', topic)
-   >>> subscription.modify_push_configuration(push_endpoint=ENDPOINT)  # API request
-
-Convert a push subscription to pull:
-
-.. doctest::
-
-   >>> ENDPOINT = 'https://example.com/hook'
-   >>> from gcloud.pubsub.topic import Topic
-   >>> topic = Topic('topic_name')
-   >>> subscription = Subscription('subscription_name', topic,
-   ...                             push_endpoint=ENDPOINT)
-   >>> subscription.modify_push_configuration(push_endpoint=None)  # API request
-
-List subscriptions for a topic:
-
-.. doctest::
-
-   >>> from gcloud.pubsub.topic import Topic
-   >>> topic = Topic('topic_name')
-   >>> subscriptions = topic.list_subscriptions()  # API request
-   >>> [subscription.name for subscription in subscriptions]
-   ['subscription_name']
-
-Delete a subscription:
-
-.. doctest::
-
-   >>> from gcloud.pubsub.topic import Topic
-   >>> from gcloud.pubsub.subscription import Subscription
-   >>> topic = Topic('topic_name')
-   >>> subscription = Subscription('subscription_name', topic)
-   >>> subscription.delete()  # API request
-
-
-Pull messages from a subscription
----------------------------------
-
-Fetch pending messages for a pull subscription
-
-.. note::
-
-   The messages will have been ACKed already.
-
-.. doctest::
-
-   >>> from gcloud.pubsub.topic import Topic
-   >>> from gcloud.pubsub.subscription import Subscription
-   >>> topic = Topic('topic_name')
-   >>> subscription = Subscription('subscription_name', topic)
-   >>> with topic:
-   ...     topic.publish('this is the first message_payload')
-   ...     topic.publish('this is the second message_payload',
-   ...                   attr1='value1', attr2='value2')
-   >>> messages = subscription.pull()  # API request
-   >>> [message.id for message in messages]
-   [<message_id1>, <message_id2>]
-   >>> [message.data for message in messages]
-   ['this is the first message_payload', 'this is the second message_payload']
-   >>> [message.attrs for message in messages]
-   [{}, {'attr1': 'value1', 'attr2': 'value2'}]
-
-Fetch a limited number of pending messages for a pull subscription:
-
-.. doctest::
-
-   >>> from gcloud.pubsub.topic import Topic
-   >>> from gcloud.pubsub.subscription import Subscription
-   >>> topic = Topic('topic_name')
-   >>> subscription = Subscription('subscription_name', topic)
-   >>> with topic:
-   ...     topic.publish('this is the first message_payload')
-   ...     topic.publish('this is the second message_payload',
-   ...                   attr1='value1', attr2='value2')
-   >>> [message.id for message in subscription.pull(max_messages=1)]
-   [<message_id1>]
-
-Fetch messages for a pull subscription without blocking (none pending):
-
-.. doctest::
-
-   >>> from gcloud.pubsub.topic import Topic
-   >>> from gcloud.pubsub.subscription import Subscription
-   >>> topic = Topic('topic_name')
-   >>> subscription = Subscription('subscription_name', topic)
-   >>> [message.id for message in subscription.pull(return_immediately=True)]
-   []
-
+.. automodule:: gcloud.pubsub.api
+  :members:
+  :undoc-members:
+  :show-inheritance:
diff --git a/docs/pubsub-subscription.rst b/docs/pubsub-subscription.rst
new file mode 100644
index 000000000000..43fc3344a918
--- /dev/null
+++ b/docs/pubsub-subscription.rst
@@ -0,0 +1,7 @@
+Subscriptions
+~~~~~~~~~~~~~
+
+.. automodule:: gcloud.pubsub.subscription
+  :members:
+  :undoc-members:
+  :show-inheritance:
diff --git a/docs/pubsub-surface.rst b/docs/pubsub-surface.rst
new file mode 100644
index 000000000000..73708ed90fcb
--- /dev/null
+++ b/docs/pubsub-surface.rst
@@ -0,0 +1,251 @@
+``gcloud.pubsub`` API
+=====================
+
+Connection / Authorization
+--------------------------
+
+- Inferred defaults used to create connection if none configured explicitly:
+
+  - credentials (derived from GAE / GCE environ if present).
+
+  - ``project_id`` (derived from GAE / GCE environ if present).
+
+  - ``scopes``
+
+
+Manage topics for a project
+---------------------------
+
+Create a new topic for the default project:
+
+.. doctest::
+
+   >>> from gcloud.pubsub.topic import Topic
+   >>> topic = Topic('topic_name')
+   >>> topic.create()  # API request
+
+Create a new topic for an explicit project:
+
+.. doctest::
+
+   >>> from gcloud.pubsub.topic import Topic
+   >>> topic = Topic('topic_name', project_id='my.project')
+   >>> topic.create()  # API request
+
+Check for the existance of a topic:
+
+.. doctest::
+
+   >>> from gcloud.pubsub.topic import Topic
+   >>> topic = Topic('topic_name')
+   >>> topic.exists()  # API request
+   True
+
+List topics for the default project:
+
+.. doctest::
+
+   >>> from gcloud import pubsub
+   >>> [topic.name for topic in pubsub.list_topics()]  # API request
+   ['topic_name']
+
+List topics for an explicit project:
+
+.. doctest::
+
+   >>> from gcloud import pubsub
+   >>> topics = pubsub.list_topics(project_id='my.project')  # API request
+   >>> [topic.name for topic in topics]
+   ['topic_name']
+
+Delete a topic:
+
+.. doctest::
+
+   >>> from gcloud.pubsub.topic import Topic
+   >>> topic = Topic('topic_name')
+   >>> topic.delete()  # API request
+
+
+Publish messages to a topic
+---------------------------
+
+Publish a single message to a topic, without attributes:
+
+.. doctest::
+
+   >>> from gcloud.pubsub.topic import Topic
+   >>> topic = Topic('topic_name')
+   >>> topic.publish('this is the message_payload')  # API request
+   <message_id>
+
+Publish a single message to a topic, with attributes:
+
+.. doctest::
+
+   >>> from gcloud.pubsub.topic import Topic
+   >>> topic = Topic('topic_name')
+   >>> topic.publish('this is another message_payload',
+   ...               attr1='value1', attr2='value2')  # API request
+   <message_id>
+
+Publish a set of messages to a topic (as a single request):
+
+.. doctest::
+
+   >>> from gcloud.pubsub.topic import Topic
+   >>> topic = Topic('topic_name')
+   >>> with topic.batch() as batch:
+   ...     batch.publish('this is the first message_payload')
+   ...     batch.publish('this is the second message_payload',
+   ...                   attr1='value1', attr2='value2')
+   >>> list(batch)
+   [<message_id1>, <message_id2>]
+
+.. note::
+
+   The only API request happens during the ``__exit__()`` of the topic
+   used as a context manager.
+
+
+Manage subscriptions to topics
+------------------------------
+
+Create a new pull subscription for a topic:
+
+.. doctest::
+
+   >>> from gcloud.pubsub.topic import Topic
+   >>> from gcloud.pubsub.subscription import Subscription
+   >>> topic = Topic('topic_name')
+   >>> subscription = Subscription('subscription_name', topic)
+   >>> subscription.create()  # API request
+
+Create a new pull subscription for a topic with a non-default ACK deadline:
+
+.. doctest::
+
+   >>> from gcloud.pubsub.topic import Topic
+   >>> from gcloud.pubsub.subscription import Subscription
+   >>> topic = Topic('topic_name')
+   >>> subscription = Subscription('subscription_name', ack_deadline=90)
+   >>> subscription.create()  # API request
+
+Create a new push subscription for a topic:
+
+.. doctest::
+
+   >>> ENDPOINT = 'https://example.com/hook'
+   >>> from gcloud.pubsub.topic import Topic
+   >>> from gcloud.pubsub.subscription import Subscription
+   >>> topic = Topic('topic_name')
+   >>> subscription = Subscription('subscription_name', push_endpoint=ENDPOINT)
+   >>> subscription.create()  # API request
+
+Check for the existence of a subscription:
+
+.. doctest::
+
+   >>> from gcloud.pubsub.topic import Topic
+   >>> from gcloud.pubsub.subscription import Subscription
+   >>> topic = Topic('topic_name')
+   >>> subscription = Subscription('subscription_name', topic)
+   >>> subscription.exists()  # API request
+   True
+
+Convert a pull subscription to push:
+
+.. doctest::
+
+   >>> ENDPOINT = 'https://example.com/hook'
+   >>> from gcloud.pubsub.topic import Topic
+   >>> from gcloud.pubsub.subscription import Subscription
+   >>> topic = Topic('topic_name')
+   >>> subscription = Subscription('subscription_name', topic)
+   >>> subscription.modify_push_configuration(push_endpoint=ENDPOINT)  # API request
+
+Convert a push subscription to pull:
+
+.. doctest::
+
+   >>> ENDPOINT = 'https://example.com/hook'
+   >>> from gcloud.pubsub.topic import Topic
+   >>> topic = Topic('topic_name')
+   >>> subscription = Subscription('subscription_name', topic,
+   ...                             push_endpoint=ENDPOINT)
+   >>> subscription.modify_push_configuration(push_endpoint=None)  # API request
+
+List subscriptions for a topic:
+
+.. doctest::
+
+   >>> from gcloud.pubsub.topic import Topic
+   >>> topic = Topic('topic_name')
+   >>> subscriptions = topic.list_subscriptions()  # API request
+   >>> [subscription.name for subscription in subscriptions]
+   ['subscription_name']
+
+Delete a subscription:
+
+.. doctest::
+
+   >>> from gcloud.pubsub.topic import Topic
+   >>> from gcloud.pubsub.subscription import Subscription
+   >>> topic = Topic('topic_name')
+   >>> subscription = Subscription('subscription_name', topic)
+   >>> subscription.delete()  # API request
+
+
+Pull messages from a subscription
+---------------------------------
+
+Fetch pending messages for a pull subscription
+
+.. note::
+
+   The messages will have been ACKed already.
+
+.. doctest::
+
+   >>> from gcloud.pubsub.topic import Topic
+   >>> from gcloud.pubsub.subscription import Subscription
+   >>> topic = Topic('topic_name')
+   >>> subscription = Subscription('subscription_name', topic)
+   >>> with topic:
+   ...     topic.publish('this is the first message_payload')
+   ...     topic.publish('this is the second message_payload',
+   ...                   attr1='value1', attr2='value2')
+   >>> messages = subscription.pull()  # API request
+   >>> [message.id for message in messages]
+   [<message_id1>, <message_id2>]
+   >>> [message.data for message in messages]
+   ['this is the first message_payload', 'this is the second message_payload']
+   >>> [message.attrs for message in messages]
+   [{}, {'attr1': 'value1', 'attr2': 'value2'}]
+
+Fetch a limited number of pending messages for a pull subscription:
+
+.. doctest::
+
+   >>> from gcloud.pubsub.topic import Topic
+   >>> from gcloud.pubsub.subscription import Subscription
+   >>> topic = Topic('topic_name')
+   >>> subscription = Subscription('subscription_name', topic)
+   >>> with topic:
+   ...     topic.publish('this is the first message_payload')
+   ...     topic.publish('this is the second message_payload',
+   ...                   attr1='value1', attr2='value2')
+   >>> [message.id for message in subscription.pull(max_messages=1)]
+   [<message_id1>]
+
+Fetch messages for a pull subscription without blocking (none pending):
+
+.. doctest::
+
+   >>> from gcloud.pubsub.topic import Topic
+   >>> from gcloud.pubsub.subscription import Subscription
+   >>> topic = Topic('topic_name')
+   >>> subscription = Subscription('subscription_name', topic)
+   >>> [message.id for message in subscription.pull(return_immediately=True)]
+   []
+
diff --git a/docs/pubsub-topic.rst b/docs/pubsub-topic.rst
new file mode 100644
index 000000000000..2b840b05db6a
--- /dev/null
+++ b/docs/pubsub-topic.rst
@@ -0,0 +1,7 @@
+Topics
+~~~~~~
+
+.. automodule:: gcloud.pubsub.topic
+  :members:
+  :undoc-members:
+  :show-inheritance: