diff --git a/Gemfile.lock b/Gemfile.lock
index 19f7e0d9..87d0cc9d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -50,7 +50,7 @@ GIT
 
 GIT
   remote: git://github.com/travis-ci/travis-core.git
-  revision: a82f25fb00a39c3c64b8c09c716c206e6f4c6fad
+  revision: d88d5f84eaea2996c4d325f8f4906d2fdd844125
   specs:
     travis-core (0.0.1)
       actionmailer (~> 3.2.19)
@@ -61,7 +61,7 @@ GIT
       hashr (~> 0.0.19)
       metriks (~> 0.9.7)
       multi_json
-      pusher (~> 0.12.0)
+      pusher (~> 0.14.0)
       railties (~> 3.2.19)
       rake
       redis (~> 3.0)
@@ -95,6 +95,7 @@ PATH
   remote: .
   specs:
     travis-api (0.0.1)
+      composite_primary_keys (~> 5.0)
       memcachier
       mustermann (~> 0.4)
       pg (~> 0.13.2)
@@ -154,6 +155,8 @@ GEM
     coderay (1.1.0)
     coercible (1.0.0)
       descendants_tracker (~> 0.0.1)
+    composite_primary_keys (5.0.14)
+      activerecord (~> 3.2.0, >= 3.2.9)
     connection_pool (2.1.1)
     daemons (1.1.9)
     dalli (2.7.2)
@@ -168,7 +171,7 @@ GEM
     dotenv (0.7.0)
     equalizer (0.0.9)
     erubis (2.7.0)
-    eventmachine (1.0.4)
+    eventmachine (1.0.7)
     factory_girl (2.4.2)
       activesupport
     faraday (0.9.1)
@@ -187,9 +190,9 @@ GEM
     hashr (0.0.22)
     hike (1.2.3)
     hitimes (1.2.2)
-    httpclient (2.3.4.1)
+    httpclient (2.6.0.1)
     i18n (0.6.11)
-    ice_nine (0.11.0)
+    ice_nine (0.11.1)
     journey (1.0.4)
     json (1.8.1)
     kgio (2.9.2)
@@ -224,10 +227,10 @@ GEM
       coderay (~> 1.1.0)
       method_source (~> 0.8.1)
       slop (~> 3.4)
-    pusher (0.12.0)
-      httpclient (~> 2.3.0)
+    pusher (0.14.4)
+      httpclient (~> 2.5)
       multi_json (~> 1.0)
-      signature (~> 0.1.6)
+      signature (~> 0.1.8)
     rack (1.4.5)
     rack-attack (4.2.0)
       rack
@@ -274,7 +277,7 @@ GEM
       json
       redis (>= 3.0.6)
       redis-namespace (>= 1.3.1)
-    signature (0.1.7)
+    signature (0.1.8)
     simple_states (1.0.1)
       activesupport
       hashr (~> 0.0.10)
@@ -324,7 +327,7 @@ GEM
       raindrops (~> 0.7)
     useragent (0.10.0)
     uuidtools (2.1.5)
-    virtus (1.0.3)
+    virtus (1.0.4)
       axiom-types (~> 0.1)
       coercible (~> 1.0)
       descendants_tracker (~> 0.0, >= 0.0.3)
diff --git a/lib/travis/api/app/endpoint/repos.rb b/lib/travis/api/app/endpoint/repos.rb
index f960c8dc..bb5d4311 100644
--- a/lib/travis/api/app/endpoint/repos.rb
+++ b/lib/travis/api/app/endpoint/repos.rb
@@ -98,8 +98,9 @@ class Travis::Api::App
         respond_with service(:find_branches, params), type: :branches, version: :v2
       end
 
-      # Gets lastest build on a branch branches
-      get '/:repository_id/branches/:branch' do
+      # Gets latest build on a branch
+      get '/:repository_id/branches/*' do
+        params[:branch] = params[:splat]
         respond_with service(:find_branch, params), type: :branch, version: :v2
       end
 
@@ -170,8 +171,9 @@ class Travis::Api::App
         respond_with service(:find_branches, params), type: :branches, version: :v2
       end
 
-      # Gets lastest build on a branch branches
-      get '/:owner_name/:name/branches/:branch' do
+      # Gets latest build on a branch
+      get '/:owner_name/:name/branches/*' do
+        params[:branch] = params[:splat]
         respond_with service(:find_branch, params), type: :branch, version: :v2
       end
 
diff --git a/lib/travis/api/v3.rb b/lib/travis/api/v3.rb
index 824f90bd..d2c19859 100644
--- a/lib/travis/api/v3.rb
+++ b/lib/travis/api/v3.rb
@@ -21,6 +21,7 @@ module Travis
       end
 
       extend self
+      load_dir("#{__dir__}/v3/extensions")
       load_dir("#{__dir__}/v3")
 
       ClientError        = Error        .create(status: 400)
