diff --git a/plugins/pipelines/create.js b/plugins/pipelines/create.js
index 4e1e2529f..0f09ea132 100644
--- a/plugins/pipelines/create.js
+++ b/plugins/pipelines/create.js
@@ -113,10 +113,9 @@ module.exports = () => ({
                 });
             }
 
-            const results = await Promise.all([
-                pipeline.sync(),
-                pipeline.addWebhooks(`${request.server.info.uri}/v4/webhooks`)
-            ]);
+            const results = await pipeline.sync();
+
+            await pipeline.addWebhooks(`${request.server.info.uri}/v4/webhooks`);
 
             const location = urlLib.format({
                 host: request.headers.host,
@@ -124,7 +123,7 @@ module.exports = () => ({
                 protocol: request.server.info.protocol,
                 pathname: `${request.path}/${pipeline.id}`
             });
-            const data = await results[0].toJson();
+            const data = await results.toJson();
 
             return h
                 .response(data)
diff --git a/plugins/pipelines/update.js b/plugins/pipelines/update.js
index cf4106fc5..b181ed089 100644
--- a/plugins/pipelines/update.js
+++ b/plugins/pipelines/update.js
@@ -135,17 +135,15 @@ module.exports = () => ({
                                             oldPipeline.name = scmRepo.name;
 
                                             // update pipeline with new scmRepo and branch
-                                            return oldPipeline
-                                                .update()
-                                                .then(updatedPipeline =>
-                                                    Promise.all([
-                                                        updatedPipeline.sync(),
-                                                        updatedPipeline.addWebhooks(
-                                                            `${request.server.info.uri}/v4/webhooks`
-                                                        )
-                                                    ])
-                                                )
-                                                .then(results => h.response(results[0].toJson()).code(200));
+                                            return oldPipeline.update().then(async updatedPipeline => {
+                                                await updatedPipeline.addWebhooks(
+                                                    `${request.server.info.uri}/v4/webhooks`
+                                                );
+
+                                                const result = await updatedPipeline.sync();
+
+                                                return h.response(result.toJson()).code(200);
+                                            });
                                         })
                                 )
                         );
diff --git a/plugins/webhooks/index.js b/plugins/webhooks/index.js
index e22434770..84f19cbf4 100644
--- a/plugins/webhooks/index.js
+++ b/plugins/webhooks/index.js
@@ -250,6 +250,20 @@ function getSkipMessageAndChainPR({ pipeline, prSource, restrictPR, chainPR }) {
     return result;
 }
 
