diff --git a/docs/content/doc/features/webhooks.en-us.md b/docs/content/doc/features/webhooks.en-us.md
index 1a0a180e7a..ec50c013f5 100644
--- a/docs/content/doc/features/webhooks.en-us.md
+++ b/docs/content/doc/features/webhooks.en-us.md
@@ -15,24 +15,24 @@ menu:
 
 # Webhooks
 
-Gitea supports web hooks for repository events. This can be found in the settings
-page `/:username/:reponame/settings/hooks`. All event pushes are POST requests.
-The methods currently supported are:
+Gitea supports web hooks for repository events. This can be configured in the settings
+page `/:username/:reponame/settings/hooks` by a repository admin. Webhooks can also be configured on a per-organization and whole system basis.
+All event pushes are POST requests. The methods currently supported are:
 
-- Gitea
+- Gitea (can also be a GET request)
 - Gogs
 - Slack
 - Discord
 - Dingtalk
 - Telegram
 - Microsoft Teams
+- Feishu
 
 ### Event information
 
 The following is an example of event information that will be sent by Gitea to
 a Payload URL:
 
-
 ```
 X-GitHub-Delivery: f6266f16-1bf3-46a5-9ea4-602e06ead473
 X-GitHub-Event: push
diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index ba411dd8c2..2badb72788 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -194,6 +194,8 @@ var migrations = []Migration{
 	NewMigration("remove dependencies from deleted repositories", purgeUnusedDependencies),
 	// v130 -> v131
 	NewMigration("Expand webhooks for more granularity", expandWebhooks),
+	// v131 -> v132
+	NewMigration("Add IsSystemWebhook column to webhooks table", addSystemWebhookColumn),
 }
 
 // Migrate database to current version
diff --git a/models/migrations/v131.go b/models/migrations/v131.go
new file mode 100644
index 0000000000..a38c7be634
--- /dev/null
+++ b/models/migrations/v131.go
@@ -0,0 +1,22 @@
+// Copyright 2020 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 migrations
+
+import (
+	"fmt"
+
+	"xorm.io/xorm"
+)
+
+func addSystemWebhookColumn(x *xorm.Engine) error {
+	type Webhook struct {
+		IsSystemWebhook bool `xorm:"NOT NULL DEFAULT false"`
+	}
+
+	if err := x.Sync2(new(Webhook)); err != nil {
+		return fmt.Errorf("Sync2: %v", err)
+	}
+	return nil
+}
diff --git a/models/webhook.go b/models/webhook.go
index 82aedf7e81..d161ca1ae9 100644
--- a/models/webhook.go
+++ b/models/webhook.go
@@ -99,21 +99,22 @@ const (
 
 // Webhook represents a web hook object.
 type Webhook struct {
-	ID           int64  `xorm:"pk autoincr"`
-	RepoID       int64  `xorm:"INDEX"`
-	OrgID        int64  `xorm:"INDEX"`
-	URL          string `xorm:"url TEXT"`
-	Signature    string `xorm:"TEXT"`
-	HTTPMethod   string `xorm:"http_method"`
-	ContentType  HookContentType
-	Secret       string `xorm:"TEXT"`
-	Events       string `xorm:"TEXT"`
-	*HookEvent   `xorm:"-"`
-	IsSSL        bool `xorm:"is_ssl"`
-	IsActive     bool `xorm:"INDEX"`
-	HookTaskType HookTaskType
-	Meta         string     `xorm:"TEXT"` // store hook-specific attributes
-	LastStatus   HookStatus // Last delivery status
+	ID              int64 `xorm:"pk autoincr"`
+	RepoID          int64 `xorm:"INDEX"` // An ID of 0 indicates either a default or system webhook
+	OrgID           int64 `xorm:"INDEX"`
+	IsSystemWebhook bool
+	URL             string `xorm:"url TEXT"`
+	Signature       string `xorm:"TEXT"`
+	HTTPMethod      string `xorm:"http_method"`
+	ContentType     HookContentType
+	Secret          string `xorm:"TEXT"`
+	Events          string `xorm:"TEXT"`
+	*HookEvent      `xorm:"-"`
+	IsSSL           bool `xorm:"is_ssl"`
+	IsActive        bool `xorm:"INDEX"`
+	HookTaskType    HookTaskType
+	Meta            string     `xorm:"TEXT"` // store hook-specific attributes
+	LastStatus      HookStatus // Last delivery status
 
 	CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
 	UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
@@ -401,7 +402,7 @@ func GetWebhooksByOrgID(orgID int64, listOptions ListOptions) ([]*Webhook, error
 func GetDefaultWebhook(id int64) (*Webhook, error) {
 	webhook := &Webhook{ID: id}
 	has, err := x.
-		Where("repo_id=? AND org_id=?", 0, 0).
+		Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, false).
 		Get(webhook)
 	if err != nil {
 		return nil, err
@@ -419,7 +420,33 @@ func GetDefaultWebhooks() ([]*Webhook, error) {
 func getDefaultWebhooks(e Engine) ([]*Webhook, error) {
 	webhooks := make([]*Webhook, 0, 5)
 	return webhooks, e.
-		Where("repo_id=? AND org_id=?", 0, 0).
+		Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, false).
+		Find(&webhooks)
+}
+
+// GetSystemWebhook returns admin system webhook by given ID.
+func GetSystemWebhook(id int64) (*Webhook, error) {
+	webhook := &Webhook{ID: id}
+	has, err := x.
+		Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, true).
+		Get(webhook)
+	if err != nil {
+		return nil, err
+	} else if !has {
+		return nil, ErrWebhookNotExist{id}
+	}
+	return webhook, nil
+}
+
+// GetSystemWebhooks returns all admin system webhooks.
+func GetSystemWebhooks() ([]*Webhook, error) {
+	return getSystemWebhooks(x)
+}
+
+func getSystemWebhooks(e Engine) ([]*Webhook, error) {
+	webhooks := make([]*Webhook, 0, 5)
+	return webhooks, e.
+		Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, true).
 		Find(&webhooks)
 }
 
@@ -471,8 +498,8 @@ func DeleteWebhookByOrgID(orgID, id int64) error {
 	})
 }
 
-// DeleteDefaultWebhook deletes an admin-default webhook by given ID.
-func DeleteDefaultWebhook(id int64) error {
+// DeleteDefaultSystemWebhook deletes an admin-configured default or system webhook (where Org and Repo ID both 0)
+func DeleteDefaultSystemWebhook(id int64) error {
 	sess := x.NewSession()
 	defer sess.Close()
 	if err := sess.Begin(); err != nil {
diff --git a/modules/webhook/webhook.go b/modules/webhook/webhook.go
index 2fab0803bc..75a81d2aff 100644
--- a/modules/webhook/webhook.go
+++ b/modules/webhook/webhook.go
@@ -181,6 +181,13 @@ func prepareWebhooks(repo *models.Repository, event models.HookEventType, p api.
 		ws = append(ws, orgHooks...)
 	}
 
+	// Add any admin-defined system webhooks
+	systemHooks, err := models.GetSystemWebhooks()
+	if err != nil {
+		return fmt.Errorf("GetSystemWebhooks: %v", err)
+	}
+	ws = append(ws, systemHooks...)
+
 	if len(ws) == 0 {
 		return nil
 	}
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index bf5b03d47d..483970e032 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -1753,6 +1753,7 @@ users = User Accounts
 organizations = Organizations
 repositories = Repositories
 hooks = Default Webhooks
+systemhooks = System Webhooks
 authentication = Authentication Sources
 emails = User Emails
 config = Configuration
@@ -1889,6 +1890,10 @@ hooks.desc = Webhooks automatically make HTTP POST requests to a server when cer
 hooks.add_webhook = Add Default Webhook
 hooks.update_webhook = Update Default Webhook
 
+systemhooks.desc = Webhooks automatically make HTTP POST requests to a server when certain Gitea events trigger. Webhooks defined will act on all repositories on the system, so please consider any performance implications this may have. Read more in the <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/webhooks/">webhooks guide</a>.
+systemhooks.add_webhook = Add System Webhook
+systemhooks.update_webhook = Update System Webhook
+
 auths.auth_manage_panel = Authentication Source Management
 auths.new = Add Authentication Source
 auths.name = Name
diff --git a/routers/admin/hooks.go b/routers/admin/hooks.go
index b80ed3cc3c..4697c4d933 100644
--- a/routers/admin/hooks.go
+++ b/routers/admin/hooks.go
@@ -12,20 +12,32 @@ import (
 )
 
 const (
-	// tplAdminHooks template path for render hook settings
+	// tplAdminHooks template path to render hook settings
 	tplAdminHooks base.TplName = "admin/hooks"
 )
 
-// DefaultWebhooks render admin-default webhook list page
-func DefaultWebhooks(ctx *context.Context) {
-	ctx.Data["Title"] = ctx.Tr("admin.hooks")
-	ctx.Data["PageIsAdminHooks"] = true
-	ctx.Data["BaseLink"] = setting.AppSubURL + "/admin/hooks"
-	ctx.Data["Description"] = ctx.Tr("admin.hooks.desc")
+// DefaultOrSystemWebhooks renders both admin default and system webhook list pages
+func DefaultOrSystemWebhooks(ctx *context.Context) {
+	var ws []*models.Webhook
+	var err error
+
+	// Are we looking at default webhooks?
+	if ctx.Params(":configType") == "hooks" {
+		ctx.Data["Title"] = ctx.Tr("admin.hooks")
+		ctx.Data["Description"] = ctx.Tr("admin.hooks.desc")
+		ctx.Data["PageIsAdminHooks"] = true
+		ctx.Data["BaseLink"] = setting.AppSubURL + "/admin/hooks"
+		ws, err = models.GetDefaultWebhooks()
+	} else {
+		ctx.Data["Title"] = ctx.Tr("admin.systemhooks")
+		ctx.Data["Description"] = ctx.Tr("admin.systemhooks.desc")
+		ctx.Data["PageIsAdminSystemHooks"] = true
+		ctx.Data["BaseLink"] = setting.AppSubURL + "/admin/system-hooks"
+		ws, err = models.GetSystemWebhooks()
+	}
 
-	ws, err := models.GetDefaultWebhooks()
 	if err != nil {
-		ctx.ServerError("GetWebhooksDefaults", err)
+		ctx.ServerError("GetWebhooksAdmin", err)
 		return
 	}
 
@@ -33,15 +45,22 @@ func DefaultWebhooks(ctx *context.Context) {
 	ctx.HTML(200, tplAdminHooks)
 }
 
-// DeleteDefaultWebhook response for delete admin-default webhook
-func DeleteDefaultWebhook(ctx *context.Context) {
-	if err := models.DeleteDefaultWebhook(ctx.QueryInt64("id")); err != nil {
+// DeleteDefaultOrSystemWebhook handler to delete an admin-defined system or default webhook
+func DeleteDefaultOrSystemWebhook(ctx *context.Context) {
+	if err := models.DeleteDefaultSystemWebhook(ctx.QueryInt64("id")); err != nil {
 		ctx.Flash.Error("DeleteDefaultWebhook: " + err.Error())
 	} else {
 		ctx.Flash.Success(ctx.Tr("repo.settings.webhook_deletion_success"))
 	}
 
-	ctx.JSON(200, map[string]interface{}{
-		"redirect": setting.AppSubURL + "/admin/hooks",
-	})
+	// Are we looking at default webhooks?
+	if ctx.Params(":configType") == "hooks" {
+		ctx.JSON(200, map[string]interface{}{
+			"redirect": setting.AppSubURL + "/admin/hooks",
+		})
+	} else {
+		ctx.JSON(200, map[string]interface{}{
+			"redirect": setting.AppSubURL + "/admin/system-hooks",
+		})
+	}
 }
diff --git a/routers/repo/webhook.go b/routers/repo/webhook.go
index cf6ff27542..94c610fe54 100644
--- a/routers/repo/webhook.go
+++ b/routers/repo/webhook.go
@@ -49,14 +49,15 @@ func Webhooks(ctx *context.Context) {
 }
 
 type orgRepoCtx struct {
-	OrgID       int64
-	RepoID      int64
-	IsAdmin     bool
-	Link        string
-	NewTemplate base.TplName
+	OrgID           int64
+	RepoID          int64
+	IsAdmin         bool
+	IsSystemWebhook bool
+	Link            string
+	NewTemplate     base.TplName
 }
 
-// getOrgRepoCtx determines whether this is a repo, organization, or admin context.
+// getOrgRepoCtx determines whether this is a repo, organization, or admin (both default and system) context.
 func getOrgRepoCtx(ctx *context.Context) (*orgRepoCtx, error) {
 	if len(ctx.Repo.RepoLink) > 0 {
 		return &orgRepoCtx{
@@ -75,10 +76,21 @@ func getOrgRepoCtx(ctx *context.Context) (*orgRepoCtx, error) {
 	}
 
 	if ctx.User.IsAdmin {
+		// Are we looking at default webhooks?
+		if ctx.Params(":configType") == "hooks" {
+			return &orgRepoCtx{
+				IsAdmin:     true,
+				Link:        path.Join(setting.AppSubURL, "/admin/hooks"),
+				NewTemplate: tplAdminHookNew,
+			}, nil
+		}
+
+		// Must be system webhooks instead
 		return &orgRepoCtx{
-			IsAdmin:     true,
-			Link:        path.Join(setting.AppSubURL, "/admin/hooks"),
-			NewTemplate: tplAdminHookNew,
+			IsAdmin:         true,
+			IsSystemWebhook: true,
+			Link:            path.Join(setting.AppSubURL, "/admin/system-hooks"),
+			NewTemplate:     tplAdminHookNew,
 		}, nil
 	}
 
@@ -105,7 +117,10 @@ func WebhooksNew(ctx *context.Context) {
 		return
 	}
 
-	if orCtx.IsAdmin {
+	if orCtx.IsAdmin && orCtx.IsSystemWebhook {
+		ctx.Data["PageIsAdminSystemHooks"] = true
+		ctx.Data["PageIsAdminSystemHooksNew"] = true
+	} else if orCtx.IsAdmin {
 		ctx.Data["PageIsAdminHooks"] = true
 		ctx.Data["PageIsAdminHooksNew"] = true
 	} else {
@@ -159,8 +174,8 @@ func ParseHookEvent(form auth.WebhookForm) *models.HookEvent {
 	}
 }
 
-// WebHooksNewPost response for creating webhook
-func WebHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) {
+// GiteaHooksNewPost response for creating Gitea webhook
+func GiteaHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) {
 	ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook")
 	ctx.Data["PageIsSettingsHooks"] = true
 	ctx.Data["PageIsSettingsHooksNew"] = true
@@ -185,15 +200,16 @@ func WebHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) {
 	}
 
 	w := &models.Webhook{
-		RepoID:       orCtx.RepoID,
-		URL:          form.PayloadURL,
-		HTTPMethod:   form.HTTPMethod,
-		ContentType:  contentType,
-		Secret:       form.Secret,
-		HookEvent:    ParseHookEvent(form.WebhookForm),
-		IsActive:     form.Active,
-		HookTaskType: models.GITEA,
-		OrgID:        orCtx.OrgID,
+		RepoID:          orCtx.RepoID,
+		URL:             form.PayloadURL,
+		HTTPMethod:      form.HTTPMethod,
+		ContentType:     contentType,
+		Secret:          form.Secret,
+		HookEvent:       ParseHookEvent(form.WebhookForm),
+		IsActive:        form.Active,
+		HookTaskType:    models.GITEA,
+		OrgID:           orCtx.OrgID,
+		IsSystemWebhook: orCtx.IsSystemWebhook,
 	}
 	if err := w.UpdateEvent(); err != nil {
 		ctx.ServerError("UpdateEvent", err)
@@ -238,14 +254,15 @@ func newGogsWebhookPost(ctx *context.Context, form auth.NewGogshookForm, kind mo
 	}
 
 	w := &models.Webhook{
-		RepoID:       orCtx.RepoID,
-		URL:          form.PayloadURL,
-		ContentType:  contentType,
-		Secret:       form.Secret,
-		HookEvent:    ParseHookEvent(form.WebhookForm),
-		IsActive:     form.Active,
-		HookTaskType: kind,
-		OrgID:        orCtx.OrgID,
+		RepoID:          orCtx.RepoID,
+		URL:             form.PayloadURL,
+		ContentType:     contentType,
+		Secret:          form.Secret,
+		HookEvent:       ParseHookEvent(form.WebhookForm),
+		IsActive:        form.Active,
+		HookTaskType:    kind,
+		OrgID:           orCtx.OrgID,
+		IsSystemWebhook: orCtx.IsSystemWebhook,
 	}
 	if err := w.UpdateEvent(); err != nil {
 		ctx.ServerError("UpdateEvent", err)
@@ -287,14 +304,15 @@ func DiscordHooksNewPost(ctx *context.Context, form auth.NewDiscordHookForm) {
 	}
 
 	w := &models.Webhook{
-		RepoID:       orCtx.RepoID,
-		URL:          form.PayloadURL,
-		ContentType:  models.ContentTypeJSON,
-		HookEvent:    ParseHookEvent(form.WebhookForm),
-		IsActive:     form.Active,
-		HookTaskType: models.DISCORD,
-		Meta:         string(meta),
-		OrgID:        orCtx.OrgID,
+		RepoID:          orCtx.RepoID,
+		URL:             form.PayloadURL,
+		ContentType:     models.ContentTypeJSON,
+		HookEvent:       ParseHookEvent(form.WebhookForm),
+		IsActive:        form.Active,
+		HookTaskType:    models.DISCORD,
+		Meta:            string(meta),
+		OrgID:           orCtx.OrgID,
+		IsSystemWebhook: orCtx.IsSystemWebhook,
 	}
 	if err := w.UpdateEvent(); err != nil {
 		ctx.ServerError("UpdateEvent", err)
@@ -327,14 +345,15 @@ func DingtalkHooksNewPost(ctx *context.Context, form auth.NewDingtalkHookForm) {
 	}
 
 	w := &models.Webhook{
-		RepoID:       orCtx.RepoID,
-		URL:          form.PayloadURL,
-		ContentType:  models.ContentTypeJSON,
-		HookEvent:    ParseHookEvent(form.WebhookForm),
-		IsActive:     form.Active,
-		HookTaskType: models.DINGTALK,
-		Meta:         "",
-		OrgID:        orCtx.OrgID,
+		RepoID:          orCtx.RepoID,
+		URL:             form.PayloadURL,
+		ContentType:     models.ContentTypeJSON,
+		HookEvent:       ParseHookEvent(form.WebhookForm),
+		IsActive:        form.Active,
+		HookTaskType:    models.DINGTALK,
+		Meta:            "",
+		OrgID:           orCtx.OrgID,
+		IsSystemWebhook: orCtx.IsSystemWebhook,
 	}
 	if err := w.UpdateEvent(); err != nil {
 		ctx.ServerError("UpdateEvent", err)
@@ -376,14 +395,15 @@ func TelegramHooksNewPost(ctx *context.Context, form auth.NewTelegramHookForm) {
 	}
 
 	w := &models.Webhook{
-		RepoID:       orCtx.RepoID,
-		URL:          fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s", form.BotToken, form.ChatID),
-		ContentType:  models.ContentTypeJSON,
-		HookEvent:    ParseHookEvent(form.WebhookForm),
-		IsActive:     form.Active,
-		HookTaskType: models.TELEGRAM,
-		Meta:         string(meta),
-		OrgID:        orCtx.OrgID,
+		RepoID:          orCtx.RepoID,
+		URL:             fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s", form.BotToken, form.ChatID),
+		ContentType:     models.ContentTypeJSON,
+		HookEvent:       ParseHookEvent(form.WebhookForm),
+		IsActive:        form.Active,
+		HookTaskType:    models.TELEGRAM,
+		Meta:            string(meta),
+		OrgID:           orCtx.OrgID,
+		IsSystemWebhook: orCtx.IsSystemWebhook,
 	}
 	if err := w.UpdateEvent(); err != nil {
 		ctx.ServerError("UpdateEvent", err)
@@ -416,14 +436,15 @@ func MSTeamsHooksNewPost(ctx *context.Context, form auth.NewMSTeamsHookForm) {
 	}
 
 	w := &models.Webhook{
-		RepoID:       orCtx.RepoID,
-		URL:          form.PayloadURL,
-		ContentType:  models.ContentTypeJSON,
-		HookEvent:    ParseHookEvent(form.WebhookForm),
-		IsActive:     form.Active,
-		HookTaskType: models.MSTEAMS,
-		Meta:         "",
-		OrgID:        orCtx.OrgID,
+		RepoID:          orCtx.RepoID,
+		URL:             form.PayloadURL,
+		ContentType:     models.ContentTypeJSON,
+		HookEvent:       ParseHookEvent(form.WebhookForm),
+		IsActive:        form.Active,
+		HookTaskType:    models.MSTEAMS,
+		Meta:            "",
+		OrgID:           orCtx.OrgID,
+		IsSystemWebhook: orCtx.IsSystemWebhook,
 	}
 	if err := w.UpdateEvent(); err != nil {
 		ctx.ServerError("UpdateEvent", err)
@@ -473,14 +494,15 @@ func SlackHooksNewPost(ctx *context.Context, form auth.NewSlackHookForm) {
 	}
 
 	w := &models.Webhook{
-		RepoID:       orCtx.RepoID,
-		URL:          form.PayloadURL,
-		ContentType:  models.ContentTypeJSON,
-		HookEvent:    ParseHookEvent(form.WebhookForm),
-		IsActive:     form.Active,
-		HookTaskType: models.SLACK,
-		Meta:         string(meta),
-		OrgID:        orCtx.OrgID,
+		RepoID:          orCtx.RepoID,
+		URL:             form.PayloadURL,
+		ContentType:     models.ContentTypeJSON,
+		HookEvent:       ParseHookEvent(form.WebhookForm),
+		IsActive:        form.Active,
+		HookTaskType:    models.SLACK,
+		Meta:            string(meta),
+		OrgID:           orCtx.OrgID,
+		IsSystemWebhook: orCtx.IsSystemWebhook,
 	}
 	if err := w.UpdateEvent(); err != nil {
 		ctx.ServerError("UpdateEvent", err)
@@ -513,14 +535,15 @@ func FeishuHooksNewPost(ctx *context.Context, form auth.NewFeishuHookForm) {
 	}
 
 	w := &models.Webhook{
-		RepoID:       orCtx.RepoID,
-		URL:          form.PayloadURL,
-		ContentType:  models.ContentTypeJSON,
-		HookEvent:    ParseHookEvent(form.WebhookForm),
-		IsActive:     form.Active,
-		HookTaskType: models.FEISHU,
-		Meta:         "",
-		OrgID:        orCtx.OrgID,
+		RepoID:          orCtx.RepoID,
+		URL:             form.PayloadURL,
+		ContentType:     models.ContentTypeJSON,
+		HookEvent:       ParseHookEvent(form.WebhookForm),
+		IsActive:        form.Active,
+		HookTaskType:    models.FEISHU,
+		Meta:            "",
+		OrgID:           orCtx.OrgID,
+		IsSystemWebhook: orCtx.IsSystemWebhook,
 	}
 	if err := w.UpdateEvent(); err != nil {
 		ctx.ServerError("UpdateEvent", err)
@@ -549,6 +572,8 @@ func checkWebhook(ctx *context.Context) (*orgRepoCtx, *models.Webhook) {
 		w, err = models.GetWebhookByRepoID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
 	} else if orCtx.OrgID > 0 {
 		w, err = models.GetWebhookByOrgID(ctx.Org.Organization.ID, ctx.ParamsInt64(":id"))
+	} else if orCtx.IsSystemWebhook {
+		w, err = models.GetSystemWebhook(ctx.ParamsInt64(":id"))
 	} else {
 		w, err = models.GetDefaultWebhook(ctx.ParamsInt64(":id"))
 	}
diff --git a/routers/routes/routes.go b/routers/routes/routes.go
index 0b0b4e05a3..093edcd920 100644
--- a/routers/routes/routes.go
+++ b/routers/routes/routes.go
@@ -458,11 +458,11 @@ func RegisterRoutes(m *macaron.Macaron) {
 			m.Post("/delete", admin.DeleteRepo)
 		})
 
-		m.Group("/hooks", func() {
-			m.Get("", admin.DefaultWebhooks)
-			m.Post("/delete", admin.DeleteDefaultWebhook)
+		m.Group("/^:configType(hooks|system-hooks)$", func() {
+			m.Get("", admin.DefaultOrSystemWebhooks)
+			m.Post("/delete", admin.DeleteDefaultOrSystemWebhook)
 			m.Get("/:type/new", repo.WebhooksNew)
-			m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
+			m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.GiteaHooksNewPost)
 			m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost)
 			m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
 			m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
@@ -569,7 +569,7 @@ func RegisterRoutes(m *macaron.Macaron) {
 					m.Get("", org.Webhooks)
 					m.Post("/delete", org.DeleteWebhook)
 					m.Get("/:type/new", repo.WebhooksNew)
-					m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
+					m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.GiteaHooksNewPost)
 					m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost)
 					m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
 					m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
@@ -635,7 +635,7 @@ func RegisterRoutes(m *macaron.Macaron) {
 				m.Get("", repo.Webhooks)
 				m.Post("/delete", repo.DeleteWebhook)
 				m.Get("/:type/new", repo.WebhooksNew)
-				m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
+				m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.GiteaHooksNewPost)
 				m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost)
 				m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
 				m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
diff --git a/templates/admin/navbar.tmpl b/templates/admin/navbar.tmpl
index 546df22e12..6d81d7557f 100644
--- a/templates/admin/navbar.tmpl
+++ b/templates/admin/navbar.tmpl
@@ -14,6 +14,9 @@
 	<a class="{{if .PageIsAdminHooks}}active{{end}} item" href="{{AppSubUrl}}/admin/hooks">
 		{{.i18n.Tr "admin.hooks"}}
 	</a>
+	<a class="{{if .PageIsAdminSystemHooks}}active{{end}} item" href="{{AppSubUrl}}/admin/system-hooks">
+		{{.i18n.Tr "admin.systemhooks"}}
+	</a>
 	<a class="{{if .PageIsAdminAuthentications}}active{{end}} item" href="{{AppSubUrl}}/admin/auths">
 		{{.i18n.Tr "admin.authentication"}}
 	</a>