diff --git a/lib/travis/api/v3/access_control/generic.rb b/lib/travis/api/v3/access_control/generic.rb
index 8c49dce9..a8e9d2e0 100644
--- a/lib/travis/api/v3/access_control/generic.rb
+++ b/lib/travis/api/v3/access_control/generic.rb
@@ -24,6 +24,10 @@ module Travis::API::V3
       visible? build.repository
     end
 
+    def branch_visible?(branch)
+      visible? branch.repository
+    end
+
     def organization_visible?(organization)
       unrestricted_api?
     end
@@ -52,8 +56,17 @@ module Travis::API::V3
     private
 
     def dispatch(object, method = caller_locations.first.base_label)
-      method = object.class.name.underscore + ?_.freeze + method
+      method = method_for(object.class, method)
       send(method, object) if respond_to?(method, true)
     end
+
+    @@method_for_cache = Tool::ThreadLocal.new
+
+    def method_for(type, method)
+      @@method_for_cache[[type, method]] ||= begin
+        prefix = type.name.sub(/^Travis::API::V3::Models::/, ''.freeze).underscore
+        "#{prefix}_#{method}"
+      end
+    end
   end
 end
diff --git a/lib/travis/api/v3/access_control/user.rb b/lib/travis/api/v3/access_control/user.rb
index 181bb399..ecc54315 100644
--- a/lib/travis/api/v3/access_control/user.rb
+++ b/lib/travis/api/v3/access_control/user.rb
@@ -5,6 +5,7 @@ module Travis::API::V3
     attr_reader :user, :permissions
 
     def initialize(user)
+      user         = Models::User.find(user.id) if user.is_a? ::User
       @user        = user
       @permissions = user.permissions.where(user_id: user.id)
       super()
