diff --git a/CHANGELOG b/CHANGELOG
index 84bfc27b1519450456f841af2fe9cdced9a176d2..2dab994ecb807afd78574a84acf42333cff1acc0 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -35,6 +35,7 @@ v 8.10.0 (unreleased)
   - Add notification settings dropdown for groups
   - Wildcards for protected branches. !4665
   - Allow importing from Github using Personal Access Tokens. (Eric K Idema)
+  - API: Expose `due_date` for issues (Robert Schilling)
   - API: Todos !3188 (Robert Schilling)
   - API: Expose shared groups for projects and shared projects for groups !5050 (Robert Schilling)
   - Add "Enabled Git access protocols" to Application Settings
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 3ced787b23e7cadf3b240a69b7787f15a0c45a83..419fb8f85d8ace0393e8f123e7c1ce77735c34d5 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -78,7 +78,8 @@ Example response:
       "iid" : 6,
       "labels" : [],
       "subscribed" : false,
-      "user_notes_count": 1
+      "user_notes_count": 1,
+      "due_date": "2016-07-22"
    }
 ]
 ```
@@ -154,7 +155,8 @@ Example response:
       "updated_at" : "2016-01-04T15:31:46.176Z",
       "created_at" : "2016-01-04T15:31:46.176Z",
       "subscribed" : false,
-      "user_notes_count": 1
+      "user_notes_count": 1,
+      "due_date": null
    }
 ]
 ```
@@ -232,7 +234,8 @@ Example response:
       "updated_at" : "2016-01-04T15:31:46.176Z",
       "created_at" : "2016-01-04T15:31:46.176Z",
       "subscribed" : false,
-      "user_notes_count": 1
+      "user_notes_count": 1,
+      "due_date": "2016-07-22"
    }
 ]
 ```
@@ -295,7 +298,8 @@ Example response:
    "updated_at" : "2016-01-04T15:31:46.176Z",
    "created_at" : "2016-01-04T15:31:46.176Z",
    "subscribed": false,
-   "user_notes_count": 1
+   "user_notes_count": 1,
+   "due_date": null
 }
 ```
 
@@ -320,6 +324,7 @@ POST /projects/:id/issues
 | `milestone_id`  | integer | no  | The ID of a milestone to assign issue |
 | `labels`        | string  | no  | Comma-separated label names for an issue  |
 | `created_at`    | string  | no  | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` |
+| `due_date`      | string  | no   | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
 
 ```bash
 curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues?title=Issues%20with%20auth&labels=bug
@@ -351,7 +356,8 @@ Example response:
    "updated_at" : "2016-01-07T12:44:33.959Z",
    "milestone" : null,
    "subscribed" : true,
-   "user_notes_count": 0
+   "user_notes_count": 0,
+   "due_date": null
 }
 ```
 
@@ -379,6 +385,7 @@ PUT /projects/:id/issues/:issue_id
 | `labels`        | string  | no  | Comma-separated label names for an issue  |
 | `state_event`   | string  | no  | The state event of an issue. Set `close` to close the issue and `reopen` to reopen it |
 | `updated_at`    | string  | no  | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` |
+| `due_date`      | string  | no   | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
 
 ```bash
 curl -X PUT -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues/85?state_event=close
@@ -410,7 +417,8 @@ Example response:
    "assignee" : null,
    "milestone" : null,
    "subscribed" : true,
-   "user_notes_count": 0
+   "user_notes_count": 0,
+   "due_date": "2016-07-22"
 }
 ```
 
@@ -487,7 +495,8 @@ Example response:
     "state": "active",
     "avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon",
     "web_url": "https://gitlab.example.com/u/solon.cremin"
-  }
+  },
+  "due_date": null
 }
 ```
 
@@ -541,7 +550,8 @@ Example response:
     "state": "active",
     "avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon",
     "web_url": "https://gitlab.example.com/u/solon.cremin"
-  }
+  },
+  "due_date": null
 }
 ```
 
