diff --git a/rhodecode/integrations/tests/test_integrations.py b/rhodecode/integrations/tests/test_integrations.py
--- a/rhodecode/integrations/tests/test_integrations.py
+++ b/rhodecode/integrations/tests/test_integrations.py
@@ -32,6 +32,65 @@ def route_path(name, **kwargs):
     }[name].format(**kwargs)
 
 
+def _post_integration_test_helper(app, url, csrf_token, repo, repo_group,
+                                  admin_view):
+    """
+    Posts form data to create integration at the url given then deletes it and
+    checks if the redirect url is correct.
+    """
+    repo_name = repo.repo_name
+    repo_group_name = repo_group.group_name
+    app.post(url, params={}, status=403)  # missing csrf check
+    response = app.post(url, params={'csrf_token': csrf_token})
+    assert response.status_code == 200
+    response.mustcontain('Errors exist')
+
+    scopes_destinations = [
+        ('global',
+                ADMIN_PREFIX + '/integrations'),
+        ('root-repos',
+                ADMIN_PREFIX + '/integrations'),
+        ('repo:%s' % repo_name,
+                '/%s/settings/integrations' % repo_name),
+        ('repogroup:%s' % repo_group_name,
+                '/%s/_settings/integrations' % repo_group_name),
+        ('repogroup-recursive:%s' % repo_group_name,
+                '/%s/_settings/integrations' % repo_group_name),
+    ]
+
+    for scope, destination in scopes_destinations:
+        if admin_view:
+            destination = ADMIN_PREFIX + '/integrations'
+
+        form_data = [
+            ('csrf_token', csrf_token),
+            ('__start__', 'options:mapping'),
+            ('name', 'test integration'),
+            ('scope', scope),
+            ('enabled', 'true'),
+            ('__end__', 'options:mapping'),
+            ('__start__', 'settings:mapping'),
+            ('test_int_field', '34'),
+            ('test_string_field', ''), # empty value on purpose as it's required
+            ('__end__', 'settings:mapping'),
+        ]
+        errors_response = app.post(url, form_data)
+        assert 'Errors exist' in errors_response.body
+
+        form_data[-2] = ('test_string_field', 'data!')
+        assert Session().query(Integration).count() == 0
+        created_response = app.post(url, form_data)
+        assert Session().query(Integration).count() == 1
+
+        delete_response = app.post(
+            created_response.location,
+            params={'csrf_token': csrf_token, 'delete': 'delete'})
+
+        assert Session().query(Integration).count() == 0
+        assert delete_response.location.endswith(destination)
+
+
+
 @pytest.mark.usefixtures('app', 'autologin_user')
 class TestIntegrationsView(object):
     pass
