diff --git a/app/assets/stylesheets/framework/icons.scss b/app/assets/stylesheets/framework/icons.scss
index 37a2264122dcf1c714c68dc177b0bc6ad8f823d9..9d09c160551211ef91513d844695331448855708 100644
--- a/app/assets/stylesheets/framework/icons.scss
+++ b/app/assets/stylesheets/framework/icons.scss
@@ -36,6 +36,7 @@
 
 .ci-status-icon-pending,
 .ci-status-icon-waiting-for-resource,
+.ci-status-icon-waiting-for-callback,
 .ci-status-icon-failed-with-warnings,
 .ci-status-icon-success-with-warnings {
   @include icon-styles($orange-500, $orange-100);
diff --git a/app/assets/stylesheets/page_bundles/ci_status.scss b/app/assets/stylesheets/page_bundles/ci_status.scss
index 17886ab954a42bef82fe424b571c0452277a33f4..f2129aa6841695450f549a97a478416546444c6a 100644
--- a/app/assets/stylesheets/page_bundles/ci_status.scss
+++ b/app/assets/stylesheets/page_bundles/ci_status.scss
@@ -48,6 +48,7 @@
 
   &.ci-pending,
   &.ci-waiting-for-resource,
+  &.ci-waiting-for-callback,
   &.ci-failed-with-warnings,
   &.ci-success-with-warnings {
     @include status-color(
diff --git a/app/graphql/types/ci/pipeline_status_enum.rb b/app/graphql/types/ci/pipeline_status_enum.rb
index c8e031e18ead006ed585ea5f54caae6a60670284..17cf48bb5cf95cb1a7413d14590cb592495ec0d4 100644
--- a/app/graphql/types/ci/pipeline_status_enum.rb
+++ b/app/graphql/types/ci/pipeline_status_enum.rb
@@ -7,6 +7,7 @@ class PipelineStatusEnum < BaseEnum
         created: 'Pipeline has been created.',
         waiting_for_resource: 'A resource (for example, a runner) that the pipeline requires to run is unavailable.',
         preparing: 'Pipeline is preparing to run.',
+        waiting_for_callback: 'Pipeline is waiting for an external action.',
         pending: 'Pipeline has not started running yet.',
         running: 'Pipeline is running.',
         failed: 'At least one stage of the pipeline failed.',
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index a7909fcedfb154d55cbbeb29a32ed905989efe84..16541adf37062289f2e4e3089fdee774123e00d4 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -190,6 +190,7 @@ class Pipeline < Ci::ApplicationRecord
 
         # this is needed to ensure tests to be covered
         transition [:running] => :running
+        transition [:waiting_for_callback] => :waiting_for_callback
       end
 
       event :request_resource do
@@ -204,6 +205,10 @@ class Pipeline < Ci::ApplicationRecord
         transition any - [:running] => :running
       end
 
+      event :wait_for_callback do
+        transition any - [:waiting_for_callback] => :waiting_for_callback
+      end
+
       event :skip do
         transition any - [:skipped] => :skipped
       end
@@ -555,7 +560,7 @@ def self.internal_sources
     end
 
     def self.bridgeable_statuses
-      ::Ci::Pipeline::AVAILABLE_STATUSES - %w[created waiting_for_resource preparing pending]
+      ::Ci::Pipeline::AVAILABLE_STATUSES - %w[created waiting_for_resource waiting_for_callback preparing pending]
     end
 
     def self.auto_devops_pipelines_completed_total
@@ -851,6 +856,7 @@ def set_status(new_status)
         when 'created' then nil
         when 'waiting_for_resource' then request_resource
         when 'preparing' then prepare
+        when 'waiting_for_callback' then wait_for_callback
         when 'pending' then enqueue
         when 'running' then run
         when 'success' then succeed
diff --git a/app/models/ci/stage.rb b/app/models/ci/stage.rb
index 3a498972153dd1b5113cdcaea4aa50b5d547373b..3d2df9a45ef127d326465b31dbe599098eb2f363 100644
--- a/app/models/ci/stage.rb
+++ b/app/models/ci/stage.rb
@@ -78,6 +78,10 @@ class Stage < Ci::ApplicationRecord
         transition any - [:running] => :running
       end
 
+      event :wait_for_callback do
+        transition any - [:waiting_for_callback] => :waiting_for_callback
+      end
+
       event :skip do
         transition any - [:skipped] => :skipped
       end
@@ -109,6 +113,7 @@ def set_status(new_status)
         when 'created' then nil
         when 'waiting_for_resource' then request_resource
         when 'preparing' then prepare
+        when 'waiting_for_callback' then wait_for_callback
         when 'pending' then enqueue
         when 'running' then run
         when 'success' then succeed
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index 6109ead9865539f7e3046706142c21ec774e1a77..ab75847fa99e15a14854ae61f67ebad2e13f9c45 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -147,15 +147,15 @@ class CommitStatus < Ci::ApplicationRecord
     end
 
     event :drop do
-      transition [:created, :waiting_for_resource, :preparing, :pending, :running, :manual, :scheduled] => :failed
+      transition [:created, :waiting_for_resource, :preparing, :waiting_for_callback, :pending, :running, :manual, :scheduled] => :failed
     end
 
     event :success do
-      transition [:created, :waiting_for_resource, :preparing, :pending, :running] => :success
+      transition [:created, :waiting_for_resource, :preparing, :waiting_for_callback, :pending, :running] => :success
     end
 
     event :cancel do
-      transition [:created, :waiting_for_resource, :preparing, :pending, :running, :manual, :scheduled] => :canceled
+      transition [:created, :waiting_for_resource, :preparing, :waiting_for_callback, :pending, :running, :manual, :scheduled] => :canceled
     end
 
     before_transition [:created, :waiting_for_resource, :preparing, :skipped, :manual, :scheduled] => :pending do |commit_status|
diff --git a/app/models/concerns/ci/has_status.rb b/app/models/concerns/ci/has_status.rb
index 2971ecb04b8465c76c7ea87b0937baf6a3cbdbf9..fb2b12e5f0045e1a57cbe5e9bc931aae9e634168 100644
--- a/app/models/concerns/ci/has_status.rb
+++ b/app/models/concerns/ci/has_status.rb
@@ -6,19 +6,20 @@ module HasStatus
 
     DEFAULT_STATUS = 'created'
     BLOCKED_STATUS = %w[manual scheduled].freeze
-    AVAILABLE_STATUSES = %w[created waiting_for_resource preparing pending running success failed canceled skipped manual scheduled].freeze
+    AVAILABLE_STATUSES = %w[created waiting_for_resource preparing waiting_for_callback pending running success failed canceled skipped manual scheduled].freeze
     STARTED_STATUSES = %w[running success failed].freeze
-    ACTIVE_STATUSES = %w[waiting_for_resource preparing pending running].freeze
+    ACTIVE_STATUSES = %w[waiting_for_resource preparing waiting_for_callback pending running].freeze
     COMPLETED_STATUSES = %w[success failed canceled skipped].freeze
     STOPPED_STATUSES = COMPLETED_STATUSES + BLOCKED_STATUS
-    ORDERED_STATUSES = %w[failed preparing pending running waiting_for_resource manual scheduled canceled success skipped created].freeze
+    ORDERED_STATUSES = %w[failed preparing pending running waiting_for_callback waiting_for_resource manual scheduled canceled success skipped created].freeze
     PASSED_WITH_WARNINGS_STATUSES = %w[failed canceled].to_set.freeze
     IGNORED_STATUSES = %w[manual].to_set.freeze
     ALIVE_STATUSES = (ACTIVE_STATUSES + ['created']).freeze
     CANCELABLE_STATUSES = (ALIVE_STATUSES + ['scheduled']).freeze
     STATUSES_ENUM = { created: 0, pending: 1, running: 2, success: 3,
                       failed: 4, canceled: 5, skipped: 6, manual: 7,
-                      scheduled: 8, preparing: 9, waiting_for_resource: 10 }.freeze
+                      scheduled: 8, preparing: 9, waiting_for_resource: 10,
+                      waiting_for_callback: 11 }.freeze
 
     UnknownStatusError = Class.new(StandardError)
 
@@ -58,6 +59,7 @@ def stopped_statuses
         state :created, value: 'created'
         state :waiting_for_resource, value: 'waiting_for_resource'
         state :preparing, value: 'preparing'
+        state :waiting_for_callback, value: 'waiting_for_callback'
         state :pending, value: 'pending'
         state :running, value: 'running'
         state :failed, value: 'failed'
@@ -72,6 +74,7 @@ def stopped_statuses
       scope :waiting_for_resource, -> { with_status(:waiting_for_resource) }
       scope :preparing, -> { with_status(:preparing) }
       scope :relevant, -> { without_status(:created) }
+      scope :waiting_for_callback, -> { with_status(:waiting_for_callback) }
       scope :running, -> { with_status(:running) }
       scope :pending, -> { with_status(:pending) }
       scope :success, -> { with_status(:success) }
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 1a84a8729427cb110b67ff4c2b6d98764bdfffd8..3541de6e441d59e803620741eb5a7b568ee699a3 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -22273,7 +22273,7 @@ Represents a file or directory in the project repository that has been locked.
 | <a id="pipelinesourcejob"></a>`sourceJob` | [`CiJob`](#cijob) | Job where pipeline was triggered from. |
 | <a id="pipelinestages"></a>`stages` | [`CiStageConnection`](#cistageconnection) | Stages of the pipeline. (see [Connections](#connections)) |
 | <a id="pipelinestartedat"></a>`startedAt` | [`Time`](#time) | Timestamp when the pipeline was started. |
-| <a id="pipelinestatus"></a>`status` | [`PipelineStatusEnum!`](#pipelinestatusenum) | Status of the pipeline (CREATED, WAITING_FOR_RESOURCE, PREPARING, PENDING, RUNNING, FAILED, SUCCESS, CANCELED, SKIPPED, MANUAL, SCHEDULED). |
+| <a id="pipelinestatus"></a>`status` | [`PipelineStatusEnum!`](#pipelinestatusenum) | Status of the pipeline (CREATED, WAITING_FOR_RESOURCE, PREPARING, WAITING_FOR_CALLBACK, PENDING, RUNNING, FAILED, SUCCESS, CANCELED, SKIPPED, MANUAL, SCHEDULED). |
 | <a id="pipelinestuck"></a>`stuck` | [`Boolean!`](#boolean) | If the pipeline is stuck. |
 | <a id="pipelinetestreportsummary"></a>`testReportSummary` | [`TestReportSummary!`](#testreportsummary) | Summary of the test report generated by the pipeline. |
 | <a id="pipelinetotaljobs"></a>`totalJobs` | [`Int!`](#int) | The total number of jobs in the pipeline. |
@@ -27801,6 +27801,7 @@ Values for sorting inherited variables.
 | <a id="cijobstatusscheduled"></a>`SCHEDULED` | A job that is scheduled. |
 | <a id="cijobstatusskipped"></a>`SKIPPED` | A job that is skipped. |
 | <a id="cijobstatussuccess"></a>`SUCCESS` | A job that is success. |
+| <a id="cijobstatuswaiting_for_callback"></a>`WAITING_FOR_CALLBACK` | A job that is waiting for callback. |
 | <a id="cijobstatuswaiting_for_resource"></a>`WAITING_FOR_RESOURCE` | A job that is waiting for resource. |
 
 ### `CiJobTokenScopeDirection`
@@ -29379,6 +29380,7 @@ Event type of the pipeline associated with a merge request.
 | <a id="pipelinestatusenumscheduled"></a>`SCHEDULED` | Pipeline is scheduled to run. |
 | <a id="pipelinestatusenumskipped"></a>`SKIPPED` | Pipeline was skipped. |
 | <a id="pipelinestatusenumsuccess"></a>`SUCCESS` | Pipeline completed successfully. |
+| <a id="pipelinestatusenumwaiting_for_callback"></a>`WAITING_FOR_CALLBACK` | Pipeline is waiting for an external action. |
 | <a id="pipelinestatusenumwaiting_for_resource"></a>`WAITING_FOR_RESOURCE` | A resource (for example, a runner) that the pipeline requires to run is unavailable. |
 
 ### `ProductAnalyticsState`
diff --git a/lib/gitlab/ci/status/composite.rb b/lib/gitlab/ci/status/composite.rb
index 1ba78b357e53de84f344c85ac8492b8e19ef6327..fe4f6db95490834db57c050a203d2e695e69c4bd 100644
--- a/lib/gitlab/ci/status/composite.rb
+++ b/lib/gitlab/ci/status/composite.rb
@@ -61,6 +61,8 @@ def status
               'running'
             elsif any_of?(:waiting_for_resource)
               'waiting_for_resource'
+            elsif any_of?(:waiting_for_callback)
+              'waiting_for_callback'
             elsif any_of?(:manual)
               'manual'
             elsif any_of?(:scheduled)
diff --git a/lib/gitlab/ci/status/waiting_for_callback.rb b/lib/gitlab/ci/status/waiting_for_callback.rb
new file mode 100644
index 0000000000000000000000000000000000000000..0184a910edecba480c606f7cf6ceea9946205fad
--- /dev/null
+++ b/lib/gitlab/ci/status/waiting_for_callback.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module Gitlab
+  module Ci
+    module Status
+      class WaitingForCallback < Status::Core
+        def text
+          s_('CiStatusText|Waiting')
+        end
+
+        def label
+          s_('CiStatusLabel|waiting for callback')
+        end
+
+        def icon
+          'status_pending'
+        end
+
+        def favicon
+          'favicon_status_pending'
+        end
+
+        def group
+          'waiting-for-callback'
+        end
+
+        def details_path
+          nil
+        end
+      end
+    end
+  end
+end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 685abd710b6f4f16dd01d59594c0564cbfd19b7f..003c0a437bad8eb956230cc8aac0ca231ea3a601 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -10307,6 +10307,9 @@ msgstr ""
 msgid "CiStatusLabel|skipped"
 msgstr ""
 
+msgid "CiStatusLabel|waiting for callback"
+msgstr ""
+
 msgid "CiStatusLabel|waiting for delayed job"
 msgstr ""
 
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index 867db96aaafd1c923123392995ca5aa7c52d2c43..18415a6079fb5b81617707526a65d01945863e6c 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -117,6 +117,11 @@
       status { 'running' }
     end
 
+    trait :waiting_for_callback do
+      started
+      status { 'waiting_for_callback' }
+    end
+
     trait :pending do
       with_token
       queued_at { 'Di 29. Okt 09:50:59 CET 2013' }
diff --git a/spec/factories/commit_statuses.rb b/spec/factories/commit_statuses.rb
index 7d0176d0683bf76b223ba472bc9cb03633dfc1fa..e0b34bc39d8a0d4922333bbcaf211fdaeff0bf16 100644
--- a/spec/factories/commit_statuses.rb
+++ b/spec/factories/commit_statuses.rb
@@ -32,6 +32,10 @@
       status { 'running' }
     end
 
+    trait :waiting_for_callback do
+      status { 'waiting_for_callback' }
+    end
+
     trait :pending do
       status { 'pending' }
     end
diff --git a/spec/helpers/ci/jobs_helper_spec.rb b/spec/helpers/ci/jobs_helper_spec.rb
index 884fe7a018e87202c1e989c608684daea3d4e255..af369f7d42064f661921ba7abc77ad76dfdf6e0c 100644
--- a/spec/helpers/ci/jobs_helper_spec.rb
+++ b/spec/helpers/ci/jobs_helper_spec.rb
@@ -43,6 +43,7 @@
         "scheduled" => "SCHEDULED",
         "skipped" => "SKIPPED",
         "success" => "SUCCESS",
+        "waiting_for_callback" => "WAITING_FOR_CALLBACK",
         "waiting_for_resource" => "WAITING_FOR_RESOURCE"
       })
     end
diff --git a/spec/lib/gitlab/ci/status/composite_spec.rb b/spec/lib/gitlab/ci/status/composite_spec.rb
index 32b95c433b24ab7eb01bf480948d47b0438a95d4..e46ad5732352ba3ed54f347ae46d86b8c2766963 100644
--- a/spec/lib/gitlab/ci/status/composite_spec.rb
+++ b/spec/lib/gitlab/ci/status/composite_spec.rb
@@ -57,6 +57,7 @@
         %i[pending created skipped success] | true  | 'skipped'              | false
         %i[running created skipped success] | true  | 'skipped'              | false
         %i[success waiting_for_resource]    | false | 'waiting_for_resource' | false
+        %i[success waiting_for_callback]    | false | 'waiting_for_callback' | false
         %i[success manual]                  | false | 'manual'               | false
         %i[success scheduled]               | false | 'scheduled'            | false
         %i[created preparing]               | false | 'preparing'            | false
diff --git a/spec/lib/gitlab/ci/status/waiting_for_callback_spec.rb b/spec/lib/gitlab/ci/status/waiting_for_callback_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6c833e9613756ccec81fba52ebaed19cad1e6995
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/waiting_for_callback_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Status::WaitingForCallback, feature_category: :deployment_management do
+  subject do
+    described_class.new(double, double)
+  end
+
+  describe '#text' do
+    it { expect(subject.text).to eq 'Waiting' }
+  end
+
+  describe '#label' do
+    it { expect(subject.label).to eq 'waiting for callback' }
+  end
+
+  describe '#icon' do
+    it { expect(subject.icon).to eq 'status_pending' }
+  end
+
+  describe '#favicon' do
+    it { expect(subject.favicon).to eq 'favicon_status_pending' }
+  end
+
+  describe '#group' do
+    it { expect(subject.group).to eq 'waiting-for-callback' }
+  end
+
+  describe '#name' do
+    it { expect(subject.name).to eq 'WAITING_FOR_CALLBACK' }
+  end
+
+  describe '#details_path' do
+    it { expect(subject.details_path).to be_nil }
+  end
+end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 0094f56d96ea07919b3cbdc0ed339dcc6a0e883f..e0ca7276dc462af2014103ab30d93e521e9abeae 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -2819,7 +2819,7 @@ def create_pipeline(status, ref, sha)
     subject { described_class.bridgeable_statuses }
 
     it { is_expected.to be_an(Array) }
-    it { is_expected.not_to include('created', 'waiting_for_resource', 'preparing', 'pending') }
+    it { is_expected.to contain_exactly('running', 'success', 'failed', 'canceled', 'skipped', 'manual', 'scheduled') }
   end
 
   describe '#status', :sidekiq_inline do
@@ -3176,6 +3176,7 @@ def create_pipeline(status, ref, sha)
     %i[
       enqueue
       request_resource
+      wait_for_callback
       prepare
       run
       skip
diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb
index 1be50083cd465b4d92c4559d459a5a775cdbd5d8..4951f57fe6fb8616591620e30d6d14515ca0a7e2 100644
--- a/spec/models/ci/stage_spec.rb
+++ b/spec/models/ci/stage_spec.rb
@@ -166,6 +166,18 @@
       end
     end
 
+    context 'when build is waiting for callback' do
+      before do
+        create(:ci_build, :waiting_for_callback, stage_id: stage.id)
+      end
+
+      it 'updates status to waiting for callback' do
+        expect { stage.update_legacy_status }
+          .to change { stage.reload.status }
+          .to 'waiting_for_callback'
+      end
+    end
+
     context 'when stage is skipped because is empty' do
       it 'updates status to skipped' do
         expect { stage.update_legacy_status }
diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb
index ac356bcd65a4a3a3dda13a51b93817680e70b9f3..9371fde4d4b98e03bcc196766df86befed434107 100644
--- a/spec/models/commit_status_spec.rb
+++ b/spec/models/commit_status_spec.rb
@@ -156,7 +156,7 @@ def create_status(**opts)
   describe '.cancelable' do
     subject { described_class.cancelable }
 
-    %i[running pending waiting_for_resource preparing created scheduled].each do |status|
+    %i[running pending waiting_for_resource waiting_for_callback preparing created scheduled].each do |status|
       context "when #{status} commit status" do
         let!(:commit_status) { create(:commit_status, status, pipeline: pipeline) }
 
diff --git a/spec/models/concerns/ci/has_status_spec.rb b/spec/models/concerns/ci/has_status_spec.rb
index 5e0a430aa130f8e299c9cecec997eb181bd8ccfd..95f17c4f85478c3b69985aade68d174146c19cfc 100644
--- a/spec/models/concerns/ci/has_status_spec.rb
+++ b/spec/models/concerns/ci/has_status_spec.rb
@@ -55,6 +55,22 @@
         it { is_expected.to eq 'waiting_for_resource' }
       end
 
+      context 'all waiting for callback' do
+        let!(:statuses) do
+          [create(type, status: :waiting_for_callback), create(type, status: :waiting_for_callback)]
+        end
+
+        it { is_expected.to eq 'waiting_for_callback' }
+      end
+
+      context 'at least one waiting for callback' do
+        let!(:statuses) do
+          [create(type, status: :success), create(type, status: :waiting_for_callback)]
+        end
+
+        it { is_expected.to eq 'waiting_for_callback' }
+      end
+
       context 'all preparing' do
         let!(:statuses) do
           [create(type, status: :preparing), create(type, status: :preparing)]
@@ -225,7 +241,7 @@
       end
     end
 
-    %i[created waiting_for_resource preparing running pending success
+    %i[created waiting_for_callback waiting_for_resource preparing running pending success
        failed canceled skipped].each do |status|
       it_behaves_like 'having a job', status
     end
@@ -271,7 +287,7 @@
     describe '.alive' do
       subject { CommitStatus.alive }
 
-      %i[running pending waiting_for_resource preparing created].each do |status|
+      %i[running pending waiting_for_callback waiting_for_resource preparing created].each do |status|
         it_behaves_like 'containing the job', status
       end
 
@@ -283,7 +299,7 @@
     describe '.alive_or_scheduled' do
       subject { CommitStatus.alive_or_scheduled }
 
-      %i[running pending waiting_for_resource preparing created scheduled].each do |status|
+      %i[running pending waiting_for_callback waiting_for_resource preparing created scheduled].each do |status|
         it_behaves_like 'containing the job', status
       end
 
@@ -319,7 +335,7 @@
     describe '.cancelable' do
       subject { CommitStatus.cancelable }
 
-      %i[running pending waiting_for_resource preparing created scheduled].each do |status|
+      %i[running pending waiting_for_callback waiting_for_resource preparing created scheduled].each do |status|
         it_behaves_like 'containing the job', status
       end