diff --git a/Makefile b/Makefile
index 9dad28910..d09d31ed5 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ JAVASCRIPTS :=
 LDFLAGS := -X "main.Version=$(shell git describe --tags --always | sed 's/-/+/' | sed 's/^v//')" -X "main.Tags=$(TAGS)"
 
 TARGETS ?= linux/*,darwin/*,windows/*
-PACKAGES ?= $(shell go list ./... | grep -v /vendor/)
+PACKAGES ?= $(filter-out code.gitea.io/gitea/integrations,$(shell go list ./... | grep -v /vendor/))
 SOURCES ?= $(shell find . -name "*.go" -type f)
 
 TAGS ?=
@@ -66,6 +66,11 @@ lint:
 	fi
 	for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done;
 
+.PHONY: integrations
+integrations: TAGS=bindata sqlite
+integrations: build
+	go test code.gitea.io/gitea/integrations
+
 .PHONY: test
 test:
 	for PKG in $(PACKAGES); do go test -cover -coverprofile $$GOPATH/src/$$PKG/coverage.out $$PKG || exit 1; done;
diff --git a/integrations/install_test.go b/integrations/install_test.go
new file mode 100644
index 000000000..96d0ce178
--- /dev/null
+++ b/integrations/install_test.go
@@ -0,0 +1,97 @@
+// Copyright 2017 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package integration
+
+import (
+	"fmt"
+	"net/http"
+	"os"
+	"os/user"
+	"path/filepath"
+	"testing"
+	"time"
+
+	"code.gitea.io/gitea/integrations/internal/utils"
+)
+
+// The HTTP port listened by the Gitea server.
+const ServerHTTPPort = "3001"
+
+const _RetryLimit = 10
+
+func makeSimpleSettings(user, workdir, port string) map[string][]string {
+	return map[string][]string{
+		"db_type":        {"SQLite3"},
+		"db_host":        {"localhost"},
+		"db_path":        {workdir + "data/gitea.db"},
+		"app_name":       {"Gitea: Git with a cup of tea"},
+		"repo_root_path": {workdir + "repositories"},
+		"run_user":       {user},
+		"domain":         {"localhost"},
+		"ssh_port":       {"22"},
+		"http_port":      {port},
+		"app_url":        {"http://localhost:" + port},
+		"log_root_path":  {workdir + "log"},
+	}
+}
+
+func install(t *utils.T) error {
+	var r *http.Response
+	var err error
+
+	for i := 1; i <= _RetryLimit; i++ {
+
+		r, err = http.Get("http://:" + ServerHTTPPort + "/")
+		if err == nil {
+			fmt.Fprintln(os.Stderr)
+			break
+		}
+
+		// Give the server some amount of time to warm up.
+		time.Sleep(100 * time.Millisecond)
+		fmt.Fprint(os.Stderr, ".")
+	}
+
+	if err != nil {
+		return err
+	}
+
+	defer r.Body.Close()
+
+	_user, err := user.Current()
+	if err != nil {
+		return err
+	}
+
+	path, err := filepath.Abs(t.Config.WorkDir)
+	if err != nil {
+		return err
+	}
+
+	settings := makeSimpleSettings(_user.Username, path, ServerHTTPPort)
+	r, err = http.PostForm("http://:"+ServerHTTPPort+"/install", settings)
+	if err != nil {
+		return err
+	}
+	defer r.Body.Close()
+
+	if r.StatusCode != http.StatusOK {
+		return fmt.Errorf("'/install': %s", r.Status)
+	}
+	return nil
+}
+
+func TestInstall(t *testing.T) {
+	conf := utils.Config{
+		Program: "../gitea",
+		WorkDir: "",
+		Args:    []string{"web", "--port", ServerHTTPPort},
+		LogFile: os.Stderr,
+	}
+
+	if err := utils.New(t, &conf).RunTest(install); err != nil {
+		t.Fatal(err)
+	}
+}
diff --git a/integrations/internal/utils/utils.go b/integrations/internal/utils/utils.go
new file mode 100644
index 000000000..511fa478b
--- /dev/null
+++ b/integrations/internal/utils/utils.go
@@ -0,0 +1,125 @@
+// Copyright 2017 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package utils
+
+import (
+	"errors"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"syscall"
+	"testing"
+)
+
+// T wraps testing.T and the configurations of the testing instance.
+type T struct {
+	*testing.T
+	Config *Config
+}
+
+// New create an instance of T
+func New(t *testing.T, c *Config) *T {
+	return &T{T: t, Config: c}
+}
+
+// Config Settings of the testing program
+type Config struct {
+	// The executable path of the tested program.
+	Program string
+	// Working directory prepared for the tested program.
+	// If empty, a directory named with random suffixes is picked, and created under the platform-dependent default temporary directory.
+	// The directory will be removed when the test finishes.
+	WorkDir string
+	// Command-line arguments passed to the tested program.
+	Args []string
+
+	// Where to redirect the stdout/stderr to. For debugging purposes.
+	LogFile *os.File
+}
+
+func redirect(cmd *exec.Cmd, f *os.File) error {
+	stdout, err := cmd.StdoutPipe()
+	if err != nil {
+		return err
+	}
+
+	stderr, err := cmd.StderrPipe()
+	if err != nil {
+		return err
+	}
+
+	go io.Copy(f, stdout)
+	go io.Copy(f, stderr)
+	return nil
+}
+
+// RunTest Helper function for setting up a running Gitea server for functional testing and then gracefully terminating it.
+func (t *T) RunTest(tests ...func(*T) error) (err error) {
+	if t.Config.Program == "" {
+		return errors.New("Need input file")
+	}
+
+	path, err := filepath.Abs(t.Config.Program)
+	if err != nil {
+		return err
+	}
+
+	workdir := t.Config.WorkDir
+	if workdir == "" {
+		workdir, err = ioutil.TempDir(os.TempDir(), "gitea_tests-")
+		if err != nil {
+			return err
+		}
+		defer os.RemoveAll(workdir)
+	}
+
+	newpath := filepath.Join(workdir, filepath.Base(path))
+	if err := os.Symlink(path, newpath); err != nil {
+		return err
+	}
+
+	log.Printf("Starting the server: %s args:%s workdir:%s", newpath, t.Config.Args, workdir)
+
+	cmd := exec.Command(newpath, t.Config.Args...)
+	cmd.Dir = workdir
+
+	if t.Config.LogFile != nil && testing.Verbose() {
+		if err := redirect(cmd, t.Config.LogFile); err != nil {
+			return err
+		}
+	}
+
+	if err := cmd.Start(); err != nil {
+		return err
+	}
+
+	log.Println("Server started.")
+
+	defer func() {
+		// Do not early return. We have to call Wait anyway.
+		_ = cmd.Process.Signal(syscall.SIGTERM)
+
+		if _err := cmd.Wait(); _err != nil {
+			if _err.Error() != "signal: terminated" {
+				err = _err
+				return
+			}
+		}
+
+		log.Println("Server exited")
+	}()
+
+	for _, fn := range tests {
+		if err := fn(t); err != nil {
+			return err
+		}
+	}
+
+	// Note that the return value 'err' may be updated by the 'defer' statement before despite it's returning nil here.
+	return nil
+}
diff --git a/integrations/version_test.go b/integrations/version_test.go
new file mode 100644
index 000000000..beda5c3ab
--- /dev/null
+++ b/integrations/version_test.go
@@ -0,0 +1,82 @@
+// Copyright 2017 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package integration
+
+import (
+	"encoding/json"
+	"fmt"
+	"log"
+	"net/http"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"code.gitea.io/gitea/integrations/internal/utils"
+	"code.gitea.io/sdk/gitea"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func version(t *utils.T) error {
+	var err error
+
+	path, err := filepath.Abs(t.Config.Program)
+	if err != nil {
+		return err
+	}
+
+	cmd := exec.Command(path, "--version")
+	out, err := cmd.Output()
+	if err != nil {
+		return err
+	}
+
+	fields := strings.Fields(string(out))
+	if !strings.HasPrefix(string(out), "Gitea version") {
+		return fmt.Errorf("unexpected version string '%s' of the gitea executable", out)
+	}
+
+	expected := fields[2]
+
+	var r *http.Response
+	r, err = http.Get("http://:" + ServerHTTPPort + "/api/v1/version")
+	if err != nil {
+		return err
+	}
+	defer r.Body.Close()
+
+	if r.StatusCode != http.StatusOK {
+		return fmt.Errorf("'/api/v1/version': %s\n", r.Status)
+	}
+
+	var v gitea.ServerVersion
+
+	dec := json.NewDecoder(r.Body)
+	if err := dec.Decode(&v); err != nil {
+		return err
+	}
+
+	actual := v.Version
+
+	log.Printf("Actual: \"%s\" Expected: \"%s\"\n", actual, expected)
+	assert.Equal(t, expected, actual)
+
+	return nil
+}
+
+func TestVersion(t *testing.T) {
+	conf := utils.Config{
+		Program: "../gitea",
+		WorkDir: "",
+		Args:    []string{"web", "--port", ServerHTTPPort},
+		LogFile: os.Stderr,
+	}
+
+	if err := utils.New(t, &conf).RunTest(install, version); err != nil {
+		t.Fatal(err)
+	}
+}
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index 9431dac01..611a8f91d 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -232,6 +232,7 @@ func RegisterRoutes(m *macaron.Macaron) {
 
 	m.Group("/v1", func() {
 		// Miscellaneous
+		m.Get("/version", misc.Version)
 		m.Post("/markdown", bind(api.MarkdownOption{}), misc.Markdown)
 		m.Post("/markdown/raw", misc.MarkdownRaw)
 
diff --git a/routers/api/v1/misc/version.go b/routers/api/v1/misc/version.go
new file mode 100644
index 000000000..92950c19c
--- /dev/null
+++ b/routers/api/v1/misc/version.go
@@ -0,0 +1,16 @@
+// Copyright 2017 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package misc
+
+import (
+	"code.gitea.io/gitea/modules/context"
+	"code.gitea.io/gitea/modules/setting"
+	"code.gitea.io/sdk/gitea"
+)
+
+// Version shows the version of the Gitea server
+func Version(ctx *context.APIContext) {
+	ctx.JSON(200, &gitea.ServerVersion{Version: setting.AppVer})
+}
diff --git a/vendor/code.gitea.io/sdk/gitea/miscellaneous.go b/vendor/code.gitea.io/sdk/gitea/miscellaneous.go
index 30aaee77c..dc56177ca 100644
--- a/vendor/code.gitea.io/sdk/gitea/miscellaneous.go
+++ b/vendor/code.gitea.io/sdk/gitea/miscellaneous.go
@@ -11,3 +11,14 @@ type MarkdownOption struct {
 	Context string
 	Wiki    bool
 }
+
+// ServerVersion wraps the version of the server
+type ServerVersion struct {
+	Version string
+}
+
+// ServerVersion returns the version of the server
+func (c *Client) ServerVersion() (string, error) {
+	v := ServerVersion{}
+	return v.Version, c.getParsedResponse("GET", "/api/v1/version", nil, nil, &v)
+}
diff --git a/vendor/vendor.json b/vendor/vendor.json
index afe768a0b..78ae8f3ff 100644
--- a/vendor/vendor.json
+++ b/vendor/vendor.json
@@ -9,10 +9,10 @@
 			"revisionTime": "2017-02-22T02:52:05Z"
 		},
 		{
-			"checksumSHA1": "K0VWBaa3ZUE598zVFGavdLB7vW4=",
+			"checksumSHA1": "qXD1HI8bTn7qNJZJOeZqQgxo354=",
 			"path": "code.gitea.io/sdk/gitea",
-			"revision": "06902fe19508c7ede2be38b71287c665efa1f10d",
-			"revisionTime": "2017-02-19T11:17:32Z"
+			"revision": "8807a1d2ced513880b288a5e2add39df6bf72144",
+			"revisionTime": "2017-03-04T10:22:44Z"
 		},
 		{
 			"checksumSHA1": "IyfS7Rbl6OgR83QR7TOfKdDCq+M=",