@@ -209,61 +268,3 @@ class TestRepoGroupIntegrationsView(Test
         _post_integration_test_helper(
             self.app, url, csrf_token, admin_view=False,
             repo=backend_random.repo, repo_group=test_repo_group)
-
-
-def _post_integration_test_helper(app, url, csrf_token, repo, repo_group,
-                                  admin_view):
-    """
-    Posts form data to create integration at the url given then deletes it and
-    checks if the redirect url is correct.
-    """
-    repo_name = repo.repo_name
-    repo_group_name = repo_group.group_name
-    app.post(url, params={}, status=403)  # missing csrf check
-    response = app.post(url, params={'csrf_token': csrf_token})
-    assert response.status_code == 200
-    response.mustcontain('Errors exist')
-
-    scopes_destinations = [
-        ('global',
-                ADMIN_PREFIX + '/integrations'),
-        ('root-repos',
-                ADMIN_PREFIX + '/integrations'),
-        ('repo:%s' % repo_name,
-                '/%s/settings/integrations' % repo_name),
-        ('repogroup:%s' % repo_group_name,
-                '/%s/_settings/integrations' % repo_group_name),
-        ('repogroup-recursive:%s' % repo_group_name,
-                '/%s/_settings/integrations' % repo_group_name),
-    ]
-
-    for scope, destination in scopes_destinations:
-        if admin_view:
-            destination = ADMIN_PREFIX + '/integrations'
-
-        form_data = [
-            ('csrf_token', csrf_token),
-            ('__start__', 'options:mapping'),
-            ('name', 'test integration'),
-            ('scope', scope),
-            ('enabled', 'true'),
-            ('__end__', 'options:mapping'),
-            ('__start__', 'settings:mapping'),
-            ('test_int_field', '34'),
-            ('test_string_field', ''), # empty value on purpose as it's required
-            ('__end__', 'settings:mapping'),
-        ]
-        errors_response = app.post(url, form_data)
-        assert 'Errors exist' in errors_response.body
-
-        form_data[-2] = ('test_string_field', 'data!')
-        assert Session().query(Integration).count() == 0
-        created_response = app.post(url, form_data)
-        assert Session().query(Integration).count() == 1
-
-        delete_response = app.post(
-            created_response.location,
-            params={'csrf_token': csrf_token, 'delete': 'delete'})
-
-        assert Session().query(Integration).count() == 0
-        assert delete_response.location.endswith(destination)
diff --git a/rhodecode/integrations/types/base.py b/rhodecode/integrations/types/base.py
--- a/rhodecode/integrations/types/base.py
+++ b/rhodecode/integrations/types/base.py
@@ -218,11 +218,11 @@ class WebhookDataHandler(CommitParsingDa
 
     def repo_push_event_handler(self, event, data):
         url = self.get_base_parsed_template(data)
-        url_cals = []
+        url_calls = []
 
         branches_commits = self.aggregate_branch_data(
             data['push']['branches'], data['push']['commits'])
-        if '${branch}' in url or '${branch_head}' in url:
+        if '${branch}' in url or '${branch_head}' in url or '${commit_id}' in url:
             # call it multiple times, for each branch if used in variables
             for branch, commit_ids in branches_commits.items():
                 branch_url = string.Template(url).safe_substitute(branch=branch)
@@ -243,7 +243,7 @@ class WebhookDataHandler(CommitParsingDa
                         log.debug(
                             'register %s call(%s) to url %s',
                             self.name, event, commit_url)
-                        url_cals.append(
+                        url_calls.append(
                             (commit_url, self.headers, data))
 
                 else:
@@ -251,15 +251,15 @@ class WebhookDataHandler(CommitParsingDa
                     log.debug(
                         'register %s call(%s) to url %s',
                         self.name, event, branch_url)
-                    url_cals.append(
+                    url_calls.append(
                         (branch_url, self.headers, data))
 
         else:
             log.debug(
                 'register %s call(%s) to url %s', self.name, event, url)
-            url_cals.append((url, self.headers, data))
+            url_calls.append((url, self.headers, data))
 
-        return url_cals
+        return url_calls
 
     def repo_create_event_handler(self, event, data):
         url = self.get_base_parsed_template(data)
diff --git a/rhodecode/tests/integrations/test_webhook.py b/rhodecode/tests/integrations/test_webhook.py
--- a/rhodecode/tests/integrations/test_webhook.py
+++ b/rhodecode/tests/integrations/test_webhook.py
@@ -107,6 +107,14 @@ def test_webook_parse_url_for_pull_reque
          'http://server.com/stable/stable-yyy',
          'http://server.com/dev/dev-xxx',
          'http://server.com/dev/dev-yyy']),
+    ('http://server.com/${branch_head}',
+     ['http://server.com/stable-yyy',
+      'http://server.com/dev-yyy']),
+    ('http://server.com/${commit_id}',
+     ['http://server.com/stable-xxx',
+      'http://server.com/stable-yyy',
+      'http://server.com/dev-xxx',
+      'http://server.com/dev-yyy']),
 ])
 def test_webook_parse_url_for_push_event(
         baseapp, repo_push_event, base_data, template, expected_urls):