diff --git a/Gemfile.lock b/Gemfile.lock
index bc4a1f5b..c56de6bf 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -50,7 +50,7 @@ GIT
 
 GIT
   remote: git://github.com/travis-ci/travis-core.git
-  revision: ba10e214824632f15598555a2634ce3347d2f227
+  revision: 4834399048b8c9cff4882d435f770826930665f6
   specs:
     travis-core (0.0.1)
       actionmailer (~> 3.2.19)
@@ -81,7 +81,7 @@ GIT
 
 GIT
   remote: git://github.com/travis-ci/travis-support.git
-  revision: 4fdd220ed7b06a12951e5d74a763c05a80eb0d20
+  revision: e7f81093f83bd029cca6508739c5720e57e3d571
   specs:
     travis-support (0.0.1)
 
diff --git a/lib/travis/api/v3/queries/account.rb b/lib/travis/api/v3/queries/account.rb
new file mode 100644
index 00000000..398bd39a
--- /dev/null
+++ b/lib/travis/api/v3/queries/account.rb
@@ -0,0 +1,20 @@
+module Travis::API::V3
+  class Queries::Account < Query
+    def find
+      find!(:organization) || find!(:user)
+    end
+
+    private
+
+    def query(type, main_type: self.main_type, params: self.params)
+      main_type = type if main_type == :account
+      params    = params.merge("#{type}.login" => params["account.login".freeze]) if params["account.login".freeze]
+      Queries[type].new(params, main_type)
+    end
+
+    def find!(type)
+      query(type).find
+    rescue WrongParams => e
+    end
+  end
+end
diff --git a/lib/travis/api/v3/queries/organization.rb b/lib/travis/api/v3/queries/organization.rb
index 8c07c910..fed17682 100644
--- a/lib/travis/api/v3/queries/organization.rb
+++ b/lib/travis/api/v3/queries/organization.rb
@@ -1,10 +1,11 @@
 module Travis::API::V3
   class Queries::Organization < Query
-    params :id
+    params :id, :login
 
     def find
-      return Models::Organization.find_by_id(id) if id
-      raise WrongParams, 'missing organization.id'.freeze
+      return Models::Organization.find_by_id(id)       if id
+      return Models::Organization.find_by_login(login) if login
+      raise WrongParams, 'missing organization.id or organization.login'.freeze
     end
   end
 end
diff --git a/lib/travis/api/v3/queries/user.rb b/lib/travis/api/v3/queries/user.rb
index af067d19..c05c9899 100644
--- a/lib/travis/api/v3/queries/user.rb
+++ b/lib/travis/api/v3/queries/user.rb
@@ -1,10 +1,11 @@
 module Travis::API::V3
   class Queries::User < Query
-    params :id
+    params :id, :login
 
     def find
-      return Models::User.find_by_id(id) if id
-      raise WrongParams, 'missing user.id'.freeze
+      return Models::User.find_by_id(id)       if id
+      return Models::User.find_by_login(login) if login
+      raise WrongParams, 'missing user.id or user.login'.freeze
     end
   end
 end
diff --git a/lib/travis/api/v3/routes.rb b/lib/travis/api/v3/routes.rb
index ebc26022..bccb414f 100644
--- a/lib/travis/api/v3/routes.rb
+++ b/lib/travis/api/v3/routes.rb
@@ -3,6 +3,11 @@ module Travis::API::V3
     require 'travis/api/v3/routes/dsl'
     extend DSL
 
+    resource :account do
+      route '/account/({account.login}|{user.login}|{organization.login})'
+      get :find
+    end
+
     resource :repository do
       route '/repo/{repository.id}'
       get :find
diff --git a/lib/travis/api/v3/service.rb b/lib/travis/api/v3/service.rb
index b19e662c..01e2f61c 100644
--- a/lib/travis/api/v3/service.rb
+++ b/lib/travis/api/v3/service.rb
@@ -16,15 +16,15 @@ module Travis::API::V3
       @github         = {}
     end
 
