diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index c26d40c57037dd67fd29816e24e5153a5d758910..354a95e9a93a1c62f506e745194ca97d8951adc9 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -91,7 +91,7 @@ class MergeRequest < ActiveRecord::Base
 
   def validate_branches
     if target_branch == source_branch
-      errors.add :base, "You can not use same branch for source and target branches"
+      errors.add :branch_conflict, "You can not use same branch for source and target branches"
     end
   end
 
diff --git a/app/models/project.rb b/app/models/project.rb
index 02f1df13f9cc44fc186b0d2bbe1c564ac99af1a7..07ba7fc369eb3e0ef57271b0f9c3cdc93d258137 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -160,7 +160,7 @@ class Project < ActiveRecord::Base
 
   def check_limit
     unless creator.can_create_project?
-      errors[:base] << ("Your own projects limit is #{creator.projects_limit}! Please contact administrator to increase it")
+      errors[:limit_reached] << ("Your own projects limit is #{creator.projects_limit}! Please contact administrator to increase it")
     end
   rescue
     errors[:base] << ("Can't check your ability to create project")
diff --git a/config/routes.rb b/config/routes.rb
index 3550636c91c91dd5592292baf10b035f125c2d9c..b06fda8f85da6087b41bae6b8ded69e8ee0a76cc 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -8,6 +8,7 @@ Gitlab::Application.routes.draw do
 
   # API
   require 'api'
+  Gitlab::API.logger Rails.logger
   mount Gitlab::API => '/api'
 
   constraint = lambda { |request| request.env["warden"].authenticate? and request.env['warden'].user.admin? }
diff --git a/doc/api/README.md b/doc/api/README.md
index 0618db7e369b6e5c11428fce6672d696b05526f1..f6c4e41b6cdbb3b20fd992242de45f91ce842f97 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -1,6 +1,6 @@
 # GitLab API
 
-All API requests require authentication. You need to pass a `private_token` parameter by url or header. You can find or reset your private token in your profile.
+All API requests require authentication. You need to pass a `private_token` parameter by url or header. If passed as header, the header name must be "PRIVATE-TOKEN" (capital and with dash instead of underscore). You can find or reset your private token in your profile.
 
 If no, or an invalid, `private_token` is provided then an error message will be returned with status code 401:
 
@@ -18,8 +18,48 @@ Example of a valid API request:
 GET http://example.com/api/v3/projects?private_token=QVy1PB7sTxfy4pqfZM1U
 ```
 
+Example for a valid API request using curl and authentication via header:
+
+```
+curl --header "PRIVATE-TOKEN: QVy1PB7sTxfy4pqfZM1U" "http://example.com/api/v3/projects"
+```
+
+
 The API uses JSON to serialize data. You don't need to specify `.json` at the end of API URL.
 
+
+
+## Status codes
+
+The API is designed to return different status codes according to context and action. In this way
+if a request results in an error the caller is able to get insight into what went wrong, e.g.
+status code `400 Bad Request` is returned if a required attribute is missing from the request.
+The following list gives an overview of how the API functions generally behave.
+
+API request types:
+
+* `GET` requests access one or more resources and return the result as JSON
+* `POST` requests return `201 Created` if the resource is successfully created and return the newly created resource as JSON
+* `GET`, `PUT` and `DELETE` return `200 Ok` if the resource is accessed, modified or deleted successfully, the (modified) result is returned as JSON
+* `DELETE` requests are designed to be idempotent, meaning a request a resource still returns `200 Ok` even it was deleted before or is not available. The reasoning behind it is the user is not really interested if the resource existed before or not.
+
+
+The following list shows the possible return codes for API requests.
+
+Return values:
+
+* `200 Ok` - The `GET`, `PUT` or `DELETE` request was successful, the resource(s) itself is returned as JSON
+* `201 Created` - The `POST` request was successful and the resource is returned as JSON
+* `400 Bad Request` - A required attribute of the API request is missing, e.g. the title of an issue is not given
+* `401 Unauthorized` - The user is not authenticated, a valid user token is necessary, see above
+* `403 Forbidden` - The request is not allowed, e.g. the user is not allowed to delete a project
+* `404 Not Found` - A resource could not be accessed, e.g. an ID for a resource could not be found
+* `405 Method Not Allowed` - The request is not supported
+* `409 Conflict` - A conflicting resource already exists, e.g. creating a project with a name that already exists
+* `500 Server Error` - While handling the request something went wrong on the server side
+
+
+
 #### Pagination
 
 When listing resources you can pass the following parameters:
diff --git a/doc/api/groups.md b/doc/api/groups.md
index 4cde66b1726883aa2862f14d2ad48709dd05714d..e9702ea2cd16c8a92a7d53347f77126a7f2fb80f 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -17,7 +17,8 @@ GET /groups
 ]
 ```
 
-## Details of group
+
+## Details of a group
 
 Get all details of a group.
 
@@ -29,19 +30,19 @@ Parameters:
 
 + `id` (required) - The ID of a group
 
+
 ## New group
 
-Create a new project group. Available only for admin
+Creates a new project group. Available only for admin.
 
 ```
 POST /groups
 ```
 
 Parameters:
-+ `name` (required)                  - Email
-+ `path`                             - Password
 
-Will return created group with status `201 Created` on success, or `404 Not found` on fail.
++ `name` (required) - The name of the group
++ `path` (required) - The path of the group
 
 ## Transfer project to group
 
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 0383b6760736326ee29fb1aaa06bcd9765be9b23..a8ae7401b3947fe21e4db402db420a94a035db9f 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -1,6 +1,7 @@
 ## List issues
 
-Get all issues created by authenticed user.
+Get all issues created by authenticed user. This function takes pagination parameters
+`page` and `per_page` to restrict the list of issues.
 
 ```
 GET /issues
@@ -68,9 +69,11 @@ GET /issues
 ]
 ```
 
+
 ## List project issues
 
-Get a list of project issues.
+Get a list of project issues. This function accepts pagination parameters `page` and `per_page`
+to return the list of project issues.
 
 ```
 GET /projects/:id/issues
@@ -80,9 +83,10 @@ Parameters:
 
 + `id` (required) - The ID of a project
 
+
 ## Single issue
 
-Get a project issue.
+Gets a single project issue.
 
 ```
 GET /projects/:id/issues/:issue_id
@@ -133,9 +137,10 @@ Parameters:
 }
 ```
 
+
 ## New issue
 
-Create a new project issue.
+Creates a new project issue.
 
 ```
 POST /projects/:id/issues
@@ -150,11 +155,10 @@ Parameters:
 + `milestone_id` (optional) - The ID of a milestone to assign issue
 + `labels` (optional) - Comma-separated label names for an issue
 
-Will return created issue with status `201 Created` on success, or `404 Not found` on fail.
 
 ## Edit issue
 
-Update an existing project issue.
+Updates an existing project issue. This function is also used to mark an issue as closed.
 
 ```
 PUT /projects/:id/issues/:issue_id
@@ -171,5 +175,19 @@ Parameters:
 + `labels` (optional) - Comma-separated label names for an issue
 + `closed` (optional) - The state of an issue (0 = false, 1 = true)
 
-Will return updated issue with status `200 OK` on success, or `404 Not found` on fail.
+
+## Delete existing issue (**Deprecated**)
+
+The function is deprecated and returns a `405 Method Not Allowed`
+error if called. An issue gets now closed and is done by calling `PUT /projects/:id/issues/:issue_id` with
+parameter `closed` set to 1.
+
+```
+DELETE /projects/:id/issues/:issue_id
+```
+
+Parameters:
+
++ `id` (required) - The project ID
++ `issue_id` (required) - The ID of the issue
 
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 525c55d12c2581167015c7212a4ff6260bfcbffc..111c52112ebc806c8a70a1adc1e336160176a930 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -1,6 +1,7 @@
 ## List merge requests
 
-Get all MR for this project.
+Get all merge requests for this project. This function takes pagination parameters
+`page` and `per_page` to restrict the list of merge requests.
 
 ```
 GET /projects/:id/merge_requests
@@ -40,9 +41,10 @@ Parameters:
 ]
 ```
 
-## Show MR
 
-Show information about MR.
+## Get single MR
+
+Shows information about a single merge request.
 
 ```
 GET /projects/:id/merge_request/:merge_request_id
@@ -84,7 +86,7 @@ Parameters:
 
 ## Create MR
 
-Create MR.
+Creates a new merge request.
 
 ```
 POST /projects/:id/merge_requests
@@ -126,9 +128,10 @@ Parameters:
 }
 ```
 
+
 ## Update MR
 
-Update MR. You can change branches, title, or even close the MR.
+Updates an existing merge request. You can change branches, title, or even close the MR.
 
 ```
 PUT /projects/:id/merge_request/:merge_request_id
@@ -172,9 +175,11 @@ Parameters:
     }
 }
 ```
+
+
 ## Post comment to MR
 
