diff --git a/internal/api/file.go b/internal/api/file.go
new file mode 100644
index 000000000..531e0f6e9
--- /dev/null
+++ b/internal/api/file.go
@@ -0,0 +1,32 @@
+package api
+
+import (
+	"net/http"
+
+	"github.com/gin-gonic/gin"
+	"github.com/photoprism/photoprism/internal/config"
+	"github.com/photoprism/photoprism/internal/query"
+)
+
+// GET /api/v1/files/:hash
+//
+// Parameters:
+//   hash: string The sha1 hash of a file
+func GetFile(router *gin.RouterGroup, conf *config.Config) {
+	router.GET("/files/:hash", func(c *gin.Context) {
+		if Unauthorized(c, conf) {
+			c.AbortWithStatusJSON(http.StatusUnauthorized, ErrUnauthorized)
+			return
+		}
+
+		q := query.New(conf.OriginalsPath(), conf.Db())
+		p, err := q.FindFileByHash(c.Param("hash"))
+
+		if err != nil {
+			c.AbortWithStatusJSON(http.StatusNotFound, ErrPhotoNotFound)
+			return
+		}
+
+		c.JSON(http.StatusOK, p)
+	})
+}
diff --git a/internal/api/file_test.go b/internal/api/file_test.go
new file mode 100644
index 000000000..8daa006e6
--- /dev/null
+++ b/internal/api/file_test.go
@@ -0,0 +1,24 @@
+package api
+
+import (
+	"net/http"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestGetFile(t *testing.T) {
+	t.Run("search for existing file", func(t *testing.T) {
+		app, router, ctx := NewApiTest()
+		GetFile(router, ctx)
+		result := PerformRequest(app, "GET", "/api/v1/files/123xxx")
+		assert.Equal(t, http.StatusOK, result.Code)
+		assert.Contains(t, result.Body.String(), "\"FileName\":\"exampleFileName.jpg\"")
+	})
+	t.Run("search for not existing file", func(t *testing.T) {
+		app, router, ctx := NewApiTest()
+		GetFile(router, ctx)
+		result := PerformRequest(app, "GET", "/api/v1/files/111")
+		assert.Equal(t, http.StatusNotFound, result.Code)
+	})
+}
diff --git a/internal/server/routes.go b/internal/server/routes.go
index 0245d75a9..c41a9f0c5 100644
--- a/internal/server/routes.go
+++ b/internal/server/routes.go
@@ -37,6 +37,7 @@ func registerRoutes(router *gin.Engine, conf *config.Config) {
 		api.AddPhotoLabel(v1, conf)
 		api.RemovePhotoLabel(v1, conf)
 		api.GetMomentsTime(v1, conf)
+		api.GetFile(v1, conf)
 
 		api.GetLabels(v1, conf)
 		api.UpdateLabel(v1, conf)