diff --git a/lib/travis/api/v3/extensions/belongs_to.rb b/lib/travis/api/v3/extensions/belongs_to.rb
new file mode 100644
index 00000000..28aaa918
--- /dev/null
+++ b/lib/travis/api/v3/extensions/belongs_to.rb
@@ -0,0 +1,49 @@
+module Travis::API::V3
+  module Extensions
+    # This is a patch to ActiveRecord to allow classes for polymorphic relations to be nested in a module without the
+    # module name being part of the type field.
+    #
+    # Example:
+    #
+    #     # Without this patch
+    #     Repository.find(2).owner.class                          # => User
+    #     Travis::API::V3::Models::Repository.find(2).owner.class # => User
+    #
+    #     # With this patch
+    #     Repository.find(2).owner.class                          # => User
+    #     Travis::API::V3::Models::Repository.find(2).owner.class # => Travis::API::V3::Models::User
+    #
+    # ActiveRecord does not support this out of the box. We accomplish this feature by tracking polymorphic relations
+    # and then adding the namespace when calling ActiveRecord::Base#[] with the foreign type key and removing it again
+    # in ActiveRecord::Base#[]=, so we don't break other code by accidentially writing the prefixed version to the
+    # database.
+    module BelongsTo
+      module ClassMethods
+        def polymorfic_foreign_types
+          @polymorfic_foreign_types ||= []
+        end
+
+        def belongs_to(field, options = {})
+          polymorfic_foreign_types << (options[:foreign_type] || "#{field}_type") if options[:polymorphic]
+          super
+        end
+      end
+
+      def self.included(base)
+        base.extend(ClassMethods)
+        super
+      end
+
+      def [](key)
+        value   = super
+        value &&= "#{self.class.parent}::#{value}" if self.class.polymorfic_foreign_types.include?(key)
+        value
+      end
+
+      def []=(key, value)
+        value &&= value.sub("#{self.class.parent}::", ''.freeze) if self.class.polymorfic_foreign_types.include?(key)
+        super(key, value)
+      end
+    end
+  end
+end
diff --git a/lib/travis/api/v3/model.rb b/lib/travis/api/v3/model.rb
new file mode 100644
index 00000000..90b26d1d
--- /dev/null
+++ b/lib/travis/api/v3/model.rb
@@ -0,0 +1,6 @@
+module Travis::API::V3
+  class Model < ActiveRecord::Base
+    include Extensions::BelongsTo
+    self.abstract_class = true
+  end
+end
diff --git a/lib/travis/api/v3/models.rb b/lib/travis/api/v3/models.rb
new file mode 100644
index 00000000..d12287b3
--- /dev/null
+++ b/lib/travis/api/v3/models.rb
@@ -0,0 +1,7 @@
+require 'composite_primary_keys'
+
+module Travis::API::V3
+  module Models
+    extend ConstantResolver
+  end
+end
diff --git a/lib/travis/api/v3/models/branch.rb b/lib/travis/api/v3/models/branch.rb
new file mode 100644
index 00000000..faa7259e
--- /dev/null
+++ b/lib/travis/api/v3/models/branch.rb
@@ -0,0 +1,8 @@
+module Travis::API::V3
+  class Models::Branch < Model
+    belongs_to :repository
+    belongs_to :last_build, class_name: 'Travis::API::V3::Models::Build'.freeze
+    has_many   :builds,  foreign_key: [:repository_id, :branch], primary_key: [:repository_id, :name], order: 'id DESC'.freeze, conditions: { event_type: 'push' }
+    has_many   :commits, foreign_key: [:repository_id, :branch], primary_key: [:repository_id, :name], order: 'id DESC'.freeze
+  end
+end
diff --git a/lib/travis/api/v3/models/broadcast.rb b/lib/travis/api/v3/models/broadcast.rb
new file mode 100644
index 00000000..9c713d8e
--- /dev/null
+++ b/lib/travis/api/v3/models/broadcast.rb
@@ -0,0 +1,5 @@
+module Travis::API::V3
+  class Models::Broadcast < Model
+    belongs_to :recipient, polymorphic: true
+  end
+end
diff --git a/lib/travis/api/v3/models/build.rb b/lib/travis/api/v3/models/build.rb
new file mode 100644
index 00000000..9b7f766b
--- /dev/null
+++ b/lib/travis/api/v3/models/build.rb
@@ -0,0 +1,10 @@
+module Travis::API::V3
+  class Models::Build < Model
+    belongs_to :repository
+    belongs_to :commit
+    belongs_to :request
+    belongs_to :repository, autosave: true
+    belongs_to :owner, polymorphic: true
+    has_many   :jobs, as: :source, order: :id, dependent: :destroy
+  end
+end
diff --git a/lib/travis/api/v3/models/commit.rb b/lib/travis/api/v3/models/commit.rb
new file mode 100644
index 00000000..ac1add22
--- /dev/null
+++ b/lib/travis/api/v3/models/commit.rb
@@ -0,0 +1,6 @@
+module Travis::API::V3
+  class Models::Commit < Model
+    belongs_to :repository
+    has_one    :request
+  end
+end
diff --git a/lib/travis/api/v3/models/email.rb b/lib/travis/api/v3/models/email.rb
new file mode 100644
index 00000000..6fd9cd7e
--- /dev/null
+++ b/lib/travis/api/v3/models/email.rb
@@ -0,0 +1,5 @@
+module Travis::API::V3
+  class Models::Email < Model
+    belongs_to :user
+  end
+end
diff --git a/lib/travis/api/v3/models/job.rb b/lib/travis/api/v3/models/job.rb
new file mode 100644
index 00000000..2db5df10
--- /dev/null
+++ b/lib/travis/api/v3/models/job.rb
@@ -0,0 +1,10 @@
+module Travis::API::V3
+  class Models::Job < Model
+    has_one    :log, dependent: :destroy
+    belongs_to :repository
+    belongs_to :commit
+    belongs_to :build, autosave: true, foreign_key: 'source_id'
+    belongs_to :owner, polymorphic: true
+    serialize :config
+  end
+end
diff --git a/lib/travis/api/v3/models/log.rb b/lib/travis/api/v3/models/log.rb
new file mode 100644
index 00000000..d1c3219b
--- /dev/null
+++ b/lib/travis/api/v3/models/log.rb
@@ -0,0 +1,7 @@
+module Travis::API::V3
+  class Models::Log < Model
+    belongs_to :job
+    belongs_to :removed_by, class_name: 'User', foreign_key: :removed_by
+    has_many  :log_parts, dependent: :destroy
+  end
+end
diff --git a/lib/travis/api/v3/models/log_part.rb b/lib/travis/api/v3/models/log_part.rb
new file mode 100644
index 00000000..43fc7370
--- /dev/null
+++ b/lib/travis/api/v3/models/log_part.rb
@@ -0,0 +1,5 @@
+module Travis::API::V3
+  class Models::LogPart < Model
+    belongs_to :log
+  end
+end
diff --git a/lib/travis/api/v3/models/membership.rb b/lib/travis/api/v3/models/membership.rb
new file mode 100644
index 00000000..b32fe2ea
--- /dev/null
+++ b/lib/travis/api/v3/models/membership.rb
@@ -0,0 +1,6 @@
+module Travis::API::V3
+  class Models::Membership < Model
+    belongs_to :user
+    belongs_to :organization
+  end
+end
diff --git a/lib/travis/api/v3/models/organization.rb b/lib/travis/api/v3/models/organization.rb
new file mode 100644
index 00000000..e42e3364
--- /dev/null
+++ b/lib/travis/api/v3/models/organization.rb
@@ -0,0 +1,7 @@
+module Travis::API::V3
+  class Models::Organization < Model
+    has_many :memberships
+    has_many :users, through: :memberships
+    has_many :repositories, as: :owner
+  end
+end
diff --git a/lib/travis/api/v3/models/permission.rb b/lib/travis/api/v3/models/permission.rb
new file mode 100644
index 00000000..7c592903
--- /dev/null
+++ b/lib/travis/api/v3/models/permission.rb
@@ -0,0 +1,6 @@
+module Travis::API::V3
+  class Models::Permission < Model
+    belongs_to :user
+    belongs_to :repository
+  end
+end
diff --git a/lib/travis/api/v3/models/repository.rb b/lib/travis/api/v3/models/repository.rb
new file mode 100644
index 00000000..3563a17c
--- /dev/null
+++ b/lib/travis/api/v3/models/repository.rb
@@ -0,0 +1,56 @@
+module Travis::API::V3
+  class Models::Repository < Model
+    has_many :commits,     dependent: :delete_all
+    has_many :requests,    dependent: :delete_all
+    has_many :branches,    dependent: :delete_all, order: 'id DESC'.freeze
+    has_many :builds,      dependent: :delete_all, order: 'id DESC'.freeze
+    has_many :permissions, dependent: :delete_all
+    has_many :users,       through:   :permissions
+
+    belongs_to :owner, polymorphic: true
+
+    has_one :last_build,
+      class_name: 'Travis::API::V3::Models::Build'.freeze,
+      order:      'id DESC'.freeze
+
+    has_one :default_branch,
+      foreign_key: [:repository_id, :name],
+      primary_key: [:id,  :default_branch],
+      class_name:  'Travis::API::V3::Models::Branch'.freeze
+
+    after_initialize do
+      update_attributes! default_branch_name: 'master'.freeze unless default_branch_name
+    end
+
+    def slug
+      @slug ||= "#{owner_name}/#{name}"
+    end
+
+    def default_branch_name
+      read_attribute(:default_branch)
+    end
+
+    def default_branch_name=(value)
+      write_attribute(:default_branch, value)
+    end
+
+    def default_branch
+      super || branch(default_branch_name, create_without_build: true)
+    end
+
+    # Creates a branch object on the fly if it doesn't exist.
+    #
+    # Will not create a branch object if we don't have any builds for it unless
+    # the create_without_build option is set to true.
+    def branch(name, create_without_build: false)
+      return nil    unless branch = branches.where(name: name).first_or_initialize
+      return branch unless branch.new_record?
+      return nil    unless create_without_build or branch.builds.any?
+      branch.last_build = branch.builds.first
+      branch.save!
+      branch
+    rescue ActiveRecord::RecordNotUnique
+      branches.where(name: name).first
+    end
+  end
+end
diff --git a/lib/travis/api/v3/models/request.rb b/lib/travis/api/v3/models/request.rb
new file mode 100644
index 00000000..fd1387a8
--- /dev/null
+++ b/lib/travis/api/v3/models/request.rb
@@ -0,0 +1,10 @@
+module Travis::API::V3
+  class Models::Request < Model
+    belongs_to :commit
+    belongs_to :repository
+    belongs_to :owner, polymorphic: true
+    has_many   :builds
+    serialize  :config
+    serialize  :payload
+  end
+end
diff --git a/lib/travis/api/v3/models/ssl_key.rb b/lib/travis/api/v3/models/ssl_key.rb
new file mode 100644
index 00000000..eb45758c
--- /dev/null
+++ b/lib/travis/api/v3/models/ssl_key.rb
@@ -0,0 +1,5 @@
+module Travis::API::V3
+  class Models::SSLKey < Model
+    belongs_to :repository
+  end
+end
diff --git a/lib/travis/api/v3/models/user.rb b/lib/travis/api/v3/models/user.rb
new file mode 100644
index 00000000..c07f3a4b
--- /dev/null
+++ b/lib/travis/api/v3/models/user.rb
@@ -0,0 +1,9 @@
+module Travis::API::V3
+  class Models::User < Model
+    has_many :memberships,   dependent: :destroy
+    has_many :organizations, through: :memberships
+    has_many :permissions,   dependent: :destroy
+    has_many :repositories,  through: :permissions
+    has_many :emails,        dependent: :destroy
+  end
+end
diff --git a/lib/travis/api/v3/queries/branch.rb b/lib/travis/api/v3/queries/branch.rb
new file mode 100644
index 00000000..145b7b02
--- /dev/null
+++ b/lib/travis/api/v3/queries/branch.rb
@@ -0,0 +1,10 @@
+module Travis::API::V3
+  class Queries::Branch < Query
+    params :name
+
+    def find(repository)
+      return repository.branch(name) if name
+      raise WrongParams, 'missing branch.name'.freeze
+    end
+  end
+end
diff --git a/lib/travis/api/v3/queries/build.rb b/lib/travis/api/v3/queries/build.rb
index 7d1594a2..1f97e7c7 100644
--- a/lib/travis/api/v3/queries/build.rb
+++ b/lib/travis/api/v3/queries/build.rb
@@ -3,8 +3,8 @@ module Travis::API::V3
     params :id
 
     def find
