diff --git a/doc/api/usage_data.md b/doc/api/usage_data.md
index a61bf9b9827506d8c4167dd1f21c6cc400c6e992..29854e58254eb83a226d09a2084e2ce670c39ceb 100644
--- a/doc/api/usage_data.md
+++ b/doc/api/usage_data.md
@@ -192,3 +192,56 @@ Sample response:
   },
 ...
 ```
+
+## Events Tracking API
+
+Tracks internal events in GitLab. Requires a personal access token with the `api` or `ai_workflows` scope.
+
+To track events to Snowplow, set the `send_to_snowplow` parameter to `true`.
+
+Example request:
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" \
+     --header "Content-Type: application/json" \
+     --request POST \
+     --data '{
+       "event": "mr_name_changed",
+       "send_to_snowplow": true,
+       "namespace_id": 1,
+       "project_id": 1,
+       "additional_properties": {
+         "lang": "eng"
+       }
+     }' \
+     "https://gitlab.example.com/api/v4/usage_data/track_event"
+```
+
+If multiple events tracking is required, send an array of events to the `/track_events` endpoint:
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" \
+     --header "Content-Type: application/json" \
+     --request POST \
+     --data '{
+       "events": [
+         {
+           "event": "mr_name_changed",
+           "namespace_id": 1,
+           "project_id": 1,
+           "additional_properties": {
+             "lang": "eng"
+           }
+         },
+         {
+           "event": "mr_name_changed",
+           "namespace_id": 2,
+           "project_id": 2,
+           "additional_properties": {
+             "lang": "eng"
+           }
+         }
+       ]
+     }' \
+     "https://gitlab.example.com/api/v4/usage_data/track_events"
+```
diff --git a/doc/development/internal_analytics/internal_event_instrumentation/quick_start.md b/doc/development/internal_analytics/internal_event_instrumentation/quick_start.md
index 680b71411c17237ab951f77e92d7383616e99811..7aaeb81ee5d1a74c4d4c20b094e72fd716dba45b 100644
--- a/doc/development/internal_analytics/internal_event_instrumentation/quick_start.md
+++ b/doc/development/internal_analytics/internal_event_instrumentation/quick_start.md
@@ -564,6 +564,11 @@ describe('DeleteApplication', () => {
 });
 ```
 
+### Using Internal Events API
+
+You can also use our API to track events from other systems connected to a GitLab instance.
+See the [Usage Data API documentation](../../../api/usage_data.md#events-tracking-api) for more information.
+
 ### Internal Events on other systems
 
 Apart from the GitLab codebase, we are using Internal Events for the systems listed below.
diff --git a/lib/api/usage_data.rb b/lib/api/usage_data.rb
index 9a9ed959b7c3e56b2a5e5b385bd2b3aa52ddcb7b..e6e74cdd689c10aff2708ba2226924af38aaa541 100644
--- a/lib/api/usage_data.rb
+++ b/lib/api/usage_data.rb
@@ -20,6 +20,8 @@ class UsageData < ::API::Base
           documentation: { example: 1234 }
         optional :additional_properties, type: Hash, desc: 'Additional properties to be tracked',
           documentation: { example: { label: 'login_button', value: 1 } }
+        optional :send_to_snowplow, type: Boolean, desc: 'Send the tracked event to Snowplow',
+          documentation: { example: true, default: false }
       end
 
       def process_event(params)
@@ -27,12 +29,13 @@ def process_event(params)
         namespace_id = params[:namespace_id]
         project_id = params[:project_id]
         additional_properties = params.fetch(:additional_properties, {}).symbolize_keys
+        send_snowplow_event = !!params[:send_to_snowplow]
 
         Gitlab::Tracking::AiTracking.track_event(event_name, additional_properties.merge(user: current_user))
 
         track_event(
           event_name,
-          send_snowplow_event: false,
+          send_snowplow_event: send_snowplow_event,
           user: current_user,
           namespace_id: namespace_id,
           project_id: project_id,
diff --git a/spec/requests/api/usage_data_spec.rb b/spec/requests/api/usage_data_spec.rb
index d7f2ad3b4c76c590b50cb5a03143597afb4ca552..483137ca1dcdea9a1dec589a19892b478edaac97 100644
--- a/spec/requests/api/usage_data_spec.rb
+++ b/spec/requests/api/usage_data_spec.rb
@@ -280,6 +280,75 @@
           end
         end
       end
+
+      describe 'send_to_snowplow param' do
+        it 'does not send the event to snowplow when send_to_snowplow is false' do
+          expect(Gitlab::InternalEvents).to receive(:track_event)
+            .with(
+              known_event,
+              send_snowplow_event: false,
+              user: user,
+              namespace: namespace,
+              project: project,
+              additional_properties: additional_properties
+            )
+
+          post api(endpoint, user), params: {
+            event: known_event,
+            namespace_id: namespace.id,
+            project_id: project.id,
+            additional_properties: additional_properties,
+            send_to_snowplow: false
+          }
+
+          expect(response).to have_gitlab_http_status(:ok)
+        end
+
+        it 'sends event to Snowplow when send_to_snowplow is true' do
+          expect(Gitlab::InternalEvents).to receive(:track_event)
+            .with(
+              known_event,
+              send_snowplow_event: true,
+              user: user,
+              namespace: namespace,
+              project: project,
+              additional_properties: additional_properties
+            )
+
+          post api(endpoint, user), params:
+            {
+              event: known_event,
+              namespace_id: namespace.id,
+              project_id: project.id,
+              additional_properties: additional_properties,
+              send_to_snowplow: true
+            }
+
+          expect(response).to have_gitlab_http_status(:ok)
+        end
+
+        it 'does not send event to Snowplow by default' do
+          expect(Gitlab::InternalEvents).to receive(:track_event)
+            .with(
+              known_event,
+              send_snowplow_event: false,
+              user: user,
+              namespace: namespace,
+              project: project,
+              additional_properties: additional_properties
+            )
+
+          post api(endpoint, user), params:
+            {
+              event: known_event,
+              namespace_id: namespace.id,
+              project_id: project.id,
+              additional_properties: additional_properties
+            }
+
+          expect(response).to have_gitlab_http_status(:ok)
+        end
+      end
     end
   end
 
@@ -305,16 +374,12 @@
     end
 
     context 'with the amount events greater than the limit' do
-      let(:params) do
-        {
-          events: Array.new(API::UsageData::MAXIMUM_TRACKED_EVENTS * 2) { { event: event } }
-        }
-      end
+      let(:params) { { events: Array.new(API::UsageData::MAXIMUM_TRACKED_EVENTS * 2) { { event: event } } } }
 
       it 'returns bad request' do
         expect(Gitlab::InternalEvents).not_to receive(:track_event)
 
-        post(api(endpoint, user), params: params)
+        post api(endpoint, user), params: params
 
         expect(response).to have_gitlab_http_status(:bad_request)
       end