+/**
+ * Returns the uri keeping only the host and the repo ID
+ * @method  uriTrimmer
+ * @param  {String}       uri       The uri to be trimmed
+ * @return {String}
+ */
+const uriTrimmer = uri => {
+    const uriToArray = uri.split(':');
+
+    while (uriToArray.length > 2) uriToArray.pop();
+
+    return uriToArray.join(':');
+};
+
 /**
  * Get all pipelines which has triggered job
  * @method  triggeredPipelines
@@ -278,9 +292,12 @@ async function triggeredPipelines(
     const scmBranch = `${splitUri[0]}:${splitUri[1]}:${splitUri[2]}`;
     const scmRepoId = `${splitUri[0]}:${splitUri[1]}`;
     const listConfig = { search: { field: 'scmUri', keyword: `${scmRepoId}:%` } };
+    const externalRepoSearchConfig = { search: { field: 'subscribedScmUrlsWithActions', keyword: `%${scmRepoId}:%` } };
 
     const pipelines = await pipelineFactory.list(listConfig);
 
+    const pipelinesWithSubscribedRepos = await pipelineFactory.list(externalRepoSearchConfig);
+
     let pipelinesOnCommitBranch = [];
     let pipelinesOnOtherBranch = [];
 
@@ -314,7 +331,9 @@ async function triggeredPipelines(
         );
     });
 
-    return pipelinesOnCommitBranch.concat(pipelinesOnOtherBranch);
+    const currentRepoPipelines = pipelinesOnCommitBranch.concat(pipelinesOnOtherBranch);
+
+    return currentRepoPipelines.concat(pipelinesWithSubscribedRepos);
 }
 
 /**
@@ -340,7 +359,6 @@ async function createPREvents(options, request) {
     const {
         username,
         scmConfig,
-        sha,
         prRef,
         prNum,
         pipelines,
@@ -350,14 +368,17 @@ async function createPREvents(options, request) {
         action,
         prSource,
         restrictPR,
-        chainPR
+        chainPR,
+        ref,
+        releaseName,
+        meta
     } = options;
     const { scm } = request.server.app.pipelineFactory;
-    const { eventFactory } = request.server.app;
-    const { pipelineFactory } = request.server.app;
+    const { eventFactory, pipelineFactory, userFactory } = request.server.app;
     const scmDisplayName = scm.getDisplayName({ scmContext: scmConfig.scmContext });
     const userDisplayName = `${scmDisplayName}:${username}`;
     const events = [];
+    let { sha } = options;
 
     scmConfig.prNum = prNum;
 
@@ -366,16 +387,41 @@ async function createPREvents(options, request) {
             const b = await p.branch;
             // obtain pipeline's latest commit sha for branch specific job
             let configPipelineSha = '';
+            let subscribedConfigSha = '';
+            let eventConfig = {};
 
-            try {
-                configPipelineSha = await pipelineFactory.scm.getCommitSha(scmConfig);
-            } catch (err) {
-                if (err.status >= 500) {
-                    throw err;
-                } else {
-                    logger.info(`skip create event for branch: ${b}`);
+            // Check if the webhook event is from a subscribed repo and
+            // and fetch the source repo commit sha and save the subscribed sha
+            if (uriTrimmer(scmConfig.scmUri) !== uriTrimmer(p.scmUri)) {
+                subscribedConfigSha = sha;
+
+                try {
+                    sha = await pipelineFactory.scm.getCommitSha({
+                        scmUri: p.scmUri,
+                        scmContext: scmConfig.scmContext,
+                        token: scmConfig.token
+                    });
+                } catch (err) {
+                    if (err.status >= 500) {
+                        throw err;
+                    } else {
+                        logger.info(`skip create event for branch: ${b}`);
+                    }
+                }
+
+                configPipelineSha = sha;
+            } else {
+                try {
+                    configPipelineSha = await pipelineFactory.scm.getCommitSha(scmConfig);
+                } catch (err) {
+                    if (err.status >= 500) {
+                        throw err;
+                    } else {
+                        logger.info(`skip create event for branch: ${b}`);
+                    }
                 }
             }
+
             const { skipMessage, resolvedChainPR } = getSkipMessageAndChainPR({
                 // Workaround for pipelines which has NULL value in `pipeline.annotations`
                 pipeline: !p.annotations ? { annotations: {}, ...p } : p,
@@ -384,7 +430,9 @@ async function createPREvents(options, request) {
                 chainPR
             });
 
-            const eventConfig = {
+            const prInfo = await eventFactory.scm.getPrInfo(scmConfig);
+
+            eventConfig = {
                 pipelineId: p.id,
                 type: 'pr',
                 webhooks: true,
@@ -399,19 +447,47 @@ async function createPREvents(options, request) {
                 prRef,
                 prNum,
                 prTitle,
-                prInfo: await eventFactory.scm.getPrInfo(scmConfig),
+                prInfo,
                 prSource,
                 baseBranch: branch
             };
 
-            if (skipMessage) {
-                eventConfig.skipMessage = skipMessage;
-            }
-
             if (b === branch) {
                 eventConfig.startFrom = '~pr';
             }
 
+            // Check if the webhook event is from a subscribed repo and
+            // set the jobs entrypoint from ~startfrom
+            // For subscribed PR event, it should be mimiced as a commit
+            // in order to function properly
+            if (uriTrimmer(scmConfig.scmUri) !== uriTrimmer(p.scmUri)) {
+                eventConfig = {
+                    pipelineId: p.id,
+                    type: 'pipeline',
+                    webhooks: true,
+                    username,
+                    scmContext: scmConfig.scmContext,
+                    startFrom: '~subscribe',
+                    sha,
+                    configPipelineSha,
+                    changedFiles,
+                    baseBranch: branch,
+                    causeMessage: `Merged by ${username}`,
+                    meta,
+                    releaseName,
+                    ref,
+                    subscribedEvent: true,
+                    subscribedConfigSha,
+                    subscribedSourceUrl: prInfo.url
+                };
+
+                await updateAdmins(userFactory, username, scmConfig.scmContext, p.id);
+            }
+
+            if (skipMessage) {
+                eventConfig.skipMessage = skipMessage;
+            }
+
             return eventConfig;
         })
     );
@@ -578,6 +654,41 @@ async function obtainScmToken(pluginOptions, userFactory, username, scmContext)
     return user.unsealToken();
 }
 
+/**
+ * Create metadata by the parsed event
+ * @param   {Object}   parsed   It has information to create metadata
+ * @returns {Object}            Metadata
+ */
+function createMeta(parsed) {
+    const { action, ref, releaseId, releaseName, releaseAuthor } = parsed;
+
+    if (action === 'release') {
+        return {
+            sd: {
+                release: {
+                    id: releaseId,
+                    name: releaseName,
+                    author: releaseAuthor
+                },
+                tag: {
+                    name: ref
+                }
+            }
+        };
+    }
+    if (action === 'tag') {
+        return {
+            sd: {
+                tag: {
+                    name: ref
+                }
+            }
+        };
+    }
+
+    return {};
+}
+
 /**
  * Act on a Pull Request change (create, sync, close)
  *  - Opening a PR should sync the pipeline (creating the job) and start the new PR job
@@ -620,6 +731,7 @@ function pullRequestEvent(pluginOptions, request, h, parsed, token) {
         scmContext
     };
     const { restrictPR, chainPR } = pluginOptions;
+    const meta = createMeta(parsed);
 
     request.log(['webhook', hookId], `PR #${prNum} ${action} for ${fullCheckoutUrl}`);
 
@@ -659,7 +771,10 @@ function pullRequestEvent(pluginOptions, request, h, parsed, token) {
                 fullCheckoutUrl,
                 restrictPR,
                 chainPR,
-                pipelines
+                pipelines,
+                ref,
+                releaseName,
+                meta
             };
 
             await batchUpdateAdmins({ userFactory, pipelines, username, scmContext });
@@ -682,41 +797,6 @@ function pullRequestEvent(pluginOptions, request, h, parsed, token) {
         });
 }
 
-/**
- * Create metadata by the parsed event
- * @param   {Object}   parsed   It has information to create metadata
- * @returns {Object}            Metadata
- */
-function createMeta(parsed) {
-    const { action, ref, releaseId, releaseName, releaseAuthor } = parsed;
-
-    if (action === 'release') {
-        return {
-            sd: {
-                release: {
-                    id: releaseId,
-                    name: releaseName,
-                    author: releaseAuthor
-                },
-                tag: {
-                    name: ref
-                }
-            }
-        };
-    }
-    if (action === 'tag') {
-        return {
-            sd: {
-                tag: {
-                    name: ref
-                }
-            }
-        };
-    }
-
-    return {};
-}
-
 /**
  * Create events for each pipeline
  * @async   createEvents
@@ -728,7 +808,15 @@ function createMeta(parsed) {
  * @param   {String}            [skipMessage]       Message to skip starting builds
  * @returns {Promise}                               Promise that resolves into events
  */