-      return ::Build.find_by_id(id) if id
-      raise WrongParams
+      return Models::Build.find_by_id(id) if id
+      raise WrongParams, 'missing build.id'.freeze
     end
   end
 end
diff --git a/lib/travis/api/v3/queries/organization.rb b/lib/travis/api/v3/queries/organization.rb
index a88f412c..8c07c910 100644
--- a/lib/travis/api/v3/queries/organization.rb
+++ b/lib/travis/api/v3/queries/organization.rb
@@ -3,8 +3,8 @@ module Travis::API::V3
     params :id
 
     def find
-      return ::Organization.find_by_id(id) if id
-      raise WrongParams
+      return Models::Organization.find_by_id(id) if id
+      raise WrongParams, 'missing organization.id'.freeze
     end
   end
 end
diff --git a/lib/travis/api/v3/queries/organizations.rb b/lib/travis/api/v3/queries/organizations.rb
index 42d84d4f..faa3f68b 100644
--- a/lib/travis/api/v3/queries/organizations.rb
+++ b/lib/travis/api/v3/queries/organizations.rb
@@ -1,7 +1,7 @@
 module Travis::API::V3
   class Queries::Organizations < Query
     def for_member(user)
-      ::Organization.joins(:users).where(users: user_condition(user))
+      Models::Organization.joins(:users).where(users: user_condition(user))
     end
   end
 end
