diff --git a/src/GitLabApiClient/IResourceLabelEventsClient.cs b/src/GitLabApiClient/IResourceLabelEventsClient.cs
new file mode 100644
index 00000000..658e0cd4
--- /dev/null
+++ b/src/GitLabApiClient/IResourceLabelEventsClient.cs
@@ -0,0 +1,31 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using GitLabApiClient.Internal.Paths;
+using GitLabApiClient.Models.LabelEvents.Responses;
+using GitLabApiClient.Models.Projects.Responses;
+
+namespace GitLabApiClient
+{
+ public interface IResourceLabelEventsClient
+ {
+ ///
+ /// Retrieves label events from issues.
+ ///
+ /// The ID, path or of the project.
+ /// Resource type (supported resources: Issues, Epics, MergeRequests)
+ /// The IID of an issue, ID of an Epic, or IID of a Merge Request
+ /// Label Events for the given resource type and id
+ Task> GetAllAsync(ProjectId projectId, EventResourceType eventResourceType, int resourceId);
+
+ ///
+ /// Retrieves a single label event from issues.
+ ///
+ /// The ID, path or of the project.
+ /// Resource type (supported resources: Issues, Epics, MergeRequests)
+ /// The IID of an issue, ID of an Epic, or IID of a Merge Request
+ /// The ID of a label event
+ /// Label Events for the given issue Id
+ Task> GetAsync(ProjectId projectId, EventResourceType eventResourceType, int resourceId,
+ int eventId);
+ }
+}
diff --git a/src/GitLabApiClient/Models/LabelEvents/Responses/EventResourceType.cs b/src/GitLabApiClient/Models/LabelEvents/Responses/EventResourceType.cs
new file mode 100644
index 00000000..5163c8d8
--- /dev/null
+++ b/src/GitLabApiClient/Models/LabelEvents/Responses/EventResourceType.cs
@@ -0,0 +1,25 @@
+using System;
+using System.ComponentModel;
+
+namespace GitLabApiClient.Models.LabelEvents.Responses
+{
+ public enum EventResourceType
+ {
+ [Description("issues")]
+ Issues,
+ [Description("epics")]
+ Epics,
+ [Description("merge_requests")]
+ MergeRequests
+ }
+
+ internal static class EnumExtensions
+ {
+ public static string GetDescription(this Enum value)
+ {
+ var field = value.GetType().GetField(value.ToString());
+ var attributes = (DescriptionAttribute[])field.GetCustomAttributes(typeof(DescriptionAttribute), false);
+ return attributes.Length > 0 ? attributes[0].Description : value.ToString();
+ }
+ }
+}
diff --git a/src/GitLabApiClient/Models/LabelEvents/Responses/LabelEvent.cs b/src/GitLabApiClient/Models/LabelEvents/Responses/LabelEvent.cs
new file mode 100644
index 00000000..52868bea
--- /dev/null
+++ b/src/GitLabApiClient/Models/LabelEvents/Responses/LabelEvent.cs
@@ -0,0 +1,18 @@
+using GitLabApiClient.Models.Projects.Responses;
+using GitLabApiClient.Models.Users.Responses;
+using Newtonsoft.Json;
+
+namespace GitLabApiClient.Models.LabelEvents.Responses
+{
+ public class LabelEvent : Resource
+ {
+ [JsonProperty("user")]
+ public User User { get; set; }
+
+ [JsonProperty("label")]
+ public Label Label { get; set; }
+
+ [JsonProperty("action")]
+ public string Action { get; set; }
+ }
+}
diff --git a/src/GitLabApiClient/Models/Resource.cs b/src/GitLabApiClient/Models/Resource.cs
new file mode 100644
index 00000000..fd3b6cfd
--- /dev/null
+++ b/src/GitLabApiClient/Models/Resource.cs
@@ -0,0 +1,22 @@
+using System;
+using Newtonsoft.Json;
+
+namespace GitLabApiClient.Models
+{
+ public class Resource
+ {
+ internal Resource() { }
+
+ [JsonProperty("id")]
+ public int Id { get; set; }
+
+ [JsonProperty("created_at")]
+ public DateTime CreatedAt { get; set; }
+
+ [JsonProperty("resource_type")]
+ public string ResourceType { get; set; }
+
+ [JsonProperty("resource_id")]
+ public string ResourceId { get; set; }
+ }
+}
diff --git a/src/GitLabApiClient/ResourceLabelEventsClient.cs b/src/GitLabApiClient/ResourceLabelEventsClient.cs
new file mode 100644
index 00000000..7593e0d7
--- /dev/null
+++ b/src/GitLabApiClient/ResourceLabelEventsClient.cs
@@ -0,0 +1,36 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using GitLabApiClient.Internal.Http;
+using GitLabApiClient.Internal.Paths;
+using GitLabApiClient.Models.LabelEvents.Responses;
+
+namespace GitLabApiClient
+{
+ public sealed class ResourceLabelEventsClient : IResourceLabelEventsClient
+ {
+ private readonly GitLabHttpFacade _httpFacade;
+
+ internal ResourceLabelEventsClient(GitLabHttpFacade httpFacade) =>
+ _httpFacade = httpFacade;
+
+ public async Task> GetAllAsync(
+ ProjectId projectId,
+ EventResourceType eventResourceType,
+ int resourceId)
+ {
+ string query =
+ $"projects/{projectId}/{eventResourceType.GetDescription()}/{resourceId}/resource_label_events";
+ return await _httpFacade.GetPagedList(query);
+ }
+
+ public async Task> GetAsync(ProjectId projectId,
+ EventResourceType eventResourceType,
+ int resourceId,
+ int eventId)
+ {
+ string query =
+ $"projects/{projectId}/{eventResourceType.GetDescription()}/{resourceId}/resource_label_events/{eventId}";
+ return await _httpFacade.GetPagedList(query);
+ }
+ }
+}
diff --git a/test/GitLabApiClient.Test/ResourceLabelEventsClientTest.cs b/test/GitLabApiClient.Test/ResourceLabelEventsClientTest.cs
new file mode 100644
index 00000000..05215efd
--- /dev/null
+++ b/test/GitLabApiClient.Test/ResourceLabelEventsClientTest.cs
@@ -0,0 +1,54 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using FluentAssertions;
+using GitLabApiClient.Internal.Queries;
+using GitLabApiClient.Models.Issues.Requests;
+using GitLabApiClient.Models.LabelEvents.Responses;
+using GitLabApiClient.Test.Utilities;
+using Xunit;
+
+namespace GitLabApiClient.Test
+{
+ [Trait("Category", "LinuxIntegration")]
+ [Collection("GitLabContainerFixture")]
+ public class ResourceLabelEventsClientTest : IAsyncLifetime
+ {
+ private readonly MergeRequestsClient _mergeRequestsClient = new MergeRequestsClient(
+ GitLabApiHelper.GetFacade(), new MergeRequestsQueryBuilder(), new ProjectMergeRequestsQueryBuilder(),
+ new ProjectMergeRequestsNotesQueryBuilder());
+
+ private readonly IssuesClient _issuesClient = new IssuesClient(
+ GitLabApiHelper.GetFacade(), new IssuesQueryBuilder(), new ProjectIssueNotesQueryBuilder());
+
+ private readonly ResourceLabelEventsClient _sut = new ResourceLabelEventsClient(GitLabApiHelper.GetFacade());
+
+ [Fact]
+ public async Task IssuesLabelEventsCanBeRetrieved()
+ {
+ var createdIssue = await _issuesClient.CreateAsync(
+ GitLabApiHelper.TestProjectTextId, new CreateIssueRequest("Title1")
+ {
+ Assignees = new List { 1 },
+ Confidential = true,
+ Description = "Description1",
+ Labels = new[] { "Label1" },
+ MilestoneId = 2,
+ DiscussionToResolveId = 3,
+ MergeRequestIdToResolveDiscussions = 4
+ });
+
+ var labelEvents = await _sut.GetAllAsync(
+ GitLabApiHelper.TestProjectTextId,
+ EventResourceType.Issues,
+ createdIssue.Iid
+ );
+
+ labelEvents.Single().Should().Match(actual =>
+ actual.Label.Name == "Label1");
+ }
+
+ public Task InitializeAsync() => throw new System.NotImplementedException();
+ public Task DisposeAsync() => throw new System.NotImplementedException();
+ }
+}