-async function createEvents(eventFactory, userFactory, pipelineFactory, pipelines, parsed, skipMessage) {
+async function createEvents(
+    eventFactory,
+    userFactory,
+    pipelineFactory,
+    pipelines,
+    parsed,
+    skipMessage,
+    scmConfigFromHook
+) {
     const { action, branch, sha, username, scmContext, changedFiles, type, releaseName, ref } = parsed;
     const events = [];
     const meta = createMeta(parsed);
@@ -820,6 +908,41 @@ async function createEvents(eventFactory, userFactory, pipelineFactory, pipeline
                     ref
                 };
 
+                // Check is the webhook event is from a subscribed repo and
+                // set the jobs entry point to ~subscribe
+                if (uriTrimmer(scmConfigFromHook.scmUri) !== uriTrimmer(pTuple.pipeline.scmUri)) {
+                    eventConfig.subscribedEvent = true;
+                    eventConfig.startFrom = '~subscribe';
+                    eventConfig.subscribedConfigSha = eventConfig.sha;
+
+                    try {
+                        eventConfig.sha = await pipelineFactory.scm.getCommitSha(scmConfig);
+                    } catch (err) {
+                        if (err.status >= 500) {
+                            throw err;
+                        } else {
+                            logger.info(`skip create event for this subscribed trigger`);
+                        }
+                    }
+
+                    try {
+                        const commitInfo = await pipelineFactory.scm.decorateCommit({
+                            scmUri: scmConfigFromHook.scmUri,
+                            scmContext,
+                            sha: eventConfig.subscribedConfigSha,
+                            token
+                        });
+
+                        eventConfig.subscribedSourceUrl = commitInfo.url;
+                    } catch (err) {
+                        if (err.status >= 500) {
+                            throw err;
+                        } else {
+                            logger.info(`skip create event for this subscribed trigger`);
+                        }
+                    }
+                }
+
                 if (skipMessage) {
                     eventConfig.skipMessage = skipMessage;
                 }
@@ -855,9 +978,7 @@ async function createEvents(eventFactory, userFactory, pipelineFactory, pipeline
  * @param  {String}             [skipMessage]          Message to skip starting builds
  */
 async function pushEvent(request, h, parsed, skipMessage, token) {
-    const { eventFactory } = request.server.app;
-    const { pipelineFactory } = request.server.app;
-    const { userFactory } = request.server.app;
+    const { eventFactory, pipelineFactory, userFactory } = request.server.app;
     const { hookId, checkoutUrl, branch, scmContext, type, action, changedFiles, releaseName, ref } = parsed;
     const fullCheckoutUrl = `${checkoutUrl}#${branch}`;
     const scmConfig = {
@@ -891,7 +1012,15 @@ async function pushEvent(request, h, parsed, skipMessage, token) {
         if (!pipelines || pipelines.length === 0) {
             request.log(['webhook', hookId], `Skipping since Pipeline ${fullCheckoutUrl} does not exist`);
         } else {
-            events = await createEvents(eventFactory, userFactory, pipelineFactory, pipelines, parsed, skipMessage);
+            events = await createEvents(
+                eventFactory,
+                userFactory,
+                pipelineFactory,
+                pipelines,
+                parsed,
+                skipMessage,
+                scmConfig
+            );
         }
 
         const hasBuildEvents = events.filter(e => e.builds !== null);
diff --git a/test/plugins/pipelines.test.js b/test/plugins/pipelines.test.js
index 46c0c3d96..dab931ec9 100644
--- a/test/plugins/pipelines.test.js
+++ b/test/plugins/pipelines.test.js
@@ -1824,7 +1824,7 @@ describe('pipeline plugin test', () => {
 
         it('returns 200 when the user is admin of old repo with deprecated scmContext', () => {
             pipelineMock.admins = { [username]: true };
-            pipelineMock.scmContext = 'depreacated';
+            pipelineMock.scmContext = 'deprecated';
 
             return server.inject(options).then(reply => {
                 // Only call once to get permissions on the new repo
diff --git a/test/plugins/webhooks.test.js b/test/plugins/webhooks.test.js
index f6a7a3a6e..cfd30461f 100644
--- a/test/plugins/webhooks.test.js
+++ b/test/plugins/webhooks.test.js
@@ -390,6 +390,7 @@ describe('webhooks plugin test', () => {
         const checkoutUrl = 'git@github.com:baxterthehacker/public-repo.git';
         const fullCheckoutUrl = 'git@github.com:baxterthehacker/public-repo.git#master';
         const scmUri = 'github.com:123456:master';
+        const scmRepoId = `github.com:123456`;
         const pipelineId = 'pipelineHash';
         const jobId = 2;
         const buildId = 'buildHash';
@@ -579,6 +580,9 @@ describe('webhooks plugin test', () => {
                 pipelineMock.workflowGraph = workflowGraph;
                 pipelineMock.jobs = Promise.resolve([mainJobMock, jobMock]);
                 pipelineFactoryMock.scm.parseHook.withArgs(reqHeaders, payload).resolves(parsed);
+                pipelineFactoryMock.list
+                    .withArgs({ search: { field: 'subscribedScmUrlsWithActions', keyword: `%${scmRepoId}:%` } })
+                    .resolves([pipelineMock]);
                 pipelineFactoryMock.list.resolves([pipelineMock]);
             });
 
@@ -1139,6 +1143,9 @@ describe('webhooks plugin test', () => {
                 });
 
                 pipelineFactoryMock.list.resolves([pipelineMock, pMock1, pMock2, pMock3]);
+                pipelineFactoryMock.list
+                    .withArgs({ search: { field: 'subscribedScmUrlsWithActions', keyword: `%${scmRepoId}:%` } })
+                    .resolves([]);
 
                 return server.inject(options).then(reply => {
                     assert.equal(reply.statusCode, 201);
@@ -1236,6 +1243,9 @@ describe('webhooks plugin test', () => {
 
                 pipelineFactoryMock.scm.getChangedFiles.resolves(['lib/test.js']);
                 pipelineFactoryMock.list.resolves([pipelineMock, pMock1, pMock2]);
+                pipelineFactoryMock.list
+                    .withArgs({ search: { field: 'subscribedScmUrlsWithActions', keyword: `%${scmRepoId}:%` } })
+                    .resolves([]);
 
                 return server.inject(options).then(reply => {
                     assert.equal(reply.statusCode, 201);
@@ -1328,6 +1338,38 @@ describe('webhooks plugin test', () => {
                 });
             });
 
+            it('returns 201 when the hook source triggers subscribed event', () => {
+                pipelineFactoryMock.scm.parseUrl
+                    .withArgs({ checkoutUrl: fullCheckoutUrl, token, scmContext })
+                    .resolves('github.com:789123:master');
+                pipelineFactoryMock.list.resolves([]);
+                pipelineFactoryMock.list
+                    .withArgs({ search: { field: 'subscribedScmUrlsWithActions', keyword: '%github.com:789123:%' } })
+                    .resolves([pipelineMock]);
+
+                return server.inject(options).then(reply => {
+                    assert.equal(reply.statusCode, 201);
+                    assert.calledWith(eventFactoryMock.create, {
+                        pipelineId,
+                        type: 'pipeline',
+                        webhooks: true,
+                        username,
+                        scmContext,
+                        sha: latestSha,
+                        configPipelineSha: latestSha,
+                        subscribedConfigSha: sha,
+                        startFrom: '~subscribe',
+                        baseBranch: 'master',
+                        causeMessage: `Merged by ${username}`,
+                        changedFiles,
+                        releaseName: undefined,
+                        ref: undefined,
+                        meta: {},
+                        subscribedEvent: true
+                    });
+                });
+            });
+
             it('returns 204 when no pipeline', () => {
                 pipelineFactoryMock.get.resolves(null);
                 pipelineFactoryMock.list.resolves([]);
@@ -1812,6 +1854,48 @@ describe('webhooks plugin test', () => {
                     });
                 });
 
+                it('returns 201 when the hook source triggers subscribed event', () => {
+                    pipelineFactoryMock.scm.parseUrl
+                        .withArgs({ checkoutUrl: fullCheckoutUrl, token, scmContext })
+                        .resolves('github.com:789123:master');
+                    pipelineFactoryMock.list.resolves([]);
+                    pipelineMock.baxterthehacker = 'master';
+                    pipelineMock.admins = {
+                        baxterthehacker: true
+                    };
+                    pipelineFactoryMock.list
+                        .withArgs({
+                            search: { field: 'subscribedScmUrlsWithActions', keyword: '%github.com:789123:%' }
+                        })
+                        .resolves([pipelineMock]);
+                    eventFactoryMock.scm.getPrInfo.resolves({
+                        url: 'foo'
+                    });
+
+                    return server.inject(options).then(reply => {
+                        assert.equal(reply.statusCode, 201);
+                        assert.calledWith(eventFactoryMock.create, {
+                            pipelineId,
+                            type: 'pipeline',
+                            webhooks: true,
+                            username,
+                            scmContext,
+                            sha: latestSha,
+                            configPipelineSha: latestSha,
+                            subscribedConfigSha: sha,
+                            startFrom: '~subscribe',
+                            baseBranch: 'master',
+                            causeMessage: `Merged by ${username}`,
+                            changedFiles,
+                            releaseName: undefined,
+                            ref: undefined,
+                            meta: {},
+                            subscribedEvent: true,
+                            subscribedSourceUrl: 'foo'
+                        });
+                    });
+                });
+
                 it('returns 201 when getCommitSha() is rejected', () => {
                     pipelineFactoryMock.scm.getCommitSha.rejects(new Error('some error'));
 
@@ -2217,6 +2301,10 @@ describe('webhooks plugin test', () => {
                 it('has the workflow for stopping builds before starting a new one', () => {
                     const abortMsg = 'Aborted because new commit was pushed to PR#1';
 
+                    pipelineFactoryMock.list
+                        .withArgs({ search: { field: 'subscribedScmUrlsWithActions', keyword: `%${scmRepoId}:%` } })
+                        .resolves([]);
+
                     return server.inject(options).then(reply => {
                         assert.calledOnce(model1.update);
                         assert.calledOnce(model2.update);
@@ -2448,13 +2536,18 @@ describe('webhooks plugin test', () => {
                     pipelineFactoryMock.scm.parseHook.withArgs(reqHeaders, options.payload).resolves(parsed);
                 });
 
-                it('returns 200 on success', () =>
-                    server.inject(options).then(reply => {
+                it('returns 200 on success', () => {
+                    pipelineFactoryMock.list
+                        .withArgs({ search: { field: 'subscribedScmUrlsWithActions', keyword: `%${scmRepoId}:%` } })
+                        .resolves([]);
+
+                    return server.inject(options).then(reply => {
                         assert.equal(reply.statusCode, 200);
                         assert.calledOnce(jobMock.update);
                         assert.strictEqual(jobMock.state, 'ENABLED');
                         assert.isTrue(jobMock.archived);
-                    }));
+                    });
+                });
 
                 it('returns 204 when pipeline to be closed does not exist', () => {
                     pipelineFactoryMock.list.resolves([]);
@@ -2464,18 +2557,26 @@ describe('webhooks plugin test', () => {
                     });
                 });
 
-                it('stops running builds', () =>
-                    server.inject(options).then(() => {
+                it('stops running builds', () => {
+                    pipelineFactoryMock.list
+                        .withArgs({ search: { field: 'subscribedScmUrlsWithActions', keyword: `%${scmRepoId}:%` } })
+                        .resolves([]);
+
+                    return server.inject(options).then(() => {
                         assert.calledOnce(model1.update);
                         assert.calledOnce(model2.update);
                         assert.strictEqual(model1.status, 'ABORTED');
                         assert.strictEqual(model1.statusMessage, 'Aborted because PR#1 was closed');
                         assert.strictEqual(model2.status, 'ABORTED');
                         assert.strictEqual(model2.statusMessage, 'Aborted because PR#1 was closed');
-                    }));
+                    });
+                });
 
                 it('returns 500 when failed', () => {
                     jobMock.update.rejects(new Error('Failed to update'));
+                    pipelineFactoryMock.list
+                        .withArgs({ search: { field: 'subscribedScmUrlsWithActions', keyword: `%${scmRepoId}:%` } })
+                        .resolves([]);
 
                     return server.inject(options).then(reply => {
                         assert.equal(reply.statusCode, 500);