-    def query(type = self.class.result_type)
-      @queries[type] ||= Queries[type].new(params, self.class.result_type)
+    def query(type = result_type)
+      @queries[type] ||= Queries[type].new(params, result_type)
     end
 
     def github(user = nil)
       @github[user] ||= GitHub.new(user)
     end
 
-    def find(type = self.class.result_type, *args)
+    def find(type = result_type, *args)
       not_found(true,  type) unless object = query(type).find(*args)
       not_found(false, type) unless access_control.visible? object
       object
@@ -33,16 +33,20 @@ module Travis::API::V3
     def not_found(actually_not_found = false, type = nil)
       type, actually_not_found = actually_not_found, false if actually_not_found.is_a? Symbol
       error = actually_not_found ? EntityMissing : NotFound
-      raise(error, type || self.class.result_type)
+      raise(error, type || result_type)
     end
 
     def run!
       not_implemented
     end
 
+    def result_type
+      self.class.result_type
+    end
+
     def run
       not_found unless result = run!
-      result = Result.new(self.class.result_type, result) unless result.is_a? Result
+      result = Result.new(result_type, result) unless result.is_a? Result
       result
     end
 
@@ -53,7 +57,7 @@ module Travis::API::V3
     end
 
     def accepted(**payload)
-      payload[:resource_type] ||= self.class.result_type
+      payload[:resource_type] ||= result_type
       Result.new(:accepted, payload, status: 202)
     end
 
diff --git a/lib/travis/api/v3/services.rb b/lib/travis/api/v3/services.rb
index 45d35477..d811d705 100644
--- a/lib/travis/api/v3/services.rb
+++ b/lib/travis/api/v3/services.rb
@@ -2,6 +2,7 @@ module Travis::API::V3
   module Services
     extend ConstantResolver
 
+    Account       = Module.new { extend Services }
     Branch        = Module.new { extend Services }
     Build         = Module.new { extend Services }
     Organization  = Module.new { extend Services }
diff --git a/lib/travis/api/v3/services/account/find.rb b/lib/travis/api/v3/services/account/find.rb
new file mode 100644
index 00000000..88356b12
--- /dev/null
+++ b/lib/travis/api/v3/services/account/find.rb
@@ -0,0 +1,20 @@
+module Travis::API::V3
+  class Services::Account::Find < Service
+    def result_type
+      @result_type ||= super
+    end
+
+    def run!
+      account      = find
+      @result_type = type_for(account)
+      account
+    end
+
+    def type_for(account)
+      case account
+      when Models::User         then :user
+      when Models::Organization then :organization
+      end
+    end
+  end
+end
diff --git a/spec/v3/service_index_spec.rb b/spec/v3/service_index_spec.rb
index 79b9419b..b4780c62 100644
--- a/spec/v3/service_index_spec.rb
+++ b/spec/v3/service_index_spec.rb
@@ -86,6 +86,19 @@ describe Travis::API::V3::ServiceIndex do
               "request_method"=>"GET",
               "uri_template"=>"#{path}org/{organization.id}"}]},
          "attributes"=>["id", "login", "name", "github_id"]},
+       "account"=>
+        {"@type"=>"resource",
+         "actions"=>
+          {"find"=>
+            [{"@type"=>"template",
+              "request_method"=>"GET",
+              "uri_template"=>"#{path}account/{account.login}"},
+             {"@type"=>"template",
+              "request_method"=>"GET",
+              "uri_template"=>"#{path}account/{user.login}"},
+             {"@type"=>"template",
+              "request_method"=>"GET",
+              "uri_template"=>"#{path}account/{organization.login}"}]}},
        "organizations"=>
         {"@type"=>"resource",
          "actions"=>
@@ -108,22 +121,27 @@ describe Travis::API::V3::ServiceIndex do
          "attributes"=>["id", "login", "name", "github_id", "is_syncing", "synced_at"]}}
     }
 
+    shared_examples 'service index' do
+      describe :resources do
+        specify { expect(json['resources']).to include(expected_resources) }
+        specify { expect(json['resources'].keys.sort) .to be == expected_resources.keys.sort }
+      end
+      specify { expect(json['@href']).to be == path }
+    end
+
     describe 'with /v3 prefix' do
       let(:path) { '/v3/' }