-Post comment to MR
+Adds a comment to a merge request.
 
 ```
 POST /projects/:id/merge_request/:merge_request_id/comments
@@ -183,10 +188,9 @@ POST /projects/:id/merge_request/:merge_request_id/comments
 Parameters:
 
 + `id` (required) - The ID of a project
-+ `merge_request_id` (required) - ID of MR
++ `merge_request_id` (required) - ID of merge request
 + `note` (required) - Text of comment
 
-Will return created note with status `201 Created` on success, or `404 Not found` on fail.
 
 ```json
 {
diff --git a/doc/api/milestones.md b/doc/api/milestones.md
index 73d29afc37ac36cf06dfb10170d6acacbb5f66f9..92a29cee954848a73ba45e928566f15676846bc4 100644
--- a/doc/api/milestones.md
+++ b/doc/api/milestones.md
@@ -1,6 +1,6 @@
 ## List project milestones
 
-Get a list of project milestones.
+Returns a list of project milestones.
 
 ```
 GET /projects/:id/milestones
@@ -10,9 +10,10 @@ Parameters:
 
 + `id` (required) - The ID of a project
 
-## Single milestone
 
-Get a single project milestone.
+## Get single milestone
+
+Gets a single project milestone.
 
 ```
 GET /projects/:id/milestones/:milestone_id
@@ -23,9 +24,10 @@ Parameters:
 + `id` (required) - The ID of a project
 + `milestone_id` (required) - The ID of a project milestone
 
-## New milestone
 
-Create a new project milestone.
+## Create new milestone
+
+Creates a new project milestone.
 
 ```
 POST /projects/:id/milestones
@@ -38,9 +40,10 @@ Parameters:
 + `description` (optional) - The description of the milestone
 + `due_date` (optional) - The due date of the milestone
 
+
 ## Edit milestone
 
-Update an existing project milestone.
+Updates an existing project milestone.
 
 ```
 PUT /projects/:id/milestones/:milestone_id
@@ -54,3 +57,4 @@ Parameters:
 + `description` (optional) - The description of a milestone
 + `due_date` (optional) - The due date of the milestone
 + `closed` (optional) - The status of the milestone
+
diff --git a/doc/api/notes.md b/doc/api/notes.md
index a4ba282607643d6f324c9f8767cf337776c50705..4b57f636a0143e6075b2bb761f58a31ffa939d1f 100644
--- a/doc/api/notes.md
+++ b/doc/api/notes.md
@@ -1,4 +1,4 @@
-## List notes
+## Wall
 
 ### List project wall notes
 
@@ -30,22 +30,40 @@ Parameters:
 
 + `id` (required) - The ID of a project
 
-### List merge request notes
 
-Get a list of merge request notes.
+### Get single wall note
+
+Returns a single wall note.
 
 ```
-GET /projects/:id/merge_requests/:merge_request_id/notes
+GET /projects/:id/notes/:note_id
 ```
 
 Parameters:
 
 + `id` (required) - The ID of a project
-+ `merge_request_id` (required) - The ID of an merge request
++ `note_id` (required) - The ID of a wall note
 
-### List issue notes
 
-Get a list of issue notes.
+### Create new wall note
+
+Creates a new wall note.
+
+```
+POST /projects/:id/notes
+```
+
+Parameters:
+
++ `id` (required) - The ID of a project
++ `body` (required) - The content of a note
+
+
+## Issues
+
+### List project issue notes
+
+Gets a list of all notes for a single issue.
 
 ```
 GET /projects/:id/issues/:issue_id/notes
@@ -56,54 +74,59 @@ Parameters:
 + `id` (required) - The ID of a project
 + `issue_id` (required) - The ID of an issue
 
-### List snippet notes
 
-Get a list of snippet notes.
+### Get single issue note
+
+Returns a single note for a specific project issue
 
 ```
-GET /projects/:id/snippets/:snippet_id/notes
+GET /projects/:id/issues/:issue_id/notes/:note_id
 ```
 
 Parameters:
 
 + `id` (required) - The ID of a project
-+ `snippet_id` (required) - The ID of a snippet
++ `issue_id` (required) - The ID of a project issue
++ `note_id` (required) - The ID of an issue note
 
-## Single note
 
-### Single wall note
+### Create new issue note
 
-Get a wall note.
+Creates a new note to a single project issue.
 
 ```
-GET /projects/:id/notes/:note_id
+POST /projects/:id/issues/:issue_id/notes
 ```
 
 Parameters:
 
 + `id` (required) - The ID of a project
-+ `note_id` (required) - The ID of a wall note
++ `issue_id` (required) - The ID of an issue
++ `body` (required) - The content of a note
 
-### Single issue note
 
-Get an issue note.
+## Snippets
+
+### List all snippet notes
+
+Gets a list of all notes for a single snippet. Snippet notes are comments users can post to a snippet.
 
 ```
-GET /projects/:id/issues/:issue_id/:notes/:note_id
+GET /projects/:id/snippets/:snippet_id/notes
 ```
 
 Parameters:
 
 + `id` (required) - The ID of a project
-+ `issue_id` (required) - The ID of a project issue
-+ `note_id` (required) - The ID of an issue note
++ `snippet_id` (required) - The ID of a project snippet
+
 
-### Single snippet note
+### Get single snippet note
 
-Get a snippet note.
+Returns a single note for a given snippet.
 
 ```
-GET /projects/:id/issues/:snippet_id/:notes/:note_id
+GET /projects/:id/snippets/:snippet_id/notes/:note_id
 ```
 
 Parameters:
@@ -112,52 +135,64 @@ Parameters:
 + `snippet_id` (required) - The ID of a project snippet
 + `note_id` (required) - The ID of an snippet note
 
-## New note
 
-### New wall note
+### Create new snippet note
 
-Create a new wall note.
+Creates a new note for a single snippet. Snippet notes are comments users can post to a snippet.
 
 ```
-POST /projects/:id/notes
+POST /projects/:id/snippets/:snippet_id/notes
 ```
 
 Parameters:
 
 + `id` (required) - The ID of a project
++ `snippet_id` (required) - The ID of an snippet
 + `body` (required) - The content of a note
 
-Will return created note with status `201 Created` on success, or `404 Not found` on fail.
 
+## Merge Requests
 
-### New issue note
+### List all merge request notes
 
-Create a new issue note.
+Gets a list of all notes for a single merge request.
 
 ```
-POST /projects/:id/issues/:issue_id/notes
+GET /projects/:id/merge_requests/:merge_request_id/notes
 ```
 
 Parameters:
 
 + `id` (required) - The ID of a project
-+ `issue_id` (required) - The ID of an issue
-+ `body` (required) - The content of a note
++ `merge_request_id` (required) - The ID of a project merge request
 
-Will return created note with status `201 Created` on success, or `404 Not found` on fail.
 
-### New snippet note
+### Get single merge request note
 
-Create a new snippet note.
+Returns a single note for a given merge request.
 
 ```
-POST /projects/:id/snippets/:snippet_id/notes
+GET /projects/:id/merge_requests/:merge_request_id/notes/:note_id
 ```
 
 Parameters:
 
 + `id` (required) - The ID of a project
-+ `snippet_id` (required) - The ID of an snippet
++ `merge_request_id` (required) - The ID of a project merge request
++ `note_id` (required) - The ID of a merge request note
+
+
+### Create new merge request note
+
+Creates a new note for a single merge request.
+
+```
+POST /projects/:id/merge_requests/:merge_request_id/notes
+```
+
+Parameters:
+
++ `id` (required) - The ID of a project
++ `merge_request_id` (required) - The ID of a merge request
 + `body` (required) - The content of a note
 
-Will return created note with status `201 Created` on success, or `404 Not found` on fail.
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 4cbefbb6189a6bf278d1aab98c2b7606552d0922..d6a9a8854ca8ec79d25e9735cee6d8b7b23b0f29 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -1,4 +1,6 @@
-## List projects
+## Projects
+
+### List projects
 
 Get a list of projects owned by the authenticated user.
 
@@ -55,9 +57,11 @@ GET /projects
 ]
 ```
 
-## Single project
 
-Get a specific project, identified by project ID, which is owned by the authentication user.
+### Get single project
+
+Get a specific project, identified by project ID or NAME, which is owned by the authentication user.
+Currently namespaced projects cannot retrieved by name.
 
 ```
 GET /projects/:id
@@ -65,7 +69,7 @@ GET /projects/:id
 
 Parameters:
 
-+ `id` (required) - The ID of a project
++ `id` (required) - The ID or NAME of a project
 
 ```json
 {
@@ -92,9 +96,10 @@ Parameters:
 }
 ```
 
-## Create project
 
-Create new project owned by user
+### Create project
+
+Creates new project owned by user.
 
 ```
 POST /projects
@@ -110,12 +115,21 @@ Parameters:
 + `merge_requests_enabled` (optional) - enabled by default
 + `wiki_enabled` (optional) - enabled by default
 
-Will return created project with status `201 Created` on success, or `404 Not
-found` on fail.
+**Project access levels**
 
-## Create project for user
+The project access levels are defined in the `user_project.rb` class. Currently, these levels are recoginized:
+
+```
+  GUEST     = 10
+  REPORTER  = 20
+  DEVELOPER = 30
+  MASTER    = 40
+```
 
-Create new project owned by user. Available only for admin
+
+### Create project for user
+
+Creates a new project owned by user. Available only for admins.
 
 ```
 POST /projects/user/:user_id
@@ -132,10 +146,11 @@ Parameters:
 + `merge_requests_enabled` (optional) - enabled by default
 + `wiki_enabled` (optional) - enabled by default
 
-Will return created project with status `201 Created` on success, or `404 Not
-found` on fail.
 
-## List project team members
+
+## Team members
+
+### List project team members
 
 Get a list of project team members.
 
@@ -145,12 +160,13 @@ GET /projects/:id/members
 
 Parameters:
 
-+ `id` (required) - The ID of a project
-+ `query`         - Query string
++ `id` (required) - The ID or NAME of a project
++ `query` (optional) - Query string to search for members
+
 
-## Get project team member
+### Get project team member
 
-Get a project team member.
+Gets a project team member.
 
 ```
 GET /projects/:id/members/:user_id
@@ -158,12 +174,11 @@ GET /projects/:id/members/:user_id
 
 Parameters:
 
-+ `id` (required) - The ID of a project
++ `id` (required) - The ID or NAME of a project
 + `user_id` (required) - The ID of a user
 
 ```json
 {
-
   "id": 1,
   "username": "john_smith",
   "email": "john@example.com",
@@ -174,9 +189,12 @@ Parameters:
 }
 ```
 
-## Add project team member
 
-Add a user to a project team.
+### Add project team member
+
+Adds a user to a project team. This is an idempotent method and can be called multiple times
+with the same parameters. Adding team membership to a user that is already a member does not
+affect the existing membership.
 
 ```
 POST /projects/:id/members
@@ -184,15 +202,14 @@ POST /projects/:id/members
 
 Parameters:
 
-+ `id` (required) - The ID of a project
++ `id` (required) - The ID or NAME of a project
 + `user_id` (required) - The ID of a user to add
 + `access_level` (required) - Project access level
 
-Will return status `201 Created` on success, or `404 Not found` on fail.
 
-## Edit project team member
+### Edit project team member
 
-Update project team member to specified access level.
+Updates project team member to a specified access level.
 
 ```
 PUT /projects/:id/members/:user_id
@@ -200,13 +217,12 @@ PUT /projects/:id/members/:user_id
 
 Parameters:
 
-+ `id` (required) - The ID of a project
++ `id` (required) - The ID or NAME of a project
 + `user_id` (required) - The ID of a team member
 + `access_level` (required) - Project access level
 
-Will return status `200 OK` on success, or `404 Not found` on fail.
 
-## Remove project team member
+### Remove project team member
 
 Removes user from project team.
 
@@ -216,14 +232,20 @@ DELETE /projects/:id/members/:user_id
 
 Parameters:
 
-+ `id` (required) - The ID of a project
++ `id` (required) - The ID or NAME of a project
 + `user_id` (required) - The ID of a team member
 
-Status code `200` will be returned on success.
+This method is idempotent and can be called multiple times with the same parameters.
+Revoking team membership for a user who is not currently a team member is considered success.
+Please note that the returned JSON currently differs slightly. Thus you should not
+rely on the returned JSON structure.
+
 
-## List project hooks
+## Hooks
 
-Get list for project hooks
+### List project hooks
+
+Get list of project hooks.
 
 ```
 GET /projects/:id/hooks
@@ -231,13 +253,12 @@ GET /projects/:id/hooks
 
 Parameters:
 
-+ `id` (required) - The ID of a project
++ `id` (required) - The ID or NAME of a project
 
-Will return hooks with status `200 OK` on success, or `404 Not found` on fail.
 
-## Get project hook
+### Get project hook
 
-Get hook for project
+Get a specific hook for project.
 
 ```
 GET /projects/:id/hooks/:hook_id
@@ -245,14 +266,21 @@ GET /projects/:id/hooks/:hook_id
 
 Parameters:
 
-+ `id` (required) - The ID of a project
++ `id` (required) - The ID or NAME of a project
 + `hook_id` (required) - The ID of a project hook
 
-Will return hook with status `200 OK` on success, or `404 Not found` on fail.
+```json
+{
+  "id": 1,
+  "url": "http://example.com/hook",
+  "created_at": "2012-10-12T17:04:47Z"
+}
+```
 
-## Add project hook
 
-Add hook to project
+### Add project hook
+
+Adds a hook to project.
 
 ```
 POST /projects/:id/hooks
@@ -260,14 +288,13 @@ POST /projects/:id/hooks
 
 Parameters:
 
-+ `id` (required) - The ID of a project
++ `id` (required) - The ID or NAME of a project
 + `url` (required) - The hook URL
 
-Will return status `201 Created` on success, or `404 Not found` on fail.
 
-## Edit project hook
+### Edit project hook
 
-Edit hook for project
+Edits a hook for project.
 
 ```
 PUT /projects/:id/hooks/:hook_id
@@ -275,30 +302,125 @@ PUT /projects/:id/hooks/:hook_id
 
 Parameters:
 
-+ `id` (required) - The ID of a project
++ `id` (required) - The ID or NAME of a project
 + `hook_id` (required) - The ID of a project hook
 + `url` (required) - The hook URL
 
-Will return status `201 Created` on success, or `404 Not found` on fail.
-
 
-## Delete project hook
+### Delete project hook
 
-Delete hook from project
+Removes a hook from project. This is an idempotent method and can be called multiple times.
+Either the hook is available or not.
 
 ```
-DELETE /projects/:id/hooks/:hook_id
+DELETE /projects/:id/hooks/
 ```
 
 Parameters:
 
-+ `id` (required) - The ID of a project
++ `id` (required) - The ID or NAME of a project
 + `hook_id` (required) - The ID of hook to delete
 
-Will return status `200 OK` on success, or `404 Not found` on fail.
+Note the JSON response differs if the hook is available or not. If the project hook
+is available before it is returned in the JSON response or an empty response is returned.
 
 
-## List deploy keys
+## Branches
+
+### List branches
+
+Lists all branches of a project.
+
+```
+GET /projects/:id/repository/branches
+```
+
+Parameters:
+
++ `id` (required) - The ID of the project
+
+
+### List single branch
+
+Lists a specific branch of a project.
+
+```
+GET /projects/:id/repository/branches/:branch
+```
+
+Parameters:
+
++ `id` (required) - The ID of the project.
++ `branch` (required) - The name of the branch.
+
+
+### Protect single branch
+
+Protects a single branch of a project.
+
+```
+PUT /projects/:id/repository/branches/:branch/protect
+```
+
+Parameters:
+
++ `id` (required) - The ID of the project.
++ `branch` (required) - The name of the branch.
+
+
+### Unprotect single branch
+
+Unprotects a single branch of a project.
+
+```
+PUT /projects/:id/repository/branches/:branch/unprotect
+```
+
+Parameters:
+
++ `id` (required) - The ID of the project.
++ `branch` (required) - The name of the branch.
+
+
+### List tags
+
+Lists all tags of a project.
+
+```
+GET /projects/:id/repository/tags
+```
+
+Parameters:
+
++ `id` (required) - The ID of the project
+
+
+### List commits
+
+Lists all commits with pagination. If the optional `ref_name` name is not given the commits of
+the default branch (usually master) are returned.
+
+```
+GET /projects/:id/repository/commits
+```
+
+Parameters:
+
++ `id` (required) - The Id of the project
++ `ref_name` (optional) - The name of a repository branch or tag
++ `page` (optional) - The page of commits to return (`0` default)
++ `per_page` (optional) - The number of commits per page (`20` default)
+
+Returns values:
+
++ `200 Ok` on success and a list with commits
++ `404 Not Found` if project with id or the branch with `ref_name` not found
+
+
+
+## Deploy Keys
+
+### List deploy keys
 
 Get a list of a project's deploy keys.
 
@@ -306,6 +428,10 @@ Get a list of a project's deploy keys.
 GET /projects/:id/keys
 ```
 
+Parameters:
+
++ `id` (required) - The ID of the project
+
 ```json
 [
   {
@@ -325,7 +451,8 @@ GET /projects/:id/keys
 ]
 ```
 
-## Single deploy key
+
+### Single deploy key
 
 Get a single key.
 
@@ -335,7 +462,8 @@ GET /projects/:id/keys/:key_id
 
 Parameters:
 
-+ `id` (required) - The ID of an deploy key
++ `id` (required) - The ID of the project
++ `key_id` (required) - The ID of the deploy key
 
 ```json
 {
@@ -346,9 +474,11 @@ Parameters:
       soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0="
 }
 ```
-## Add deploy key
 
-Create new deploy key for a project
+
+### Add deploy key
+
+Creates a new deploy key for a project.
 
 ```
 POST /projects/:id/keys
@@ -356,13 +486,12 @@ POST /projects/:id/keys
 
 Parameters:
 
-+ `title` (required) - new deploy key's title
-+ `key` (required) - new deploy key
++ `id` (required) - The ID of the project
++ `title` (required) - New deploy key's title
++ `key` (required) - New deploy key
 
-Will return created key with status `201 Created` on success, or `404 Not
-found` on fail.
 
-## Delete deploy key
+### Delete deploy key
 
 Delete a deploy key from a project
 
@@ -372,6 +501,6 @@ DELETE /projects/:id/keys/:key_id
 
 Parameters:
 
-+ `id` (required) - Deploy key ID
++ `id` (required) - The ID of the project
++ `key_id` (required) - The ID of the deploy key
 
-Will return `200 OK` on success, or `404 Not Found` on fail.
diff --git a/doc/api/repositories.md b/doc/api/repositories.md
index fd0ef1f53eb51aa218630828367d741097091aeb..90fda387947dd15e04634107a7541634fbf72465 100644
--- a/doc/api/repositories.md
+++ b/doc/api/repositories.md
@@ -1,4 +1,4 @@
-## Project repository branches
+## List repository branches
 
 Get a list of repository branches from a project, sorted by name alphabetically.
 
@@ -39,7 +39,8 @@ Parameters:
 ]
 ```
 
-## Project repository branch
+
+## Get single repository branch
 
 Get a single project repository branch.
 
@@ -79,12 +80,11 @@ Parameters:
 }
 ```
 
-Will return status code `200` on success or `404 Not found` if the branch is not available.
-
 
-## Protect a project repository branch
+## Protect repository branch
 
-Protect a single project repository branch.
+Protects a single project repository branch. This is an idempotent function, protecting an already
+protected repository branch still returns a `200 Ok` status code.
 
 ```
 PUT /projects/:id/repository/branches/:branch/protect
@@ -122,9 +122,11 @@ Parameters:
 }
 ```
 
-## Unprotect a project repository branch
 
-Unprotect a single project repository branch.
+## Unprotect repository branch
+
+Unprotects a single project repository branch. This is an idempotent function, unprotecting an already
+unprotected repository branch still returns a `200 Ok` status code.
 
 ```
 PUT /projects/:id/repository/branches/:branch/unprotect
@@ -162,7 +164,8 @@ Parameters:
 }
 ```
 
-## Project repository tags
+
+## List project repository tags
 
 Get a list of repository tags from a project, sorted by name in reverse alphabetical order.
 
@@ -201,7 +204,8 @@ Parameters:
 ]
 ```
 
-## Project repository commits
+
+## List repository commits
 
 Get a list of repository commits in a project.
 
@@ -212,7 +216,7 @@ GET /projects/:id/repository/commits
 Parameters:
 
 + `id` (required) - The ID of a project
-+ `ref_name` (optional) - The name of a repository branch or tag
++ `ref_name` (optional) - The name of a repository branch or tag or if not given the default branch
 
 ```json
 [
@@ -235,6 +239,7 @@ Parameters:
 ]
 ```
 
+
 ## Raw blob content
 
 Get the raw file contents for a file.
@@ -248,5 +253,3 @@ Parameters:
 + `id` (required) - The ID of a project
 + `sha` (required) - The commit or branch name
 + `filepath` (required) - The path the file
-
-Will return the raw file contents.
diff --git a/doc/api/snippets.md b/doc/api/snippets.md
index ceb8a63d06fb6591efac268a4a32670ac54a0819..04ea367d51807cf1033f230e5f9a0a8ed041df49 100644
--- a/doc/api/snippets.md
+++ b/doc/api/snippets.md
@@ -10,9 +10,10 @@ Parameters:
 
 + `id` (required) - The ID of a project
 
+
 ## Single snippet
 
-Get a project snippet.
+Get a single project snippet.
 
 ```
 GET /projects/:id/snippets/:snippet_id