diff --git a/lib/travis/api/v3/queries/repositories.rb b/lib/travis/api/v3/queries/repositories.rb
index 1f4c0c22..bc374e7b 100644
--- a/lib/travis/api/v3/queries/repositories.rb
+++ b/lib/travis/api/v3/queries/repositories.rb
@@ -8,9 +8,10 @@ module Travis::API::V3
 
     def all
       @all ||= begin
-        all = ::Repository
+        all = Models::Repository
         all = all.where(active:  bool(active))  unless active.nil?
         all = all.where(private: bool(private)) unless private.nil?
+        all = all.includes(:default_branch) # TODO: use includes params
         all
       end
     end
diff --git a/lib/travis/api/v3/queries/repository.rb b/lib/travis/api/v3/queries/repository.rb
index fa1e6d35..d8ceaff9 100644
--- a/lib/travis/api/v3/queries/repository.rb
+++ b/lib/travis/api/v3/queries/repository.rb
@@ -3,8 +3,8 @@ module Travis::API::V3
     params :id
 
     def find
-      return ::Repository.find_by_id(id) if id
-      raise WrongParams
+      return Models::Repository.find_by_id(id) if id
+      raise WrongParams, 'missing repository.id'.freeze
     end
   end
 end
diff --git a/lib/travis/api/v3/query.rb b/lib/travis/api/v3/query.rb
index 3676065f..48989490 100644
--- a/lib/travis/api/v3/query.rb
+++ b/lib/travis/api/v3/query.rb
@@ -46,9 +46,9 @@ module Travis::API::V3
 
     def user_condition(value)
       case value
-      when String  then { login: value    }
-      when Integer then { id:    value    }
-      when ::User  then { id:    value.id }
+      when String       then { login: value    }
+      when Integer      then { id:    value    }
+      when Models::User then { id:    value.id }
       else raise WrongParams
       end
     end
diff --git a/lib/travis/api/v3/renderer.rb b/lib/travis/api/v3/renderer.rb
index d4fb7735..3747cd61 100644
--- a/lib/travis/api/v3/renderer.rb
+++ b/lib/travis/api/v3/renderer.rb
@@ -10,13 +10,22 @@ module Travis::API::V3
       args.select { |key, value| !value.nil? }
     end
 
-    def href(type, script_name: nil, **args)
-      expander     = EXPANDER_CACHE[[type, script_name, args.keys]] ||= begin
-        resource   = Routes.resources.detect { |r| r.identifier == type }
-        unprefixed = args.keys.reject { |a| a.to_s.include? ?..freeze }
-        route      = resource.route
-        route    &&= Mustermann.new(script_name, type: :identity) + route if script_name and not script_name.empty?
-        generate_expander(route, type, unprefixed)
+    def href(type, string_args = nil, script_name: nil, **args)
+      args.merge! string_args if string_args
+
+      expander      = EXPANDER_CACHE[[type, script_name, args.keys]] ||= begin
+        resource    = Routes.resources.detect { |r| r.identifier == type }
+        route       = resource.route
+        route     &&= Mustermann.new(script_name, type: :identity) + route if script_name and not script_name.empty?
+        key_mapping = {}
+        args.keys.each do |key|
+          case key.to_s
+          when /\./        then key_mapping[key.to_sym]        = key unless key.is_a? Symbol
+          when /^(.+)_id$/ then key_mapping[:"#{$1}.id"]       = key
+          else                  key_mapping[:"#{type}.#{key}"] = key
+          end
+        end
+        generate_expander(route, key_mapping)
       end
 
       expander.call(args)
@@ -24,11 +33,11 @@ module Travis::API::V3
 
     private
 
-    def generate_expander(route, prefix, unprefixed)
+    def generate_expander(route, key_mapping)
       return proc { |**| } unless route.respond_to? :expand
