diff --git a/NetCord/Rest/AllowedMentionsProperties.cs b/NetCord/Rest/AllowedMentionsProperties.cs
index 75a4d5aa8..67bb2dcb9 100644
--- a/NetCord/Rest/AllowedMentionsProperties.cs
+++ b/NetCord/Rest/AllowedMentionsProperties.cs
@@ -21,7 +21,7 @@ public partial class AllowedMentionsProperties
///
/// A list of mentionable role IDs. Allows all roles if set to .
///
- /// ///
+ ///
///
/// If a role's property is set to , and is not set, it will not be mentioned regardless.
///
diff --git a/NetCord/Rest/JsonModels/JsonChannelPins.cs b/NetCord/Rest/JsonModels/JsonChannelPins.cs
new file mode 100644
index 000000000..00652eee1
--- /dev/null
+++ b/NetCord/Rest/JsonModels/JsonChannelPins.cs
@@ -0,0 +1,14 @@
+using System.Text.Json.Serialization;
+
+using NetCord.JsonModels;
+
+namespace NetCord.Rest.JsonModels;
+
+internal class JsonChannelPins
+{
+ [JsonPropertyName("items")]
+ public JsonMessagePin[] Items { get; set; }
+
+ [JsonPropertyName("has_more")]
+ public bool HasMore { get; set; }
+}
diff --git a/NetCord/Rest/JsonModels/JsonMessagePin.cs b/NetCord/Rest/JsonModels/JsonMessagePin.cs
new file mode 100644
index 000000000..4099daa7a
--- /dev/null
+++ b/NetCord/Rest/JsonModels/JsonMessagePin.cs
@@ -0,0 +1,14 @@
+using System.Text.Json.Serialization;
+
+using NetCord.JsonModels;
+
+namespace NetCord.Rest.JsonModels;
+
+public class JsonMessagePin
+{
+ [JsonPropertyName("pinned_at")]
+ public DateTimeOffset PinnedAt { get; set; }
+
+ [JsonPropertyName("message")]
+ public JsonMessage Message { get; set; }
+}
diff --git a/NetCord/Rest/MessagePin.cs b/NetCord/Rest/MessagePin.cs
new file mode 100644
index 000000000..e46633b61
--- /dev/null
+++ b/NetCord/Rest/MessagePin.cs
@@ -0,0 +1,19 @@
+namespace NetCord.Rest;
+
+///
+/// Represents a message pin in a channel, containing the pinned message and the time it was pinned.
+///
+public class MessagePin(JsonModels.JsonMessagePin jsonModel, RestClient client) : IJsonModel
+{
+ JsonModels.JsonMessagePin IJsonModel.JsonModel => jsonModel;
+
+ ///
+ /// The time the message was pinned.
+ ///
+ public DateTimeOffset PinnedAt => jsonModel.PinnedAt;
+
+ ///
+ /// The pinned message.
+ ///
+ public RestMessage Message { get; } = new(jsonModel.Message, client);
+}
diff --git a/NetCord/Rest/RestClient.Channel.cs b/NetCord/Rest/RestClient.Channel.cs
index ef8b636c5..018be8336 100644
--- a/NetCord/Rest/RestClient.Channel.cs
+++ b/NetCord/Rest/RestClient.Channel.cs
@@ -645,7 +645,7 @@ public Task TriggerTypingAsync(ulong channelId, RestRequestProperties? propertie
=> SendRequestAsync(HttpMethod.Post, $"/channels/{channelId}/typing", null, new(channelId), properties, cancellationToken: cancellationToken);
///
- /// /// Enters a typing scope for a channel, while waiting for the typing indicator to trigger.
+ /// Enters a typing scope for a channel, while waiting for the typing indicator to trigger.
///
/// The ID of the channel to type in.
/// Optional properties to customize the typing interval, can be .
@@ -660,7 +660,7 @@ public ValueTask EnterTypingScopeAsync(ulong channelId, TypingScope
}
///
- /// /// Enters a typing scope for a channel, while waiting for the typing indicator to trigger.
+ /// Enters a typing scope for a channel, while waiting for the typing indicator to trigger.
///
/// The ID of the channel to type in.
/// Optional properties to customize the typing interval, can be .
@@ -674,16 +674,45 @@ public IDisposable EnterTypingScope(ulong channelId, TypingScopeProperties? scop
///
/// Retrieves all pinned messages in a channel.
///
+ ///
+ /// Requires the permission.
+ /// If the user is missing the permission in the channel, then no pins will be returned.
+ ///
/// The ID of the channel to get pinned messages from.
- /// Optional properties to customize the request, can be .
+ /// Optional properties to customize result pagination, can be .
+ /// Optional properties to customize each request, can be .
/// A token that can be used to cancel the operation before it completes.
- [GenerateAlias([typeof(TextChannel)], nameof(TextChannel.Id))]
- public async Task> GetPinnedMessagesAsync(ulong channelId, RestRequestProperties? properties = null, CancellationToken cancellationToken = default)
- => (await (await SendRequestAsync(HttpMethod.Get, $"/channels/{channelId}/pins", null, new(channelId), properties, cancellationToken: cancellationToken).ConfigureAwait(false)).ToObjectAsync(Serialization.Default.JsonMessageArray).ConfigureAwait(false)).Select(m => new RestMessage(m, this)).ToArray();
+ [GenerateAlias([typeof(TextChannel)], nameof(TextChannel.Id), TypeNameOverride = "Channel")]
+ public IAsyncEnumerable GetChannelPinsAsync(ulong channelId, PaginationProperties? paginationProperties = null, RestRequestProperties? properties = null, CancellationToken cancellationToken = default)
+ {
+ paginationProperties =
+ PaginationProperties.PrepareWithDirectionValidation(
+ paginationProperties,
+ PaginationDirection.Before,
+ 50);
+
+ return new OptimizedQueryPaginationAsyncEnumerable(
+ this,
+ paginationProperties,
+ async s =>
+ {
+ var result = await s.ToObjectAsync(Serialization.Default.JsonChannelPins).ConfigureAwait(false);
+ return (result.Items.Select(m => new MessagePin(m, this)), result.HasMore);
+ },
+ m => m.PinnedAt,
+ HttpMethod.Get,
+ $"/channels/{channelId}/messages/pins",
+ new(paginationProperties.BatchSize.GetValueOrDefault(), paginationProperties.Direction.GetValueOrDefault(), timestamp => timestamp.ToString("s")),
+ new(channelId),
+ properties);
+ }
///
/// Pins a message in a channel.
///
+ ///
+ /// Requires the permission. Fires a event.
+ ///
/// The ID of the channel containing the message.
/// The ID of the message to pin.
/// Optional properties to customize the request, can be .
@@ -691,11 +720,14 @@ public async Task> GetPinnedMessagesAsync(ulong chann
[GenerateAlias([typeof(TextChannel)], nameof(TextChannel.Id))]
[GenerateAlias([typeof(RestMessage)], nameof(RestMessage.ChannelId), nameof(RestMessage.Id), TypeNameOverride = "Message")]
public Task PinMessageAsync(ulong channelId, ulong messageId, RestRequestProperties? properties = null, CancellationToken cancellationToken = default)
- => SendRequestAsync(HttpMethod.Put, $"/channels/{channelId}/pins/{messageId}", null, new(channelId), properties, cancellationToken: cancellationToken);
+ => SendRequestAsync(HttpMethod.Put, $"/channels/{channelId}/messages/pins/{messageId}", null, new(channelId), properties, cancellationToken: cancellationToken);
///
/// Unpins a message from a channel.
///
+ ///
+ /// Requires the permission. Fires a event.
+ ///
/// The ID of the channel containing the message.
/// The ID of the message to unpin.
/// Optional properties to customize the request, can be .
@@ -703,7 +735,7 @@ public Task PinMessageAsync(ulong channelId, ulong messageId, RestRequestPropert
[GenerateAlias([typeof(TextChannel)], nameof(TextChannel.Id))]
[GenerateAlias([typeof(RestMessage)], nameof(RestMessage.ChannelId), nameof(RestMessage.Id), TypeNameOverride = "Message")]
public Task UnpinMessageAsync(ulong channelId, ulong messageId, RestRequestProperties? properties = null, CancellationToken cancellationToken = default)
- => SendRequestAsync(HttpMethod.Delete, $"/channels/{channelId}/pins/{messageId}", null, new(channelId), properties, cancellationToken: cancellationToken);
+ => SendRequestAsync(HttpMethod.Delete, $"/channels/{channelId}/messages/pins/{messageId}", null, new(channelId), properties, cancellationToken: cancellationToken);
///
/// Adds a recipient to a group DM channel.
diff --git a/NetCord/Serialization.cs b/NetCord/Serialization.cs
index f8be6b8a0..c38ec6ba9 100644
--- a/NetCord/Serialization.cs
+++ b/NetCord/Serialization.cs
@@ -211,6 +211,7 @@ namespace NetCord;
[JsonSerializable(typeof(JsonEntitlement[]))]
[JsonSerializable(typeof(JsonSku[]))]
[JsonSerializable(typeof(JsonAuthorizationInformation))]
+[JsonSerializable(typeof(JsonChannelPins))]
[JsonSerializable(typeof(StageInstanceProperties))]
[JsonSerializable(typeof(StageInstanceOptions))]
[JsonSerializable(typeof(JsonSticker))]