@@ -42,22 +43,10 @@ Parameters:
 }
 ```
 
-## Snippet content
-
-Get a raw project snippet.
-
-```
-GET /projects/:id/snippets/:snippet_id/raw
-```
-
-Parameters:
-
-+ `id` (required) - The ID of a project
-+ `snippet_id` (required) - The ID of a project's snippet
 
-## New snippet
+## Create new snippet
 
-Create a new project snippet.
+Creates a new project snippet. The user must have permission to create new snippets.
 
 ```
 POST /projects/:id/snippets
@@ -71,11 +60,10 @@ Parameters:
 + `lifetime` (optional) - The expiration date of a snippet
 + `code` (required) - The content of a snippet
 
-Will return created snippet with status `201 Created` on success, or `404 Not found` on fail.
 
-## Edit snippet
+## Update snippet
 
-Update an existing project snippet.
+Updates an existing project snippet. The user must have permission to change an existing snippet.
 
 ```
 PUT /projects/:id/snippets/:snippet_id
@@ -90,11 +78,11 @@ Parameters:
 + `lifetime` (optional) - The expiration date of a snippet
 + `code` (optional) - The content of a snippet
 
-Will return updated snippet with status `200 OK` on success, or `404 Not found` on fail.
 
 ## Delete snippet
 
-Delete existing project snippet.
+Deletes an existing project snippet. This is an idempotent function and deleting a non-existent
+snippet still returns a `200 Ok` status code.
 
 ```
 DELETE /projects/:id/snippets/:snippet_id