-      proc do |**args|
-        unprefixed.each { |key| args[:"#{prefix}.#{key}"] = args.delete(key) }
-        route.expand(**args)
+      proc do |args|
+        key_mapping.each { |a, b| args[a] = args.delete(b) }
+        route.expand(:ignore, **args)
       end
     end
   end
diff --git a/lib/travis/api/v3/renderer/branch.rb b/lib/travis/api/v3/renderer/branch.rb
new file mode 100644
index 00000000..80445497
--- /dev/null
+++ b/lib/travis/api/v3/renderer/branch.rb
@@ -0,0 +1,8 @@
+require 'travis/api/v3/renderer/model_renderer'
+
+module Travis::API::V3
+  class Renderer::Branch < Renderer::ModelRenderer
+    representation(:minimal,  :name, :last_build)
+    representation(:standard, :name, :repository, :last_build)
+  end
+end
diff --git a/lib/travis/api/v3/renderer/model_renderer.rb b/lib/travis/api/v3/renderer/model_renderer.rb
index 0c508172..0be52876 100644
--- a/lib/travis/api/v3/renderer/model_renderer.rb
+++ b/lib/travis/api/v3/renderer/model_renderer.rb
@@ -33,8 +33,8 @@ module Travis::API::V3
 
     def href
       return @href if defined? @href # allows setting href to nil
-      return unless self.class.type and model.respond_to? :id and model.id
-      @href = Renderer.href(self.class.type, script_name: script_name, id: model.id)
+      return unless self.class.type and model.respond_to? :attributes
+      @href = Renderer.href(self.class.type, model.attributes, script_name: script_name)
     end
 
     def render(representation)
@@ -47,17 +47,17 @@ module Travis::API::V3
       result
     end
 
-    def render_model(model, type: model.class.name.to_sym, mode: :minimal, **options)
+    def render_model(model, type: model.class.name[/[^:]+$/].to_sym, mode: :minimal, **options)
       Renderer[type].render(model, mode, script_name: script_name, **options)
     end
 
     def render_value(value)
       case value
-      when Hash          then value.map { |k, v| [k, render_value(v)] }.to_h
-      when Array         then value.map { |v   | render_value(v)      }
-      when *PRIMITIVE    then value
-      when Time          then value.strftime('%Y-%m-%dT%H:%M:%SZ')
-      when Travis::Model then render_model(value)
+      when Hash        then value.map { |k, v| [k, render_value(v)] }.to_h
+      when Array       then value.map { |v   | render_value(v)      }
+      when *PRIMITIVE  then value
+      when Time        then value.strftime('%Y-%m-%dT%H:%M:%SZ')
+      when Model       then render_model(value)
       else raise ArgumentError, 'cannot render %p (%p)' % [value.class, value]
       end
     end
diff --git a/lib/travis/api/v3/renderer/repository.rb b/lib/travis/api/v3/renderer/repository.rb
index f807b299..947ea727 100644
--- a/lib/travis/api/v3/renderer/repository.rb
+++ b/lib/travis/api/v3/renderer/repository.rb
@@ -5,15 +5,6 @@ module Travis::API::V3
     representation(:minimal,  :id, :slug)
     representation(:standard, :id, :name, :slug, :description, :github_language, :active, :private, :owner, :last_build, :default_branch)
 
-    def default_branch
-      branch_name = model.default_branch || 'master'.freeze
-      {
-        :@type      => 'branch'.freeze,
-        :name       => branch_name,
-        :last_build => model.last_build_on(branch_name)
-      }
-    end
-
     def active
       !!model.active
     end
diff --git a/lib/travis/api/v3/routes.rb b/lib/travis/api/v3/routes.rb
index 83343ad8..80e6a214 100644
--- a/lib/travis/api/v3/routes.rb
+++ b/lib/travis/api/v3/routes.rb
@@ -15,6 +15,11 @@ module Travis::API::V3
         get  :find
         post :create
       end
+
+      resource :branch do
+        route '/branch/{branch.name}'
+        get :find
+      end
     end
 
     resource :repositories do
diff --git a/lib/travis/api/v3/routes/dsl.rb b/lib/travis/api/v3/routes/dsl.rb
index e4e08df2..fbd71c8f 100644
--- a/lib/travis/api/v3/routes/dsl.rb
+++ b/lib/travis/api/v3/routes/dsl.rb
@@ -34,7 +34,7 @@ module Travis::API::V3
     end
 
     def route(value)
-      current_resource.route = prefix + value
+      current_resource.route = Mustermann.new(prefix) + Mustermann.new(value)
     end
 
     def get(*args)
diff --git a/lib/travis/api/v3/services.rb b/lib/travis/api/v3/services.rb
index 5e543412..e5180864 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
 
+    Branch        = Module.new { extend Services }
     Build         = Module.new { extend Services }
     Organization  = Module.new { extend Services }
     Organizations = Module.new { extend Services }