-      specify(:resources) { expect(json['resources']) .to be == expected_resources }
-      specify(:@href)     { expect(json['@href'])     .to be == '/v3/' }
+      it_behaves_like 'service index'
     end
 
     describe 'with Accept header' do
       let(:headers) { { 'HTTP_ACCEPT' => 'application/vnd.travis-ci.3+json' } }
-      specify(:resources) { expect(json['resources']) .to be == expected_resources }
-      specify(:@href)     { expect(json['@href'])     .to be == '/' }
+      it_behaves_like 'service index'
     end
 
     describe 'with Travis-API-Version header' do
       let(:headers) { { 'HTTP_TRAVIS_API_VERSION' => '3' } }
-      specify(:resources) { expect(json['resources']) .to be == expected_resources }
-      specify(:@href)     { expect(json['@href'])     .to be == '/' }
+      it_behaves_like 'service index'
     end
   end
 
diff --git a/spec/v3/services/account/find_spec.rb b/spec/v3/services/account/find_spec.rb
new file mode 100644
index 00000000..e2c0b2a6
--- /dev/null
+++ b/spec/v3/services/account/find_spec.rb
@@ -0,0 +1,85 @@
+require 'spec_helper'
+
+describe Travis::API::V3::Services::Account::Find do
+  describe "organization" do
+    let(:org) { Organization.new(login: 'example-org') }
+    before    { org.save!                              }
+    after     { org.delete                             }
+
+    describe 'existing org, public api' do
+      before  { get("/v3/account/example-org")   }
+      example { expect(last_response).to be_ok   }
+      example { expect(JSON.load(body)).to be == {
+        "@type"     => "organization",
+        "@href"     => "/v3/org/#{org.id}",
+        "id"        => org.id,
+        "login"     => "example-org",
+        "name"      => nil,
+        "github_id" => nil
+      }}
+    end
+
+    describe "does not allow overriding org id" do
+      let(:other) { Organization.new(login: 'other-org') }
+      before      { other.save!                          }
+      after       { other.delete                         }
+
+      before  { get("/v3/account/example-org?organization.id=#{other.id}") }
+      example { expect(last_response).to be_ok   }
+
+      pending "param whitelisting not yet implemented" do
+        example { expect(JSON.load(body)).to be == {
+          "@type"     => "organization",
+          "@href"     => "/v3/org/#{org.id}",
+          "id"        => org.id,
+          "login"     => "example-org",
+          "name"      => nil,
+          "github_id" => nil
+        }}
+      end
+    end
+  end
+
+  describe "user" do
+    let(:user) { User.new(login: 'example-user') }
+    before     { user.save!                      }
+    after      { user.delete                     }
+
+    describe 'existing user, public api' do
+      before  { get("/v3/account/example-user")   }
+      example { expect(last_response).to be_ok   }
+      example { expect(JSON.load(body)).to be == {
+        "@type"     => "user",
+        "@href"     => "/v3/user/#{user.id}",
+        "id"        => user.id,
+        "login"     => "example-user",
+        "name"      => nil,
+        "github_id" => nil,
+        "is_syncing"=> nil,
+        "synced_at" => nil
+      }}
+    end
+
+    describe "does not allow overriding user id" do
+      let(:other) { User.new(login: 'other-user') }
+      before      { other.save!                   }
+      after       { other.delete                  }
+
+      before  { get("/v3/account/example-org?user.id=#{other.id}") }
+      example { expect(last_response).to be_ok   }
+
+      pending "param whitelisting not yet implemented" do
+        example { expect(JSON.load(body)).to be == {
+          "@type"     => "user",
+          "@href"     => "/v3/user/#{user.id}",
+          "id"        => user.id,
+          "login"     => "example-user",
+          "name"      => nil,
+          "github_id" => nil,
+          "is_syncing"=> nil,
+          "synced_at" => nil
+        }}
+      end
+    end
+  end
+end