@@ -105,5 +93,16 @@ Parameters:
 + `id` (required) - The ID of a project
 + `snippet_id` (required) - The ID of a project's snippet
 
-Status code `200` will be returned on success.
 
+## Snippet content
+
+Returns the raw project snippet as plain text.
+
+```
+GET /projects/:id/snippets/:snippet_id/raw
+```
+
+Parameters:
+
++ `id` (required) - The ID of a project
++ `snippet_id` (required) - The ID of a project's snippet
diff --git a/doc/api/users.md b/doc/api/users.md
index b75e84c6b965519c7bf395a81dca01f7cc57e4da..dc31c10eb9dae470f573b7fecb853a754f799240 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -43,6 +43,7 @@ GET /users
 ]
 ```
 
+
 ## Single user
 
 Get a single user.
@@ -74,37 +75,40 @@ Parameters:
 }
 ```
 
+
 ## User creation
-Create user. Available only for admin
+
+Creates a new user. Note only administrators can create new users.
 
 ```
 POST /users
 ```
 
 Parameters:
-+ `email` (required)                  - Email
-+ `password` (required)               - Password
-+ `username` (required)               - Username
-+ `name` (required)                   - Name
-+ `skype`                             - Skype ID
-+ `linkedin`                          - Linkedin
-+ `twitter`                           - Twitter account
-+ `projects_limit`                    - Number of projects user can create
-+ `extern_uid`                        - External UID
-+ `provider`                          - External provider name
-+ `bio`                               - User's bio
 
-Will return created user with status `201 Created` on success, or `404 Not
-found` on fail.
++ `email` (required)          - Email
++ `password` (required)       - Password
++ `username` (required)       - Username
++ `name` (required)           - Name
++ `skype` (optional)          - Skype ID
++ `linkedin` (optional)       - Linkedin
++ `twitter` (optional)        - Twitter account
++ `projects_limit` (optional) - Number of projects user can create
++ `extern_uid` (optional)     - External UID
++ `provider` (optional)       - External provider name
++ `bio` (optional)            - User's bio
+
 
 ## User modification
-Modify user. Available only for admin
+
+Modifies an existing user. Only administrators can change attributes of a user.
 
 ```
 PUT /users/:id
 ```
 
 Parameters:
+
 + `email`                             - Email
 + `username`                          - Username
 + `name`                              - Name
@@ -117,23 +121,28 @@ Parameters:
 + `provider`                          - External provider name
 + `bio`                               - User's bio
 
+Note, at the moment this method does only return a 404 error, even in cases where a 409 (Conflict) would
+be more appropriate, e.g. when renaming the email address to some exsisting one.
 
-Will return created user with status `200 OK` on success, or `404 Not
-found` on fail.
 
 ## User deletion
-Delete user. Available only for admin
+
+Deletes a user. Available only for administrators. This is an idempotent function, calling this function
+for a non-existent user id still returns a status code `200 Ok`. The JSON response differs if the user
+was actually deleted or not. In the former the user is returned and in the latter not.
 
 ```
 DELETE /users/:id
 ```
 
-Will return deleted user with status `200 OK` on success, or `404 Not
-found` on fail.
+Parameters:
+
++ `id` (required) - The ID of the user
+
 
 ## Current user
 
-Get currently authenticated user.
+Gets currently authenticated user.
 
 ```
 GET /user
@@ -156,6 +165,7 @@ GET /user
 }
 ```
 
+
 ## List SSH keys
 
 Get a list of currently authenticated user's SSH keys.
@@ -183,6 +193,11 @@ GET /user/keys
 ]
 ```
 
+Parameters:
+
++ **none**
+
+
 ## Single SSH key
 
 Get a single key.
@@ -204,9 +219,11 @@ Parameters:
       soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0="
 }
 ```
+
+
 ## Add SSH key
 
-Create new key owned by currently authenticated user
+Creates a new key owned by the currently authenticated user.
 
 ```
 POST /user/keys
@@ -217,8 +234,6 @@ Parameters:
 + `title` (required) - new SSH Key's title
 + `key` (required) - new SSH key
 
-Will return created key with status `201 Created` on success, or `404 Not
-found` on fail.
 
 ## Add SSH key for user
 
@@ -239,7 +254,8 @@ found` on fail.
 
 ## Delete SSH key
 