diff --git a/lib/travis/api/v3/services/branch/find.rb b/lib/travis/api/v3/services/branch/find.rb
new file mode 100644
index 00000000..927b1a87
--- /dev/null
+++ b/lib/travis/api/v3/services/branch/find.rb
@@ -0,0 +1,7 @@
+module Travis::API::V3
+  class Services::Branch::Find < Service
+    def run!
+      find(:branch, find(:repository))
+    end
+  end
+end
diff --git a/spec/integration/v2/repositories_spec.rb b/spec/integration/v2/repositories_spec.rb
index e40518e2..dfa86220 100644
--- a/spec/integration/v2/repositories_spec.rb
+++ b/spec/integration/v2/repositories_spec.rb
@@ -134,6 +134,30 @@ describe 'Repos' do
     JSON.parse(result.body).should == { 'file' => 'not found' }
   end
 
+  it 'GET /repos/svenfuchs/minimal/branches' do
+    response = get '/repos/svenfuchs/minimal/branches', {}, headers
+    response.should deliver_json_for(repo.last_finished_builds_by_branches, version: 'v2', type: 'branches')
+  end
+
+  it 'GET /repos/1/branches' do
+    response = get "/repos/#{repo.id}/branches", {}, headers
+    response.should deliver_json_for(repo.last_finished_builds_by_branches, version: 'v2', type: 'branches')
+  end
+
+  it 'GET /repos/svenfuchs/minimal/branches/mybranch' do
+    mybuild = Factory(:build, repository: repo, state: :started, commit: Factory(:commit, branch: 'mybranch'), request: Factory(:request, event_type: 'push'))
+    response = get "/repos/svenfuchs/minimal/branches/mybranch", {}, headers
+    body = JSON.parse(response.body)
+    body['branch']['id'].should == mybuild.id
+  end
+
+  it 'GET /repos/svenfuchs/minimal/branches/my/branch' do
+    mybuild = Factory(:build, repository: repo, state: :started, commit: Factory(:commit, branch: 'my/branch'), request: Factory(:request, event_type: 'push'))
+    response = get "/repos/svenfuchs/minimal/branches/my/branch", {}, headers
+    body = JSON.parse(response.body)
+    body['branch']['id'].should == mybuild.id
+  end
+
   describe 'GET /repos/svenfuchs/minimal.png?branch=foo,bar' do
     let(:on_foo) { Factory(:commit, branch: 'foo') }
     let(:on_bar) { Factory(:commit, branch: 'bar') }
diff --git a/spec/v3/extensions/belongs_to_spec.rb b/spec/v3/extensions/belongs_to_spec.rb
new file mode 100644
index 00000000..dd031ab5
--- /dev/null
+++ b/spec/v3/extensions/belongs_to_spec.rb
@@ -0,0 +1,17 @@
+require 'spec_helper'
+
+describe Travis::API::V3::Extensions::BelongsTo do
+  describe 'reading polymorphic relation' do
+    subject(:repo) { Travis::API::V3::Models::Repository.first }
+    example { expect(repo.owner).to be_a(Travis::API::V3::Models::User) }
+  end
+
+  describe 'writing polymorphic relation' do
+    let(:repo) { Travis::API::V3::Models::Repository.create(owner: user) }
+    let(:user) { Travis::API::V3::Models::User.create }
+    after      { repo.destroy; user.destroy }
+
+    example { expect(repo.owner).to be_a(Travis::API::V3::Models::User) }
+    example { expect(::Repository.find(repo.id).owner).to be_a(::User)  }
+  end
+end
\ No newline at end of file
diff --git a/spec/v3/service_index_spec.rb b/spec/v3/service_index_spec.rb
index 325392e0..25f198ad 100644
--- a/spec/v3/service_index_spec.rb
+++ b/spec/v3/service_index_spec.rb
@@ -14,6 +14,8 @@ describe Travis::API::V3::ServiceIndex do
         "disable"           => [{"request-method"=>"POST",  "uri-template"=>"#{path}repo/{repository.id}/disable"}] },
       "repositories"        =>  {
         "for_current_user"  => [{"request-method"=>"GET",  "uri-template"=>"#{path}repos"}] },