@@ -596,7 +606,8 @@ Example response:
     "avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon",
     "web_url": "https://gitlab.example.com/u/orville"
   },
-  "subscribed": false
+  "subscribed": false,
+  "due_date": null
 }
 ```
 
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 301dbb688a7894e508210893aa066f80a72c5d4a..40e2a487fe9c68af01b3526869b25d168d309d1a 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -186,6 +186,7 @@ class Issue < ProjectEntity
       end
       expose :user_notes_count
       expose :upvotes, :downvotes
+      expose :due_date
     end
 
     class ExternalIssue < Grape::Entity
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 8a03a41e9c592345685ce44e96375a82923387f6..c588103e517eb05894ba94b7d0d9292786004a09 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -152,12 +152,13 @@ def create_spam_log(project, current_user, attrs)
       #   milestone_id (optional) - The ID of a milestone to assign issue
       #   labels (optional)       - The labels of an issue
       #   created_at (optional)   - Date time string, ISO 8601 formatted
+      #   due_date (optional)     - Date time string in the format YEAR-MONTH-DAY
       # Example Request:
       #   POST /projects/:id/issues
-      post ":id/issues" do
+      post ':id/issues' do
         required_attributes! [:title]
 
-        keys = [:title, :description, :assignee_id, :milestone_id]
+        keys = [:title, :description, :assignee_id, :milestone_id, :due_date]
         keys << :created_at if current_user.admin? || user_project.owner == current_user
         attrs = attributes_for_keys(keys)
 
@@ -201,12 +202,13 @@ def create_spam_log(project, current_user, attrs)
       #   labels (optional) - The labels of an issue
       #   state_event (optional) - The state event of an issue (close|reopen)
       #   updated_at (optional) - Date time string, ISO 8601 formatted
+      #   due_date (optional)     - Date time string in the format YEAR-MONTH-DAY
       # Example Request:
       #   PUT /projects/:id/issues/:issue_id
-      put ":id/issues/:issue_id" do
+      put ':id/issues/:issue_id' do
         issue = user_project.issues.find(params[:issue_id])
         authorize! :update_issue, issue
-        keys = [:title, :description, :assignee_id, :milestone_id, :state_event]
+        keys = [:title, :description, :assignee_id, :milestone_id, :state_event, :due_date]
         keys << :updated_at if current_user.admin? || user_project.owner == current_user
         attrs = attributes_for_keys(keys)
 
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 6adccb4ebae9348f8d7e928b602a70b68267b2ef..12f2cfa69426d4dce431f72ebcd0a70792c4a0d1 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -503,6 +503,20 @@
       ])
     end
 
+    context 'with due date' do
+      it 'creates a new project issue' do
+        due_date = 2.weeks.from_now.strftime('%Y-%m-%d')
+
+        post api("/projects/#{project.id}/issues", user),
+          title: 'new issue', due_date: due_date
+
+        expect(response).to have_http_status(201)
+        expect(json_response['title']).to eq('new issue')
+        expect(json_response['description']).to be_nil
+        expect(json_response['due_date']).to eq(due_date)
+      end
+    end
+
     context 'when an admin or owner makes the request' do
       it 'accepts the creation date to be set' do
         creation_time = 2.weeks.ago
@@ -683,6 +697,17 @@
     end
   end
 
+  describe 'PUT /projects/:id/issues/:issue_id to update due date' do
+    it 'creates a new project issue' do
+      due_date = 2.weeks.from_now.strftime('%Y-%m-%d')
+
+      put api("/projects/#{project.id}/issues/#{issue.id}", user), due_date: due_date
+
+      expect(response).to have_http_status(200)
+      expect(json_response['due_date']).to eq(due_date)
+    end
+  end
+
   describe "DELETE /projects/:id/issues/:issue_id" do
     it "rejects a non member from deleting an issue" do
       delete api("/projects/#{project.id}/issues/#{issue.id}", non_member)