-Delete key owned by currently authenticated user
+Deletes key owned by currently authenticated user. This is an idempotent function and calling it on a key that is already
+deleted or not available results in `200 Ok`.
 
 ```
 DELETE /user/keys/:id
@@ -249,4 +265,3 @@ Parameters:
 
 + `id` (required) - SSH key ID
 
-Will return `200 OK` on success, or `404 Not Found` on fail.
diff --git a/lib/api.rb b/lib/api.rb
index 2a9a0eb2842ab7000b9660360625a65cab2bbb16..d241f9b7479e4268bd84e4ae7547e1587f5822ee 100644
--- a/lib/api.rb
+++ b/lib/api.rb
@@ -8,6 +8,19 @@ module Gitlab
       rack_response({'message' => '404 Not found'}.to_json, 404)
     end
 
+    rescue_from :all do |exception|
+      # lifted from https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb#L60
+      # why is this not wrapped in something reusable?
+      trace = exception.backtrace
+
+      message = "\n#{exception.class} (#{exception.message}):\n"
+      message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
+      message << "  " << trace.join("\n  ")
+
+      API.logger.add Logger::FATAL, message 
+      rack_response({'message' => '500 Internal Server Error'}, 500)
+    end
+
     format :json
     helpers APIHelpers
     
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index 464a2d15662d9cf38ef87a4a42d15ac2f3195a9c..52fa8eff33cec6e122e376584655c5885d2a1d9d 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -20,12 +20,14 @@ module Gitlab
       # Create group. Available only for admin
       #
       # Parameters:
-      #   name (required)                   - Name
-      #   path (required)                   - Path
+      #   name (required) - The name of the group
+      #   path (required) - The path of the group
       # Example Request:
       #   POST /groups
       post do
         authenticated_as_admin!
+        required_attributes! [:name, :path]
+
         attrs = attributes_for_keys [:name, :path]
         @group = Group.new(attrs)
         @group.owner = current_user
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 6bd8111c2b20366c3aef1db626eeb152f480a8dd..f12fb5fdbd0af6ca328aee63a973091cddc40289 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -41,6 +41,17 @@ module Gitlab
       abilities.allowed?(object, action, subject)
     end
 
+    # Checks the occurrences of required attributes, each attribute must be present in the params hash
+    # or a Bad Request error is invoked.
+    #
+    # Parameters:
+    #   keys (required) - A hash consisting of keys that must be present
+    def required_attributes!(keys)
+      keys.each do |key|
+        bad_request!(key) unless params[key].present?
+      end
+    end
+
     def attributes_for_keys(keys)
       attrs = {}
       keys.each do |key|
@@ -55,6 +66,12 @@ module Gitlab
       render_api_error!('403 Forbidden', 403)
     end
 
+    def bad_request!(attribute)
+      message = ["400 (Bad request)"]
+      message << "\"" + attribute.to_s + "\" not given"
+      render_api_error!(message.join(' '), 400)
+    end
+
     def not_found!(resource = nil)
       message = ["404"]
       message << resource if resource
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 70bbf47e72c05618ee78576d976c2afbd64305ff..500a8551f35ebfc36616229dec4745c10b7b90a5 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -48,6 +48,7 @@ module Gitlab
       # Example Request:
       #   POST /projects/:id/issues
       post ":id/issues" do
+        required_attributes! [:title]
         attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id]
         attrs[:label_list] = params[:labels] if params[:labels].present?
         @issue = user_project.issues.new attrs
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 7f763eb49d57555b5e173fd8b777ef22aeaacf14..234a005a99808b6321bf82acf7e85c1bf5a5b1ba 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -4,6 +4,16 @@ module Gitlab
     before { authenticate! }
 
     resource :projects do
+      helpers do
+        def handle_merge_request_errors!(errors)
+          if errors[:project_access].any?
+            error!(errors[:project_access], 422)
+          elsif errors[:branch_conflict].any?
+            error!(errors[:branch_conflict], 422)
+          end
+          not_found!
+        end
+      end
 
       # List merge requests
       #
@@ -51,6 +61,7 @@ module Gitlab
       #
       post ":id/merge_requests" do
         authorize! :write_merge_request, user_project
+        required_attributes! [:source_branch, :target_branch, :title]
 
         attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title]
         merge_request = user_project.merge_requests.new(attrs)
@@ -60,7 +71,7 @@ module Gitlab
           merge_request.reload_code
           present merge_request, with: Entities::MergeRequest
         else
-          not_found!
+          handle_merge_request_errors! merge_request.errors
         end
       end
 
@@ -88,7 +99,7 @@ module Gitlab
           merge_request.mark_as_unchecked
           present merge_request, with: Entities::MergeRequest
         else
-          not_found!
+          handle_merge_request_errors! merge_request.errors
         end
       end
 
@@ -102,6 +113,8 @@ module Gitlab
       #   POST /projects/:id/merge_request/:merge_request_id/comments
       #
       post ":id/merge_request/:merge_request_id/comments" do
+        required_attributes! [:note]
+
         merge_request = user_project.merge_requests.find(params[:merge_request_id])
         note = merge_request.notes.new(note: params[:note], project_id: user_project.id)
         note.author = current_user
diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb
index eaf0d37c18b9af7fbd332947d96c50818decd27e..1adeefece1f2202b5491f471df0ee2b4c73a17da 100644
--- a/lib/api/milestones.rb
+++ b/lib/api/milestones.rb
@@ -41,6 +41,7 @@ module Gitlab
       #   POST /projects/:id/milestones
       post ":id/milestones" do
         authorize! :admin_milestone, user_project
+        required_attributes! [:title]
 
         attrs = attributes_for_keys [:title, :description, :due_date]
         @milestone = user_project.milestones.new attrs
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index 70344d6e3813a2098f14f9f30dd6428375491de8..097cc7ea4752d215bf4a287b2a7b31aa6fe917c7 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -37,12 +37,16 @@ module Gitlab
       # Example Request:
       #   POST /projects/:id/notes
       post ":id/notes" do
+        required_attributes! [:body]
+
         @note = user_project.notes.new(note: params[:body])
         @note.author = current_user
 
         if @note.save
           present @note, with: Entities::Note
         else
+          # :note is exposed as :body, but :note is set on error
+          bad_request!(:note) if @note.errors[:note].any?
           not_found!
         end
       end
@@ -89,6 +93,8 @@ module Gitlab
         #   POST /projects/:id/issues/:noteable_id/notes
         #   POST /projects/:id/snippets/:noteable_id/notes
         post ":id/#{noteables_str}/:#{noteable_id_str}/notes" do
+          required_attributes! [:body]
+
           @noteable = user_project.send(:"#{noteables_str}").find(params[:"#{noteable_id_str}"])
           @note = @noteable.notes.new(note: params[:body])
           @note.author = current_user
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 00b70728c0efca908eea0c5ba36b5adbe824cad1..e82cfeca45d963944557f2801471f061151fda0e 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -4,6 +4,15 @@ module Gitlab
     before { authenticate! }
 
     resource :projects do
+      helpers do
+        def handle_project_member_errors(errors)
+          if errors[:project_access].any?
+            error!(errors[:project_access], 422)
+          end
+          not_found!
+        end
+      end
+
       # Get a projects list for authenticated user
       #
       # Example Request:
@@ -33,9 +42,11 @@ module Gitlab
       #   wall_enabled (optional) - enabled by default
       #   merge_requests_enabled (optional) - enabled by default
       #   wiki_enabled (optional) - enabled by default
+      #   namespace_id (optional) - defaults to user namespace
       # Example Request
       #   POST /projects
       post do
+        required_attributes! [:name]
         attrs = attributes_for_keys [:name,
                                     :description,
                                     :default_branch,
@@ -48,6 +59,9 @@ module Gitlab
         if @project.saved?
           present @project, with: Entities::Project
         else
+          if @project.errors[:limit_reached].present?
+            error!(@project.errors[:limit_reached], 403)
+          end
           not_found!
         end
       end
@@ -122,16 +136,22 @@ module Gitlab
       #   POST /projects/:id/members
       post ":id/members" do
         authorize! :admin_project, user_project
-        users_project = user_project.users_projects.new(
-          user_id: params[:user_id],
-          project_access: params[:access_level]
-        )
+        required_attributes! [:user_id, :access_level]
+
+        # either the user is already a team member or a new one
+        team_member = user_project.team_member_by_id(params[:user_id])
+        if team_member.nil?
+          team_member = user_project.users_projects.new(
+            user_id: params[:user_id],
+            project_access: params[:access_level]
+          )
+        end
 
-        if users_project.save
-          @member = users_project.user
+        if team_member.save
+          @member = team_member.user
           present @member, with: Entities::ProjectMember, project: user_project
         else
-          not_found!
+          handle_project_member_errors team_member.errors
         end
       end
 
@@ -145,13 +165,16 @@ module Gitlab
       #   PUT /projects/:id/members/:user_id
       put ":id/members/:user_id" do
         authorize! :admin_project, user_project
-        users_project = user_project.users_projects.find_by_user_id params[:user_id]
+        required_attributes! [:access_level]
+
+        team_member = user_project.users_projects.find_by_user_id(params[:user_id])
+        not_found!("User can not be found") if team_member.nil?
 
-        if users_project.update_attributes(project_access: params[:access_level])
-          @member = users_project.user
+        if team_member.update_attributes(project_access: params[:access_level])
+          @member = team_member.user
           present @member, with: Entities::ProjectMember, project: user_project
         else
-          not_found!
+          handle_project_member_errors team_member.errors
         end
       end
 
@@ -164,8 +187,12 @@ module Gitlab
       #   DELETE /projects/:id/members/:user_id
       delete ":id/members/:user_id" do
         authorize! :admin_project, user_project
-        users_project = user_project.users_projects.find_by_user_id params[:user_id]
-        users_project.destroy
+        team_member = user_project.users_projects.find_by_user_id(params[:user_id])
+        unless team_member.nil?
+          team_member.destroy
+        else
+          {:message => "Access revoked", :id => params[:user_id].to_i}
+        end
       end
 
       # Get project hooks
@@ -203,11 +230,16 @@ module Gitlab
       #   POST /projects/:id/hooks
       post ":id/hooks" do
         authorize! :admin_project, user_project
+        required_attributes! [:url]
+
         @hook = user_project.hooks.new({"url" => params[:url]})
         if @hook.save
           present @hook, with: Entities::Hook
         else
-          error!({'message' => '404 Not found'}, 404)
+          if @hook.errors[:url].present?
+            error!("Invalid url given", 422)
+          end
+          not_found!
         end
       end
 
@@ -222,27 +254,36 @@ module Gitlab
       put ":id/hooks/:hook_id" do
         @hook = user_project.hooks.find(params[:hook_id])
         authorize! :admin_project, user_project
+        required_attributes! [:url]
 
         attrs = attributes_for_keys [:url]
-
         if @hook.update_attributes attrs
           present @hook, with: Entities::Hook
         else
+          if @hook.errors[:url].present?
+            error!("Invalid url given", 422)
+          end
           not_found!
         end
       end
 
-      # Delete project hook
+      # Deletes project hook. This is an idempotent function.
       #
       # Parameters:
       #   id (required) - The ID of a project
       #   hook_id (required) - The ID of hook to delete
       # Example Request:
       #   DELETE /projects/:id/hooks/:hook_id
-      delete ":id/hooks/:hook_id" do
+      delete ":id/hooks" do
         authorize! :admin_project, user_project
-        @hook = user_project.hooks.find(params[:hook_id])
-        @hook.destroy
+        required_attributes! [:hook_id]
+
+        begin
+          @hook = ProjectHook.find(params[:hook_id])
+          @hook.destroy
+        rescue
+          # ProjectHook can raise Error if hook_id not found
+        end
       end
 
       # Get a project repository branches
@@ -277,6 +318,7 @@ module Gitlab
       #   PUT /projects/:id/repository/branches/:branch/protect
       put ":id/repository/branches/:branch/protect" do
         @branch = user_project.repo.heads.find { |item| item.name == params[:branch] }
+        not_found! unless @branch
         protected = user_project.protected_branches.find_by_name(@branch.name)
 
         unless protected
@@ -295,6 +337,7 @@ module Gitlab
       #   PUT /projects/:id/repository/branches/:branch/unprotect
       put ":id/repository/branches/:branch/unprotect" do
         @branch = user_project.repo.heads.find { |item| item.name == params[:branch] }
+        not_found! unless @branch
         protected = user_project.protected_branches.find_by_name(@branch.name)
 
         if protected
@@ -318,7 +361,7 @@ module Gitlab
       #
       # Parameters:
       #   id (required) - The ID of a project
-      #   ref_name (optional) - The name of a repository branch or tag
+      #   ref_name (optional) - The name of a repository branch or tag, if not given the default branch is used
       # Example Request:
       #   GET /projects/:id/repository/commits
       get ":id/repository/commits" do
@@ -366,6 +409,7 @@ module Gitlab
       #   POST /projects/:id/snippets
       post ":id/snippets" do
         authorize! :write_snippet, user_project
+        required_attributes! [:title, :file_name, :code]
 
         attrs = attributes_for_keys [:title, :file_name]
         attrs[:expires_at] = params[:lifetime] if params[:lifetime].present?
@@ -414,10 +458,12 @@ module Gitlab
       # Example Request:
       #   DELETE /projects/:id/snippets/:snippet_id
       delete ":id/snippets/:snippet_id" do
-        @snippet = user_project.snippets.find(params[:snippet_id])
-        authorize! :modify_snippet, @snippet
-
-        @snippet.destroy
+        begin
+          @snippet = user_project.snippets.find(params[:snippet_id])
+          authorize! :modify_snippet, user_project
+          @snippet.destroy
+        rescue
+        end
       end
 
       # Get a raw project snippet
@@ -443,6 +489,7 @@ module Gitlab
       #   GET /projects/:id/repository/commits/:sha/blob
       get ":id/repository/commits/:sha/blob" do
         authorize! :download_code, user_project
+        required_attributes! [:filepath]
 
         ref = params[:sha]
 
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 7399d1a5034c69a88fe968e903092436f044801c..6cc3a7e52c9455a6970daab6c97ddd90a7ee4f8f 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -41,6 +41,8 @@ module Gitlab
       #   POST /users
       post do
         authenticated_as_admin!
+        required_attributes! [:email, :password, :name, :username]
+
         attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio]
         user = User.new attrs, as: :admin
         if user.save
@@ -67,10 +69,12 @@ module Gitlab
       #   PUT /users/:id
       put ":id" do
         authenticated_as_admin!
+
         attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio]
-        user = User.find_by_id(params[:id])
+        user = User.find(params[:id])
+        not_found!("User not found") unless user
 
-        if user && user.update_attributes(attrs)
+        if user.update_attributes(attrs)
           present user, with: Entities::User
         else
           not_found!
@@ -147,6 +151,8 @@ module Gitlab
       # Example Request:
       #   POST /user/keys
       post "keys" do
+        required_attributes! [:title, :key]
+
         attrs = attributes_for_keys [:title, :key]
         key = current_user.keys.new attrs
         if key.save
@@ -156,15 +162,18 @@ module Gitlab
         end
       end
 
-      # Delete existed ssh key of currently authenticated user
+      # Delete existing ssh key of currently authenticated user
       #
       # Parameters:
       #   id (required) - SSH Key ID
       # Example Request:
       #   DELETE /user/keys/:id
       delete "keys/:id" do
-        key = current_user.keys.find params[:id]
-        key.delete
+        begin
+          key = current_user.keys.find params[:id]
+          key.delete
+        rescue
+        end
       end
     end
   end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 44f4cd4a7379bfec811a72d080b7e7ede7760e76..545908b214d4c1d00a6b79b1b6a5c9acbbea8ac4 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -65,7 +65,7 @@ describe Project do
     it "should not allow new projects beyond user limits" do
       project.stub(:creator).and_return(double(can_create_project?: false, projects_limit: 1))
       project.should_not be_valid
-      project.errors[:base].first.should match(/Your own projects limit is 1/)
+      project.errors[:limit_reached].first.should match(/Your own projects limit is 1/)
     end
   end
 
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index 63616eef1bbeaf1b968a92be9f51a23677fabbf8..e97ceb2c9910d09cc4353c321748d0e2b929bfa5 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -88,6 +88,16 @@ describe Gitlab::API do
         post api("/groups", admin), {:name => "Duplicate Test", :path => group2.path}
         response.status.should == 404
       end
+
+      it "should return 400 bad request error if name not given" do
+        post api("/groups", admin), { :path => group2.path }
+        response.status.should == 400
+      end
+
+      it "should return 400 bad request error if path not given" do
+        post api("/groups", admin), { :name => 'test' }
+        response.status.should == 400
+      end
     end
   end
 
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 630ac0f820a7a7068120e347253512586fd16b5c..ecf0bdb70844ceb17513f913769807b7f5d107e6 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -41,6 +41,11 @@ describe Gitlab::API do
       response.status.should == 200
       json_response['title'].should == issue.title
     end
+
+    it "should return 404 if issue id not found" do
+      get api("/projects/#{project.id}/issues/54321", user)
+      response.status.should == 404
+    end
   end
 
   describe "POST /projects/:id/issues" do
@@ -52,6 +57,11 @@ describe Gitlab::API do
       json_response['description'].should be_nil
       json_response['labels'].should == ['label', 'label2']
     end
+
+    it "should return a 400 bad request if title not given" do
+      post api("/projects/#{project.id}/issues", user), labels: 'label, label2'
+      response.status.should == 400
+    end
   end
 
   describe "PUT /projects/:id/issues/:issue_id to update only title" do
@@ -62,6 +72,12 @@ describe Gitlab::API do
 
       json_response['title'].should == 'updated title'
     end
+
+    it "should return 404 error if issue id not found" do
+      put api("/projects/#{project.id}/issues/44444", user),
+        title: 'updated title'
+      response.status.should == 404
+    end
   end
 
   describe "PUT /projects/:id/issues/:issue_id to update state and label" do
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 1abd7a20dec2915fbd41d84cf8e199bbe2a3d165..e7af056af8ecea691b1bebf66a8548e006d3d40c 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -32,6 +32,11 @@ describe Gitlab::API do
       response.status.should == 200
       json_response['title'].should == merge_request.title
     end
+
+    it "should return a 404 error if merge_request_id not found" do
+      get api("/projects/#{project.id}/merge_request/999", user)
+      response.status.should == 404
+    end
   end
 
   describe "POST /projects/:id/merge_requests" do
@@ -41,6 +46,30 @@ describe Gitlab::API do
       response.status.should == 201
       json_response['title'].should == 'Test merge_request'
     end
+
+    it "should return 422 when source_branch equals target_branch" do
+      post api("/projects/#{project.id}/merge_requests", user),
+        title: "Test merge_request", source_branch: "master", target_branch: "master", author: user
+      response.status.should == 422
+    end
+
+    it "should return 400 when source_branch is missing" do
+      post api("/projects/#{project.id}/merge_requests", user),
+        title: "Test merge_request", target_branch: "master", author: user
+      response.status.should == 400
+    end
+
+    it "should return 400 when target_branch is missing" do
+      post api("/projects/#{project.id}/merge_requests", user),
+        title: "Test merge_request", source_branch: "stable", author: user
+      response.status.should == 400
+    end
+
+    it "should return 400 when title is missing" do
+      post api("/projects/#{project.id}/merge_requests", user),
+        target_branch: 'master', source_branch: 'stable'
+      response.status.should == 400
+    end
   end
 
   describe "PUT /projects/:id/merge_request/:merge_request_id to close MR" do
@@ -59,13 +88,24 @@ describe Gitlab::API do
     end
   end
 
-
   describe "PUT /projects/:id/merge_request/:merge_request_id" do
     it "should return merge_request" do
       put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), title: "New title"
       response.status.should == 200
       json_response['title'].should == 'New title'
     end
+
+    it "should return 422 when source_branch and target_branch are renamed the same" do
+      put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user),
+        source_branch: "master", target_branch: "master"
+      response.status.should == 422
+    end
+
+    it "should return merge_request with renamed target_branch" do
+      put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), target_branch: "test"
+      response.status.should == 200
+      json_response['target_branch'].should == 'test'
+    end
   end
 
   describe "POST /projects/:id/merge_request/:merge_request_id/comments" do
@@ -74,6 +114,16 @@ describe Gitlab::API do
       response.status.should == 201
       json_response['note'].should == 'My comment'
     end
+
+    it "should return 400 if note is missing" do
+      post api("/projects/#{project.id}/merge_request/#{merge_request.id}/comments", user)
+      response.status.should == 400
+    end
+
+    it "should return 404 if note is attached to non existent merge request" do
+      post api("/projects/#{project.id}/merge_request/111/comments", user), note: "My comment"
+      response.status.should == 404
+    end
   end
 
 end
diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb
index d1b5e449bc5a169af1307c45ce97b77f07e3b27b..c379e8a530771e15573bf5fcc56b0f25a7a86d5f 100644
--- a/spec/requests/api/milestones_spec.rb
+++ b/spec/requests/api/milestones_spec.rb
@@ -16,6 +16,11 @@ describe Gitlab::API do
       json_response.should be_an Array
       json_response.first['title'].should == milestone.title
     end
+
+    it "should return a 401 error if user not authenticated" do
+      get api("/projects/#{project.id}/milestones")
+      response.status.should == 401
+    end
   end
 
   describe "GET /projects/:id/milestones/:milestone_id" do
@@ -24,16 +29,38 @@ describe Gitlab::API do
       response.status.should == 200
       json_response['title'].should == milestone.title
     end
+
+    it "should return 401 error if user not authenticated" do
+      get api("/projects/#{project.id}/milestones/#{milestone.id}")
+      response.status.should == 401
+    end
+
+    it "should return a 404 error if milestone id not found" do
+      get api("/projects/#{project.id}/milestones/1234", user)
+      response.status.should == 404
+    end
   end
 
   describe "POST /projects/:id/milestones" do
     it "should create a new project milestone" do
-      post api("/projects/#{project.id}/milestones", user),
-        title: 'new milestone'
+      post api("/projects/#{project.id}/milestones", user), title: 'new milestone'
       response.status.should == 201
       json_response['title'].should == 'new milestone'
       json_response['description'].should be_nil
     end
+
+    it "should create a new project milestone with description and due date" do
+      post api("/projects/#{project.id}/milestones", user),
+        title: 'new milestone', description: 'release', due_date: '2013-03-02'
+      response.status.should == 201
+      json_response['description'].should == 'release'
+      json_response['due_date'].should == '2013-03-02'
+    end
+
+    it "should return a 400 error if title is missing" do
+      post api("/projects/#{project.id}/milestones", user)
+      response.status.should == 400
+    end
   end
 
   describe "PUT /projects/:id/milestones/:milestone_id" do
@@ -43,6 +70,12 @@ describe Gitlab::API do
       response.status.should == 200
       json_response['title'].should == 'updated title'
     end
+
+    it "should return a 404 error if milestone id not found" do
+      put api("/projects/#{project.id}/milestones/1234", user),
+        title: 'updated title'
+      response.status.should == 404
+    end
   end
 
   describe "PUT /projects/:id/milestones/:milestone_id to close milestone" do
diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb
index ee99d85df4d721aeb412ba84fc9af5f921e0b5ea..901640834f212f04e558bd7833f549ec61a32e6e 100644
--- a/spec/requests/api/notes_spec.rb
+++ b/spec/requests/api/notes_spec.rb
@@ -38,6 +38,11 @@ describe Gitlab::API do
       response.status.should == 200
       json_response['body'].should == wall_note.note
     end
+
+    it "should return a 404 error if note not found" do
+      get api("/projects/#{project.id}/notes/123", user)
+      response.status.should == 404
+    end
   end
 
   describe "POST /projects/:id/notes" do
@@ -46,6 +51,16 @@ describe Gitlab::API do
       response.status.should == 201
       json_response['body'].should == 'hi!'
     end
+
+    it "should return 401 unauthorized error" do
+      post api("/projects/#{project.id}/notes")
+      response.status.should == 401
+    end
+
+    it "should return a 400 bad request if body is missing" do
+      post api("/projects/#{project.id}/notes", user)
+      response.status.should == 400
+    end
   end
 
   describe "GET /projects/:id/noteable/:noteable_id/notes" do
@@ -56,6 +71,11 @@ describe Gitlab::API do
         json_response.should be_an Array
         json_response.first['body'].should == issue_note.note
       end
+
+      it "should return a 404 error when issue id not found" do
+        get api("/projects/#{project.id}/issues/123/notes", user)
+        response.status.should == 404
+      end
     end
 
     context "when noteable is a Snippet" do
@@ -65,6 +85,11 @@ describe Gitlab::API do
         json_response.should be_an Array
         json_response.first['body'].should == snippet_note.note
       end
+
+      it "should return a 404 error when snippet id not found" do
+        get api("/projects/#{project.id}/snippets/42/notes", user)
+        response.status.should == 404
+      end
     end
 
     context "when noteable is a Merge Request" do
@@ -74,6 +99,11 @@ describe Gitlab::API do
         json_response.should be_an Array
         json_response.first['body'].should == merge_request_note.note
       end
+
+      it "should return a 404 error if merge request id not found" do
+        get api("/projects/#{project.id}/merge_requests/4444/notes", user)
+        response.status.should == 404
+      end
     end
   end
 
@@ -84,6 +114,11 @@ describe Gitlab::API do
         response.status.should == 200
         json_response['body'].should == issue_note.note
       end
+
+      it "should return a 404 error if issue note not found" do
+        get api("/projects/#{project.id}/issues/#{issue.id}/notes/123", user)
+        response.status.should == 404
+      end
     end
 
     context "when noteable is a Snippet" do
@@ -92,6 +127,11 @@ describe Gitlab::API do
         response.status.should == 200
         json_response['body'].should == snippet_note.note
       end
+
+      it "should return a 404 error if snippet note not found" do
+        get api("/projects/#{project.id}/snippets/#{snippet.id}/notes/123", user)
+        response.status.should == 404
+      end
     end
   end
 
@@ -103,6 +143,16 @@ describe Gitlab::API do
         json_response['body'].should == 'hi!'
         json_response['author']['email'].should == user.email
       end
+
+      it "should return a 400 bad request error if body not given" do
+        post api("/projects/#{project.id}/issues/#{issue.id}/notes", user)
+        response.status.should == 400
+      end
+
+      it "should return a 401 unauthorized error if user not authenticated" do
+        post api("/projects/#{project.id}/issues/#{issue.id}/notes"), body: 'hi!'
+        response.status.should == 401
+      end
     end
 
     context "when noteable is a Snippet" do
@@ -112,6 +162,16 @@ describe Gitlab::API do
         json_response['body'].should == 'hi!'
         json_response['author']['email'].should == user.email
       end
+
+      it "should return a 400 bad request error if body not given" do
+        post api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
+        response.status.should == 400
+      end
+
+      it "should return a 401 unauthorized error if user not authenticated" do
+        post api("/projects/#{project.id}/snippets/#{snippet.id}/notes"), body: 'hi!'
+        response.status.should == 401
+      end
     end
   end
 end
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 72f93c46ce4a6204148bf09e6a430fa2b54f789a..cddb72640189df893e847fb8e9a117d4f1f6b979 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -7,8 +7,8 @@ describe Gitlab::API do
   let(:user2) { create(:user) }
   let(:user3) { create(:user) }
   let(:admin) { create(:admin) }
-  let!(:hook) { create(:project_hook, project: project, url: "http://example.com") }
   let!(:project) { create(:project, namespace: user.namespace ) }
+  let!(:hook) { create(:project_hook, project: project, url: "http://example.com") }
   let!(:snippet) { create(:snippet, author: user, project: project, title: 'example') }
   let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) }
   let!(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) }
@@ -58,6 +58,11 @@ describe Gitlab::API do
       expect { post api("/projects", user) }.to_not change {Project.count}
     end
 
+    it "should return a 400 error if name not given" do
+      post api("/projects", user)
+      response.status.should == 400
+    end
+
     it "should create last project before reaching project limit" do
       (1..user2.projects_limit-1).each { |p| post api("/projects", user2), name: "foo#{p}" }
       post api("/projects", user2), name: "foo"
@@ -69,9 +74,17 @@ describe Gitlab::API do
       response.status.should == 201
     end
 
-    it "should respond with 404 on failure" do
+    it "should respond with 400 if name is not given" do
       post api("/projects", user)
-      response.status.should == 404
+      response.status.should == 400
+    end
+
+    it "should return a 403 error if project limit reached" do
+      (1..user.projects_limit).each do |p|
+        post api("/projects", user), name: "foo#{p}"
+      end
+      post api("/projects", user), name: 'bar'
+      response.status.should == 403
     end
 
     it "should assign attributes to project" do
@@ -152,6 +165,12 @@ describe Gitlab::API do
       response.status.should == 404
       json_response['message'].should == '404 Not Found'
     end
+
+    it "should return a 404 error if user is not a member" do
+      other_user = create(:user)
+      get api("/projects/#{project.id}", other_user)
+      response.status.should == 404
+    end
   end
 
   describe "GET /projects/:id/repository/branches" do
@@ -188,6 +207,17 @@ describe Gitlab::API do
       json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1'
       json_response['protected'].should == true
     end
+
+    it "should return a 404 error if branch not found" do
+      put api("/projects/#{project.id}/repository/branches/unknown/protect", user)
+      response.status.should == 404
+    end
+
+    it "should return success when protect branch again" do
+      put api("/projects/#{project.id}/repository/branches/new_design/protect", user)
+      put api("/projects/#{project.id}/repository/branches/new_design/protect", user)
+      response.status.should == 200
+    end
   end
 
   describe "PUT /projects/:id/repository/branches/:branch/unprotect" do
@@ -199,6 +229,17 @@ describe Gitlab::API do
       json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1'
       json_response['protected'].should == false
     end
+
+    it "should return success when unprotect branch" do
+      put api("/projects/#{project.id}/repository/branches/unknown/unprotect", user)
+      response.status.should == 404
+    end
+
+    it "should return success when unprotect branch again" do
+      put api("/projects/#{project.id}/repository/branches/new_design/unprotect", user)
+      put api("/projects/#{project.id}/repository/branches/new_design/unprotect", user)
+      response.status.should == 200
+    end
   end
 
   describe "GET /projects/:id/members" do
@@ -217,6 +258,11 @@ describe Gitlab::API do
       json_response.count.should == 1
       json_response.first['email'].should == user.email
     end
+
+    it "should return a 404 error if id not found" do
+      get api("/projects/9999/members", user)
+      response.status.should == 404
+    end
   end
 
   describe "GET /projects/:id/members/:user_id" do
@@ -226,6 +272,11 @@ describe Gitlab::API do
       json_response['email'].should == user.email
       json_response['access_level'].should == UsersProject::MASTER
     end
+
+    it "should return a 404 error if user id not found" do
+      get api("/projects/#{project.id}/members/1234", user)
+      response.status.should == 404
+    end
   end
 
   describe "POST /projects/:id/members" do
@@ -239,6 +290,34 @@ describe Gitlab::API do
       json_response['email'].should == user2.email
       json_response['access_level'].should == UsersProject::DEVELOPER
     end
+
+    it "should return a 201 status if user is already project member" do
+      post api("/projects/#{project.id}/members", user), user_id: user2.id,
+        access_level: UsersProject::DEVELOPER
+      expect {
+        post api("/projects/#{project.id}/members", user), user_id: user2.id,
+          access_level: UsersProject::DEVELOPER
+      }.not_to change { UsersProject.count }.by(1)
+
+      response.status.should == 201
+      json_response['email'].should == user2.email
+      json_response['access_level'].should == UsersProject::DEVELOPER
+    end
+
+    it "should return a 400 error when user id is not given" do
+      post api("/projects/#{project.id}/members", user), access_level: UsersProject::MASTER
+      response.status.should == 400
+    end
+
+    it "should return a 400 error when access level is not given" do
+      post api("/projects/#{project.id}/members", user), user_id: user2.id
+      response.status.should == 400
+    end
+
+    it "should return a 422 error when access level is not known" do
+      post api("/projects/#{project.id}/members", user), user_id: user2.id, access_level: 1234
+      response.status.should == 422
+    end
   end
 
   describe "PUT /projects/:id/members/:user_id" do
@@ -248,6 +327,21 @@ describe Gitlab::API do
       json_response['email'].should == user3.email
       json_response['access_level'].should == UsersProject::MASTER
     end
+
+    it "should return a 404 error if user_id is not found" do
+      put api("/projects/#{project.id}/members/1234", user), access_level: UsersProject::MASTER
+      response.status.should == 404
+    end
+
+    it "should return a 400 error when access level is not given" do
+      put api("/projects/#{project.id}/members/#{user3.id}", user)
+      response.status.should == 400
+    end
+
+    it "should return a 422 error when access level is not known" do
+      put api("/projects/#{project.id}/members/#{user3.id}", user), access_level: 123
+      response.status.should == 422
+    end
   end
 
   describe "DELETE /projects/:id/members/:user_id" do
@@ -256,6 +350,30 @@ describe Gitlab::API do
         delete api("/projects/#{project.id}/members/#{user3.id}", user)
       }.to change { UsersProject.count }.by(-1)
     end
+
+    it "should return 200 if team member is not part of a project" do
+      delete api("/projects/#{project.id}/members/#{user3.id}", user)
+      expect {
+        delete api("/projects/#{project.id}/members/#{user3.id}", user)
+      }.to_not change { UsersProject.count }.by(1)
+    end
+
+    it "should return 200 if team member already removed" do
+      delete api("/projects/#{project.id}/members/#{user3.id}", user)
+      delete api("/projects/#{project.id}/members/#{user3.id}", user)
+      response.status.should == 200
+    end
+  end
+
+  describe "DELETE /projects/:id/members/:user_id" do
+    it "should return 200 OK when the user was not member" do
+      expect {
+        delete api("/projects/#{project.id}/members/1000000", user)
+      }.to change { UsersProject.count }.by(0)
+      response.status.should == 200
+      json_response['message'].should == "Access revoked"
+      json_response['id'].should == 1000000
+    end
   end
 
   describe "GET /projects/:id/hooks" do
@@ -298,6 +416,11 @@ describe Gitlab::API do
         response.status.should == 403
       end
     end
+
+    it "should return a 404 error if hook id is not available" do
+      get api("/projects/#{project.id}/hooks/1234", user)
+      response.status.should == 404
+    end
   end
 
   describe "POST /projects/:id/hooks" do
@@ -306,6 +429,17 @@ describe Gitlab::API do
         post api("/projects/#{project.id}/hooks", user),
           url: "http://example.com"
       }.to change {project.hooks.count}.by(1)
+      response.status.should == 201
+    end
+
+    it "should return a 400 error if url not given" do
+      post api("/projects/#{project.id}/hooks", user)
+      response.status.should == 400
+    end
+
+    it "should return a 422 error if url not valid" do
+      post api("/projects/#{project.id}/hooks", user), "url" => "ftp://example.com"
+      response.status.should == 422
     end
   end
 
@@ -316,13 +450,44 @@ describe Gitlab::API do
       response.status.should == 200
       json_response['url'].should == 'http://example.org'
     end
+
+    it "should return 404 error if hook id not found" do
+      put api("/projects/#{project.id}/hooks/1234", user), url: 'http://example.org'
+      response.status.should == 404
+    end
+
+    it "should return 400 error if url is not given" do
+      put api("/projects/#{project.id}/hooks/#{hook.id}", user)
+      response.status.should == 400
+    end
+
+    it "should return a 422 error if url is not valid" do
+      put api("/projects/#{project.id}/hooks/#{hook.id}", user), url: 'ftp://example.com'
+      response.status.should == 422
+    end
   end
 
-  describe "DELETE /projects/:id/hooks/:hook_id" do
+  describe "DELETE /projects/:id/hooks" do
     it "should delete hook from project" do
       expect {
-        delete api("/projects/#{project.id}/hooks/#{hook.id}", user)
+        delete api("/projects/#{project.id}/hooks", user), hook_id: hook.id
       }.to change {project.hooks.count}.by(-1)
+      response.status.should == 200
+    end
+
+    it "should return success when deleting hook" do
+      delete api("/projects/#{project.id}/hooks", user), hook_id: hook.id
+      response.status.should == 200
+    end
+
+    it "should return success when deleting non existent hook" do
+      delete api("/projects/#{project.id}/hooks", user), hook_id: 42
+      response.status.should == 200
+    end
+
+    it "should return a 400 error if hook id not given" do
+      delete api("/projects/#{project.id}/hooks", user)
+      response.status.should == 400
     end
   end
 
@@ -371,6 +536,11 @@ describe Gitlab::API do
       response.status.should == 200
       json_response['title'].should == snippet.title
     end
+
+    it "should return a 404 error if snippet id not found" do
+      get api("/projects/#{project.id}/snippets/1234", user)
+      response.status.should == 404
+    end
   end
 
   describe "POST /projects/:id/snippets" do
@@ -380,6 +550,24 @@ describe Gitlab::API do
       response.status.should == 201
       json_response['title'].should == 'api test'
     end
+
+    it "should return a 400 error if title is not given" do
+      post api("/projects/#{project.id}/snippets", user),
+        file_name: 'sample.rb', code: 'test'
+      response.status.should == 400
+    end
+
+    it "should return a 400 error if file_name not given" do
+      post api("/projects/#{project.id}/snippets", user),
+        title: 'api test', code: 'test'
+      response.status.should == 400
+    end
+
+    it "should return a 400 error if code not given" do
+      post api("/projects/#{project.id}/snippets", user),
+        title: 'api test', file_name: 'sample.rb'
+      response.status.should == 400
+    end
   end
 
   describe "PUT /projects/:id/snippets/:shippet_id" do
@@ -390,6 +578,13 @@ describe Gitlab::API do
       json_response['title'].should == 'example'
       snippet.reload.content.should == 'updated code'
     end
+
+    it "should update an existing project snippet with new title" do
+      put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
+        title: 'other api test'
+      response.status.should == 200
+      json_response['title'].should == 'other api test'
+    end
   end
 
   describe "DELETE /projects/:id/snippets/:snippet_id" do
@@ -397,6 +592,12 @@ describe Gitlab::API do
       expect {
         delete api("/projects/#{project.id}/snippets/#{snippet.id}", user)
       }.to change { Snippet.count }.by(-1)
+      response.status.should == 200
+    end
+
+    it "should return success when deleting unknown snippet id" do
+      delete api("/projects/#{project.id}/snippets/1234", user)
+      response.status.should == 200
     end
   end
 
@@ -405,9 +606,14 @@ describe Gitlab::API do
       get api("/projects/#{project.id}/snippets/#{snippet.id}/raw", user)
       response.status.should == 200
     end
+
+    it "should return a 404 error if raw project snippet not found" do
+      get api("/projects/#{project.id}/snippets/5555/raw", user)
+      response.status.should == 404
+    end
   end
 
-  describe "GET /projects/:id/:sha/blob" do
+  describe "GET /projects/:id/repository/commits/:sha/blob" do
     it "should get the raw file contents" do
       get api("/projects/#{project.id}/repository/commits/master/blob?filepath=README.md", user)
       response.status.should == 200
@@ -422,6 +628,11 @@ describe Gitlab::API do
       get api("/projects/#{project.id}/repository/commits/master/blob?filepath=README.invalid", user)
       response.status.should == 404
     end
+
+    it "should return a 400 error if filepath is missing" do
+      get api("/projects/#{project.id}/repository/commits/master/blob", user)
+      response.status.should == 400
+    end
   end
 
   describe "GET /projects/:id/keys" do
diff --git a/spec/requests/api/session_spec.rb b/spec/requests/api/session_spec.rb
index afae8be8cbca3ce2692f83bd90c87c07c13c511e..2cdb0d7e9b4a95c12d4f03d93eeb3067d8f554b9 100644
--- a/spec/requests/api/session_spec.rb
+++ b/spec/requests/api/session_spec.rb
@@ -35,5 +35,15 @@ describe Gitlab::API do
         json_response['private_token'].should be_nil
       end
     end
+
+    context "when empty name" do
+      it "should return authentication error" do
+        post api("/session"), password: user.password
+        response.status.should == 401
+
+        json_response['email'].should be_nil
+        json_response['private_token'].should be_nil
+      end
+    end
   end
 end
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index e6ac892dfc48e343283c08f723011fe9bc393f5b..c2c9f8465b8af69dc147967d281c769ed076ef0b 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -31,15 +31,20 @@ describe Gitlab::API do
       response.status.should == 200
       json_response['email'].should == user.email
     end
-  end
 
-  describe "POST /users" do
-    before{ admin }
+    it "should return a 401 if unauthenticated" do
+      get api("/users/9998")
+      response.status.should == 401
+    end
 
-    it "should not create invalid user" do
-      post api("/users", admin), { email: "invalid email" }
+    it "should return a 404 error if user id not found" do
+      get api("/users/9999", user)
       response.status.should == 404
     end
+  end
+
+  describe "POST /users" do
+    before{ admin }
 
     it "should create user" do
       expect {
@@ -47,10 +52,48 @@ describe Gitlab::API do
       }.to change { User.count }.by(1)
     end
 
+    it "should return 201 Created on success" do
+      post api("/users", admin), attributes_for(:user, projects_limit: 3)
+      response.status.should == 201
+    end
+
+    it "should not create user with invalid email" do
+      post api("/users", admin), { email: "invalid email", password: 'password' }
+      response.status.should == 400
+    end
+
+    it "should return 400 error if password not given" do
+      post api("/users", admin), { email: 'test@example.com' }
+      response.status.should == 400
+    end
+
+    it "should return 400 error if email not given" do
+      post api("/users", admin), { password: 'pass1234' }
+      response.status.should == 400
+    end
+
     it "shouldn't available for non admin users" do
       post api("/users", user), attributes_for(:user)
       response.status.should == 403
     end
+
+    context "with existing user" do
+      before { post api("/users", admin), { email: 'test@example.com', password: 'password', username: 'test' } }
+
+      it "should not create user with same email" do
+        expect {
+          post api("/users", admin), { email: 'test@example.com', password: 'password' }
+        }.to change { User.count }.by(0)
+      end
+
+      it "should return 409 conflict error if user with email exists" do
+        post api("/users", admin), { email: 'test@example.com', password: 'password' }
+      end
+
+      it "should return 409 conflict error if same username exists" do
+        post api("/users", admin), { email: 'foo@example.com', password: 'pass', username: 'test' }
+      end
+    end
   end
 
   describe "GET /users/sign_up" do
@@ -81,7 +124,7 @@ describe Gitlab::API do
   describe "PUT /users/:id" do
     before { admin }
 
-    it "should update user" do
+    it "should update user with new bio" do
       put api("/users/#{user.id}", admin), {bio: 'new test bio'}
       response.status.should == 200
       json_response['bio'].should == 'new test bio'
@@ -103,6 +146,25 @@ describe Gitlab::API do
       put api("/users/999999", admin), {bio: 'update should fail'}
       response.status.should == 404
     end
+
+    context "with existing user" do
+      before {
+        post api("/users", admin), { email: 'test@example.com', password: 'password', username: 'test', name: 'test' }
+        post api("/users", admin), { email: 'foo@bar.com', password: 'password', username: 'john', name: 'john' }
+        @user_id = User.all.last.id
+      }
+
+#      it "should return 409 conflict error if email address exists" do
+#        put api("/users/#{@user_id}", admin), { email: 'test@example.com' }
+#        response.status.should == 409
+#      end
+#
+#      it "should return 409 conflict error if username taken" do
+#        @user_id = User.all.last.id
+#        put api("/users/#{@user_id}", admin), { username: 'test' }
+#        response.status.should == 409
+#      end
+    end
   end
 
   describe "POST /users/:id/keys" do
@@ -131,6 +193,11 @@ describe Gitlab::API do
       json_response['email'].should == user.email
     end
 
+    it "should not delete for unauthenticated user" do
+      delete api("/users/#{user.id}")
+      response.status.should == 401
+    end
+
     it "shouldn't available for non admin users" do
       delete api("/users/#{user.id}", user)
       response.status.should == 403
@@ -148,6 +215,11 @@ describe Gitlab::API do
       response.status.should == 200
       json_response['email'].should == user.email
     end
+
+    it "should return 401 error if user is unauthenticated" do
+      get api("/user")
+      response.status.should == 401
+    end
   end
 
   describe "GET /user/keys" do
@@ -183,19 +255,38 @@ describe Gitlab::API do
       get api("/user/keys/42", user)
       response.status.should == 404
     end
-  end
 
-  describe "POST /user/keys" do
-    it "should not create invalid ssh key" do
-      post api("/user/keys", user), { title: "invalid key" }
+    it "should return 404 error if admin accesses user's ssh key" do
+      user.keys << key
+      user.save
+      admin
+      get api("/user/keys/#{key.id}", admin)
       response.status.should == 404
     end
+  end
 
+  describe "POST /user/keys" do
     it "should create ssh key" do
       key_attrs = attributes_for :key
       expect {
         post api("/user/keys", user), key_attrs
       }.to change{ user.keys.count }.by(1)
+      response.status.should == 201
+    end
+
+    it "should return a 401 error if unauthorized" do
+      post api("/user/keys"), title: 'some title', key: 'some key'
+      response.status.should == 401
+    end
+
+    it "should not create ssh key without key" do
+      post api("/user/keys", user), title: 'title'
+      response.status.should == 400
+    end
+
+    it "should not create ssh key without title" do
+      post api("/user/keys", user), key: "somekey"
+      response.status.should == 400
     end
   end
 
@@ -206,11 +297,19 @@ describe Gitlab::API do
       expect {
         delete api("/user/keys/#{key.id}", user)
       }.to change{user.keys.count}.by(-1)
+      response.status.should == 200
     end
 
-    it "should return 404 Not Found within invalid ID" do
+    it "should return sucess if key ID not found" do
       delete api("/user/keys/42", user)
-      response.status.should == 404
+      response.status.should == 200
+    end
+
+    it "should return 401 error if unauthorized" do
+      user.keys << key
+      user.save
+      delete api("/user/keys/#{key.id}")
+      response.status.should == 401
     end
   end
 end