+      "branch"              =>  {
+        "find"              => [{"request-method"=>"GET",  "uri-template"=>"#{path}repo/{repository.id}/branch/{branch.name}"}]},
       "build"               =>  {
         "find"              => [{"request-method"=>"GET",  "uri-template"=>"#{path}build/{build.id}"}] },
       "organizations"       =>  {
diff --git a/spec/v3/services/branch/find_spec.rb b/spec/v3/services/branch/find_spec.rb
new file mode 100644
index 00000000..8d909aa1
--- /dev/null
+++ b/spec/v3/services/branch/find_spec.rb
@@ -0,0 +1,29 @@
+require 'spec_helper'
+
+describe Travis::API::V3::Services::Repository::Find do
+  let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first }
+  before { repo.default_branch.save! }
+
+  describe "public repository, existing branch" do
+    before     { get("/v3/repo/#{repo.id}/branch/master") }
+    example    { expect(last_response).to be_ok           }
+    example    { expect(JSON.load(body)).to be ==         {
+      "@type"         => "branch",
+      "@href"         => "/v3/repo/#{repo.id}/branch/master",
+      "name"          => "master",
+      "repository"    => {
+        "@type"       => "repository",
+        "@href"       => "/v3/repo/#{repo.id}",
+        "id"          => repo.id,
+        "slug"        => "svenfuchs/minimal"},
+      "last_build"    => {
+        "@type"       => "build",
+        "@href"       => "/v3/build/#{repo.last_build.id}",
+        "id"          => repo.last_build.id,
+        "number"      => "3",
+        "state"       => "configured",
+        "duration"    => nil,
+        "started_at"  => "2010-11-12T13:00:00Z",
+        "finished_at" => nil}}}
+  end
+end
\ No newline at end of file
diff --git a/spec/v3/services/repositories/for_current_user_spec.rb b/spec/v3/services/repositories/for_current_user_spec.rb
index 4f61803b..042cdae3 100644
--- a/spec/v3/services/repositories/for_current_user_spec.rb
+++ b/spec/v3/services/repositories/for_current_user_spec.rb
@@ -40,6 +40,7 @@ describe Travis::API::V3::Services::Repositories::ForCurrentUser do
           "finished_at"   => "2010-11-12T12:30:20Z"},
         "default_branch"  => {
           "@type"         => "branch",
+          "@href"         => "/v3/repo/#{repo.id}/branch/master",
           "name"          => "master",
           "last_build"    => {
             "@type"       => "build",
diff --git a/spec/v3/services/repository/find_spec.rb b/spec/v3/services/repository/find_spec.rb
index 292a1d2c..9cce296f 100644
--- a/spec/v3/services/repository/find_spec.rb
+++ b/spec/v3/services/repository/find_spec.rb
@@ -31,6 +31,7 @@ describe Travis::API::V3::Services::Repository::Find do
         "finished_at"   => "2010-11-12T12:30:20Z"},
       "default_branch"  => {
         "@type"         => "branch",
+        "@href"         => "/v3/repo/#{repo.id}/branch/master",
         "name"          => "master",
         "last_build"    => {
           "@type"       => "build",
@@ -114,6 +115,7 @@ describe Travis::API::V3::Services::Repository::Find do
         "finished_at"   => "2010-11-12T12:30:20Z"},
       "default_branch"  => {
         "@type"         => "branch",
+        "@href"         => "/v3/repo/#{repo.id}/branch/master",
         "name"          => "master",
         "last_build"    => {
           "@type"       => "build",
@@ -182,6 +184,7 @@ describe Travis::API::V3::Services::Repository::Find do
         "finished_at"   => "2010-11-12T12:30:20Z"},
       "default_branch"  => {
         "@type"         => "branch",
+        "@href"         => "/v3/repo/#{repo.id}/branch/master",
         "name"          => "master",
         "last_build"    => {
           "@type"       => "build",
@@ -256,6 +259,7 @@ describe Travis::API::V3::Services::Repository::Find do
         "finished_at"   => "2010-11-12T12:30:20Z"},
       "default_branch"  => {
         "@type"         => "branch",
+        "@href"         => "/v3/repo/#{repo.id}/branch/master",
         "name"          => "master",
         "last_build"    => {
           "@type"       => "build",
diff --git a/travis-api.gemspec b/travis-api.gemspec
index d4e1c079..548ced44 100644
--- a/travis-api.gemspec
+++ b/travis-api.gemspec
@@ -288,14 +288,15 @@ Gem::Specification.new do |s|
   s.add_dependency 'travis-support'
   s.add_dependency 'travis-core'
 
-  s.add_dependency 'pg',              '~> 0.13.2'
-  s.add_dependency 'thin',            '~> 1.4'
-  s.add_dependency 'sinatra',         '~> 1.3'
-  s.add_dependency 'sinatra-contrib', '~> 1.3'
-  s.add_dependency 'mustermann',      '~> 0.4'
-  s.add_dependency 'redcarpet',       '~> 2.1'
-  s.add_dependency 'rack-ssl',        '~> 1.3', '>= 1.3.3'
-  s.add_dependency 'rack-contrib',    '~> 1.1'
+  s.add_dependency 'pg',                     '~> 0.13.2'
+  s.add_dependency 'composite_primary_keys', '~> 5.0'
+  s.add_dependency 'thin',                   '~> 1.4'
+  s.add_dependency 'sinatra',                '~> 1.3'
+  s.add_dependency 'sinatra-contrib',        '~> 1.3'
+  s.add_dependency 'mustermann',             '~> 0.4'
+  s.add_dependency 'redcarpet',              '~> 2.1'
+  s.add_dependency 'rack-ssl',               '~> 1.3', '>= 1.3.3'
+  s.add_dependency 'rack-contrib',           '~> 1.1'
   s.add_dependency 'memcachier'
   s.add_dependency 'useragent'
 end