diff --git a/lib/api.rb b/lib/api.rb
index 9e38bc496fea999f5bc6612e0196b5b1a9fb2595..ab5b02e0556ee6ff53a3335ed813772dece5a548 100644
--- a/lib/api.rb
+++ b/lib/api.rb
@@ -6,6 +6,7 @@ module Gitlab
     format :json
     helpers APIHelpers
 
+    # Users API
     resource :users do
       before { authenticate! }
 
@@ -27,5 +28,34 @@ module Gitlab
       authenticate!
       present @current_user, :with => Entities::User
     end
+
+    # Projects API
+    resource :projects do
+      before { authenticate! }
+
+      # GET /projects
+      get do
+        @projects = current_user.projects
+        present @projects, :with => Entities::Project
+      end
+
+      # GET /projects/:id
+      get ":id" do
+        @project = Project.find_by_code(params[:id])
+        present @project, :with => Entities::Project
+      end
+
+      # GET /projects/:id/repository/branches
+      get ":id/repository/branches" do
+        @project = Project.find_by_code(params[:id])
+        present @project.repo.heads.sort_by(&:name), :with => Entities::ProjectRepositoryBranches
+      end
+
+      # GET /projects/:id/repository/tags
+      get ":id/repository/tags" do
+        @project = Project.find_by_code(params[:id])
+        present @project.repo.tags.sort_by(&:name).reverse, :with => Entities::ProjectRepositoryTags
+      end
+    end
   end
 end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 3548e8cc5a9365ad0c940e5d2bb97536cedf0bf1..44a439856020b31765484721dccb220b50835edc 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -4,5 +4,20 @@ module Gitlab
       expose :id, :email, :name, :bio, :skype, :linkedin, :twitter,
              :dark_scheme, :theme_id, :blocked, :created_at
     end
+
+    class Project < Grape::Entity
+      expose :id, :code, :name, :description, :path, :default_branch
+      expose :owner, :using => Entities::User
+      expose :private_flag, :as => :private
+      expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at
+    end
+
+    class ProjectRepositoryBranches < Grape::Entity
+      expose :name, :commit
+    end
+
+    class ProjectRepositoryTags < Grape::Entity
+      expose :name, :commit
+    end
   end
 end
diff --git a/spec/api/projects_spec.rb b/spec/api/projects_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2d1043f961e75eb0b84736333ab8b7414522b0b9
--- /dev/null
+++ b/spec/api/projects_spec.rb
@@ -0,0 +1,56 @@
+require 'spec_helper'
+
+describe Gitlab::API do
+  let(:user) { Factory :user }
+  let!(:project) { Factory :project, :owner => user }
+
+  describe "GET /projects" do
+    before { project.add_access(user, :read) }
+
+    it "should return authentication error" do
+      get "/api/projects"
+      response.status.should == 401
+    end
+
+    describe "authenticated GET /projects" do
+      it "should return an array of projects" do
+        get "/api/projects?private_token=#{user.private_token}"
+        response.status.should == 200
+        json = JSON.parse(response.body)
+        json.should be_an Array
+        json.first['name'].should == project.name
+        json.first['owner']['email'].should == user.email
+      end
+    end
+  end
+
+  describe "GET /projects/:id" do
+    it "should return a project by id" do
+      get "/api/projects/#{project.code}?private_token=#{user.private_token}"
+      response.status.should == 200
+      json = JSON.parse(response.body)
+      json['name'].should == project.name
+      json['owner']['email'].should == user.email
+    end
+  end
+
+  describe "GET /projects/:id/repository/branches" do
+    it "should return an array of project branches" do
+      get "/api/projects/#{project.code}/repository/branches?private_token=#{user.private_token}"
+      response.status.should == 200
+      json = JSON.parse(response.body)
+      json.should be_an Array
+      json.first['name'].should == project.repo.heads.sort_by(&:name).first.name
+    end
+  end
+
+  describe "GET /projects/:id/repository/tags" do
+    it "should return an array of project tags" do
+      get "/api/projects/#{project.code}/repository/tags?private_token=#{user.private_token}"
+      response.status.should == 200
+      json = JSON.parse(response.body)
+      json.should be_an Array
+      json.first['name'].should == project.repo.tags.sort_by(&:name).reverse.first.name
+    end
+  end
+end