diff --git a/includes/project_issue.json.inc b/includes/project_issue.json.inc
new file mode 100644
index 0000000..9cc020f
--- /dev/null
+++ b/includes/project_issue.json.inc
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * Menu callback. Returns JSON for an issue node.
+ *
+ * @param $issue
+ *   A node of type project_issue.
+ * @return void
+ */
+function project_issue_json($issue) {
+  if ($project = node_load($issue->project_issue['pid'])) {
+    $options = array('absolute' => TRUE);
+    $return = array(
+      // Bump minor version when you add items. Bump major version when breaking backwards compatibility.
+      'json-version' => '1.0',
+      'title' => $issue->title,
+      'id' => $issue->nid,
+      'url' => url('node/' . $issue->nid, $options),
+      'component' => $issue->project_issue['component'],
+      'category' => $issue->project_issue['category'],
+      'priority' => $issue->project_issue['priority'],
+      'version' => $issue->project_issue['rid'],
+      'assigned' => $issue->project_issue['assigned'],
+      'status' => $issue->project_issue['sid'],
+      'project-id' => $project->nid,
+      'project-title' => $project->title,
+      'project-url' => url('node/' . $project->nid, $options),
+      'project-name' => $project->project['uri'],
+    );
+    $result = db_query("SELECT c.cid, c.status, c.thread, u.name, u.uid FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.nid = %d ORDER BY c.cid ASC", $issue->nid);
+    while ($row = db_fetch_object($result)) {
+      $return['contributors'][$row->uid] = array(
+        'name' => $row->name,
+        'uid' => $row->uid,
+        'url' => url('user/' . $row->uid, array('absolute' => TRUE)),
+      );
+      $return['comments'][$row->cid] = array(
+        'contributor' => $row->uid,
+        'url' => url('node/' . $return['id'], array('absolute' => TRUE, 'fragment' => 'comment-' . $row->cid)),
+        'status' => $row->status,
+        'thread' => $row->thread,
+      );
+    }
+    drupal_alter('project_issue_json', $return);
+    drupal_json($return);
+  }
+}
diff --git a/project_issue.module b/project_issue.module
index 7c57e27..aa910fa 100644
--- a/project_issue.module
+++ b/project_issue.module
@@ -193,6 +193,16 @@ function project_issue_menu() {
     'type' => MENU_CALLBACK,
   );
 
+  $items['node/%node/json'] = array(
+    'title' => 'JSON',
+    'page callback' => 'project_issue_json',
+    'page arguments' => array(1),
+    'access callback' => 'project_issue_menu_access_task',
+    'access arguments' => array(1),
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'includes/project_issue.json.inc',
+    'weight' => 10,
+  );
   // Autocomplete paths.
 
   // Autocomplete a comma-separated list of projects that have issues enabled.
@@ -259,6 +269,10 @@ function project_issue_menu_access($type) {
   return user_access('access project issues') || user_access('access own project issues');
 }
 
+function project_issue_menu_access_task($node) {
+  return $node->type == 'project_issue' && node_access('view', $node);
+}
+
 function project_issue_help($path, $arg) {
   switch ($path) {
     case 'admin/help#project_issue':
