Repository: hikari-py/hikari
Pull request #1571 (2023-04-02 01:46:07)

Add support for sending sticker_ids on create_message
### Summary
<!-- Small summary of the merge request -->

### Checklist
<!-- Make sure to tick all the following boxes by putting an `x` in between (like this `[x]`) -->
- [ ] I have run `nox` and all the pipelines have passed.
- [ ] I have made unittests according to the code I have added/modified/deleted.

### Related issues
<!--
To mention an issue use `#issue-id` and to mention a merge request use `!merge-request-id`
To close/fix an issue use `Close #issue-id` or `Fix #issue-id` (depending on the merge request)
-->



Patch:
diff --git a/changes/1571.feature.md b/changes/1571.feature.md
new file mode 100644
index 00000000..0501b434
--- /dev/null
+++ b/changes/1571.feature.md
@@ -0,0 +1,1 @@
+Support sending stickers when creating a message.
diff --git a/changes/1572.breaking.md b/changes/1572.breaking.md
new file mode 100644
index 00000000..97a442cb
--- /dev/null
+++ b/changes/1572.breaking.md
@@ -0,0 +1,1 @@
+Renamed `StickerPack.banner_hash` to `StickerPack.banner_asset_id`.
diff --git a/changes/1572.bugfix.md b/changes/1572.bugfix.md
new file mode 100644
index 00000000..c94172d3
--- /dev/null
+++ b/changes/1572.bugfix.md
@@ -0,0 +1,5 @@
+Fixed sticker pack handling and typing:
+
+* Fixed deserialization raising when `"banner_asset_id"` or `"cover_sticker_id"` weren't included in the payload.
+* `StickerPack.banner_asset_id` is now correctly typed as `Optional[Snowflake]`.
+* `StickerPack.banner_url` and `StickerPack.make_banner_url` both now correctly return `None` when `StickerPack.banner_asset_id` is `None`.
diff --git a/hikari/api/rest.py b/hikari/api/rest.py
index b2fb50ec..efda13eb 100644
--- a/hikari/api/rest.py
+++ b/hikari/api/rest.py
@@ -50,7 +50,7 @@
     from hikari import permissions as permissions_
     from hikari import sessions
     from hikari import snowflakes
-    from hikari import stickers
+    from hikari import stickers as stickers_
     from hikari import templates
     from hikari import users
     from hikari import voices
@@ -1000,6 +1000,10 @@ async def create_message(
         components: undefined.UndefinedOr[typing.Sequence[special_endpoints.ComponentBuilder]] = undefined.UNDEFINED,
         embed: undefined.UndefinedOr[embeds_.Embed] = undefined.UNDEFINED,
         embeds: undefined.UndefinedOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
+        sticker: undefined.UndefinedOr[snowflakes.SnowflakeishOr[stickers_.PartialSticker]] = undefined.UNDEFINED,
+        stickers: undefined.UndefinedOr[
+            snowflakes.SnowflakeishSequence[stickers_.PartialSticker]
+        ] = undefined.UNDEFINED,
         tts: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
         reply: undefined.UndefinedOr[snowflakes.SnowflakeishOr[messages_.PartialMessage]] = undefined.UNDEFINED,
         reply_must_exist: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
@@ -1076,6 +1080,15 @@ async def create_message(
             If provided, the message embed.
         embeds : hikari.undefined.UndefinedOr[typing.Sequence[hikari.embeds.Embed]]
             If provided, the message embeds.
+        sticker : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.stickers.PartialSticker]]
+            If provided, the object or ID of a sticker to send on the message.
+
+            As of writing, bots can only send custom stickers from the current guild.
+        stickers : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishSequence[hikari.stickers.PartialSticker]]
+            If provided, a sequence of the objects and IDs of up to 3 stickers
+            to send on the message.
+
+            As of writing, bots can only send custom stickers from the current guild.
         tts : hikari.undefined.UndefinedOr[bool]
             If provided, whether the message will be read out by a screen
             reader using Discord's TTS (text-to-speech) system.
@@ -3469,7 +3482,7 @@ async def delete_emoji(
         """
 
     @abc.abstractmethod
-    async def fetch_available_sticker_packs(self) -> typing.Sequence[stickers.StickerPack]:
+    async def fetch_available_sticker_packs(self) -> typing.Sequence[stickers_.StickerPack]:
         """Fetch the available sticker packs.
 
         Returns
@@ -3489,13 +3502,13 @@ async def fetch_available_sticker_packs(self) -> typing.Sequence[stickers.Sticke
     @abc.abstractmethod
     async def fetch_sticker(
         self,
-        sticker: snowflakes.SnowflakeishOr[stickers.PartialSticker],
-    ) -> typing.Union[stickers.GuildSticker, stickers.StandardSticker]:
+        sticker: snowflakes.SnowflakeishOr[stickers_.PartialSticker],
+    ) -> typing.Union[stickers_.GuildSticker, stickers_.StandardSticker]:
         """Fetch a sticker.
 
         Parameters
         ----------
-        sticker : snowflakes.SnowflakeishOr[stickers.PartialSticker]
+        sticker : hikari.snowflakes.SnowflakeishOr[hikari.stickers.PartialSticker]
             The sticker to fetch. This can be a sticker object or the
             ID of an existing sticker.
 
@@ -3520,12 +3533,12 @@ async def fetch_sticker(
     @abc.abstractmethod
     async def fetch_guild_stickers(
         self, guild: snowflakes.SnowflakeishOr[guilds.PartialGuild]
-    ) -> typing.Sequence[stickers.GuildSticker]:
+    ) -> typing.Sequence[stickers_.GuildSticker]:
         """Fetch a standard sticker.
 
         Parameters
         ----------
-        guild : snowflakes.SnowflakeishOr[stickers.PartialGuild]
+        guild : hikari.snowflakes.SnowflakeishOr[hikari.stickers.PartialGuild]
             The guild to request stickers for. This can be a guild object or the
             ID of an existing guild.
 
@@ -3553,16 +3566,16 @@ async def fetch_guild_stickers(
     async def fetch_guild_sticker(
         self,
         guild: snowflakes.SnowflakeishOr[guilds.PartialGuild],
-        sticker: snowflakes.SnowflakeishOr[stickers.PartialSticker],
-    ) -> stickers.GuildSticker:
+        sticker: snowflakes.SnowflakeishOr[stickers_.PartialSticker],
+    ) -> stickers_.GuildSticker:
         """Fetch a guild sticker.
 
         Parameters
         ----------
-        guild : snowflakes.SnowflakeishOr[stickers.PartialGuild]
+        guild : hikari.snowflakes.SnowflakeishOr[hikari.stickers.PartialGuild]
             The guild the sticker is in. This can be a guild object or the
             ID of an existing guild.
-        sticker : snowflakes.SnowflakeishOr[stickers.PartialSticker]
+        sticker : hikari.snowflakes.SnowflakeishOr[hikari.stickers.PartialSticker]
             The sticker to fetch. This can be a sticker object or the
             ID of an existing sticker.
 
@@ -3596,7 +3609,7 @@ async def create_sticker(
         *,
         description: undefined.UndefinedOr[str] = undefined.UNDEFINED,
         reason: undefined.UndefinedOr[str] = undefined.UNDEFINED,
-    ) -> stickers.GuildSticker:
+    ) -> stickers_.GuildSticker:
         """Create a sticker in a guild.
 
         Parameters
@@ -3651,13 +3664,13 @@ async def create_sticker(
     async def edit_sticker(
         self,
         guild: snowflakes.SnowflakeishOr[guilds.PartialGuild],
-        sticker: snowflakes.SnowflakeishOr[stickers.PartialSticker],
+        sticker: snowflakes.SnowflakeishOr[stickers_.PartialSticker],
         *,
         name: undefined.UndefinedOr[str] = undefined.UNDEFINED,
         description: undefined.UndefinedOr[str] = undefined.UNDEFINED,
         tag: undefined.UndefinedOr[str] = undefined.UNDEFINED,
         reason: undefined.UndefinedOr[str] = undefined.UNDEFINED,
-    ) -> stickers.GuildSticker:
+    ) -> stickers_.GuildSticker:
         """Edit a sticker in a guild.
 
         Parameters
@@ -3707,7 +3720,7 @@ async def edit_sticker(
     async def delete_sticker(
         self,
         guild: snowflakes.SnowflakeishOr[guilds.PartialGuild],
-        sticker: snowflakes.SnowflakeishOr[stickers.PartialSticker],
+        sticker: snowflakes.SnowflakeishOr[stickers_.PartialSticker],
         *,
         reason: undefined.UndefinedOr[str] = undefined.UNDEFINED,
     ) -> None:
@@ -4618,6 +4631,10 @@ async def create_forum_post(
         components: undefined.UndefinedOr[typing.Sequence[special_endpoints.ComponentBuilder]] = undefined.UNDEFINED,
         embed: undefined.UndefinedOr[embeds_.Embed] = undefined.UNDEFINED,
         embeds: undefined.UndefinedOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
+        sticker: undefined.UndefinedOr[snowflakes.SnowflakeishOr[stickers_.PartialSticker]] = undefined.UNDEFINED,
+        stickers: undefined.UndefinedOr[
+            snowflakes.SnowflakeishSequence[stickers_.PartialSticker]
+        ] = undefined.UNDEFINED,
         tts: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
         mentions_everyone: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
         mentions_reply: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
@@ -4699,6 +4716,15 @@ async def create_forum_post(
             If provided, the message embed.
         embeds : hikari.undefined.UndefinedOr[typing.Sequence[hikari.embeds.Embed]]
             If provided, the message embeds.
+        sticker : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.stickers.PartialSticker]]
+            If provided, the object or ID of a sticker to send on the message.
+
+            As of writing, bots can only send custom stickers from the current guild.
+        stickers : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishSequence[hikari.stickers.PartialSticker]]
+            If provided, a sequence of the objects and IDs of up to 3 stickers
+            to send on the message.
+
+            As of writing, bots can only send custom stickers from the current guild.
         tts : hikari.undefined.UndefinedOr[bool]
             If provided, whether the message will be read out by a screen
             reader using Discord's TTS (text-to-speech) system.
@@ -7292,6 +7318,7 @@ def interaction_autocomplete_builder(
         choices: typing.Union[
             typing.Sequence[commands.CommandChoice], typing.Sequence[special_endpoints.AutocompleteChoiceBuilder]
         ],
+        _stack_level: int = 0,
     ) -> special_endpoints.InteractionAutocompleteBuilder:
         """Create a builder for an autocomplete interaction response.
 
@@ -7674,6 +7701,7 @@ async def create_autocomplete_response(
         choices: typing.Union[
             typing.Sequence[commands.CommandChoice], typing.Sequence[special_endpoints.AutocompleteChoiceBuilder]
         ],
+        _stack_level: int = 0,
     ) -> None:
         """Create the initial response for an autocomplete interaction.
 
diff --git a/hikari/channels.py b/hikari/channels.py
index ea2d4f0d..a6c6d44b 100644
--- a/hikari/channels.py
+++ b/hikari/channels.py
@@ -80,6 +80,7 @@
     from hikari import guilds
     from hikari import iterators
     from hikari import messages
+    from hikari import stickers as stickers_
     from hikari import users
     from hikari import voices
     from hikari.api import special_endpoints
@@ -497,6 +498,10 @@ async def send(
         components: undefined.UndefinedOr[typing.Sequence[special_endpoints.ComponentBuilder]] = undefined.UNDEFINED,
         embed: undefined.UndefinedOr[embeds_.Embed] = undefined.UNDEFINED,
         embeds: undefined.UndefinedOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
+        sticker: undefined.UndefinedOr[snowflakes.SnowflakeishOr[stickers_.PartialSticker]] = undefined.UNDEFINED,
+        stickers: undefined.UndefinedOr[
+            snowflakes.SnowflakeishSequence[stickers_.PartialSticker]
+        ] = undefined.UNDEFINED,
         tts: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
         reply: undefined.UndefinedOr[snowflakes.SnowflakeishOr[messages.PartialMessage]] = undefined.UNDEFINED,
         reply_must_exist: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
@@ -571,6 +576,15 @@ async def send(
             If provided, the message embed.
         embeds : hikari.undefined.UndefinedOr[typing.Sequence[hikari.embeds.Embed]]
             If provided, the message embeds.
+        sticker : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.stickers.PartialSticker]]
+            If provided, the object or ID of a sticker to send on the message.
+
+            As of writing, bots can only send custom stickers from the current guild.
+        stickers : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishSequence[hikari.stickers.PartialSticker]]
+            If provided, a sequence of the objects and IDs of up to 3 stickers
+            to send on the message.
+
+            As of writing, bots can only send custom stickers from the current guild.
         tts : hikari.undefined.UndefinedOr[bool]
             If provided, whether the message will be TTS (Text To Speech).
         reply : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.messages.PartialMessage]]
@@ -647,6 +661,8 @@ async def send(
             components=components,
             embed=embed,
             embeds=embeds,
+            sticker=sticker,
+            stickers=stickers,
             tts=tts,
             reply=reply,
             reply_must_exist=reply_must_exist,
diff --git a/hikari/impl/entity_factory.py b/hikari/impl/entity_factory.py
index ad952a1a..7d5b81bb 100644
--- a/hikari/impl/entity_factory.py
+++ b/hikari/impl/entity_factory.py
@@ -2759,14 +2759,22 @@ def deserialize_sticker_pack(self, payload: data_binding.JSONObject) -> sticker_
         for sticker_payload in payload["stickers"]:
             pack_stickers.append(self.deserialize_standard_sticker(sticker_payload))
 
+        cover_sticker_id: typing.Optional[snowflakes.Snowflake] = None
+        if raw_cover_sticker_id := payload.get("cover_sticker_id"):
+            cover_sticker_id = snowflakes.Snowflake(raw_cover_sticker_id)
+
+        banner_asset_id: typing.Optional[snowflakes.Snowflake] = None
+        if raw_banner_asset_id := payload.get("banner_asset_id"):
+            banner_asset_id = snowflakes.Snowflake(raw_banner_asset_id)
+
         return sticker_models.StickerPack(
             id=snowflakes.Snowflake(payload["id"]),
             name=payload["name"],
             description=payload["description"],
-            cover_sticker_id=snowflakes.Snowflake(payload["cover_sticker_id"]),
+            cover_sticker_id=cover_sticker_id,
             stickers=pack_stickers,
             sku_id=snowflakes.Snowflake(payload["sku_id"]),
-            banner_hash=payload["banner_asset_id"],
+            banner_asset_id=banner_asset_id,
         )
 
     def deserialize_partial_sticker(self, payload: data_binding.JSONObject) -> sticker_models.PartialSticker:
diff --git a/hikari/impl/rest.py b/hikari/impl/rest.py
index 9b819e50..2b6a98af 100644
--- a/hikari/impl/rest.py
+++ b/hikari/impl/rest.py
@@ -89,7 +89,7 @@
     from hikari import audit_logs
     from hikari import invites
     from hikari import sessions
-    from hikari import stickers
+    from hikari import stickers as stickers_
     from hikari import templates
     from hikari import voices
     from hikari import webhooks
@@ -1346,6 +1346,10 @@ def _build_message_payload(  # noqa: C901- Function too complex
         ] = undefined.UNDEFINED,
         embed: undefined.UndefinedNoneOr[embeds_.Embed] = undefined.UNDEFINED,
         embeds: undefined.UndefinedNoneOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
+        sticker: undefined.UndefinedOr[snowflakes.SnowflakeishOr[stickers_.PartialSticker]] = undefined.UNDEFINED,
+        stickers: undefined.UndefinedOr[
+            snowflakes.SnowflakeishSequence[stickers_.PartialSticker]
+        ] = undefined.UNDEFINED,
         flags: typing.Union[undefined.UndefinedType, int, messages_.MessageFlag] = undefined.UNDEFINED,
         tts: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
         mentions_everyone: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
@@ -1367,6 +1371,9 @@ def _build_message_payload(  # noqa: C901- Function too complex
         if not undefined.any_undefined(embed, embeds):
             raise ValueError("You may only specify one of 'embed' or 'embeds', not both")
 
+        if not undefined.any_undefined(sticker, stickers):
+            raise ValueError("You may only specify one of 'sticker' or 'stickers', not both")
+
         if undefined.all_undefined(embed, embeds) and isinstance(content, embeds_.Embed):
             # Syntactic sugar, common mistake to accidentally send an embed
             # as the content, so let's detect this and fix it for the user.
@@ -1426,6 +1433,7 @@ def _build_message_payload(  # noqa: C901- Function too complex
         body.put("flags", flags)
         body.put("embeds", serialized_embeds)
         body.put("components", serialized_components)
+        body.put_snowflake_array("sticker_ids", (sticker,) if sticker else stickers)
 
         if not edit or not undefined.all_undefined(mentions_everyone, mentions_reply, user_mentions, role_mentions):
             body.put(
@@ -1469,6 +1477,10 @@ async def create_message(
         components: undefined.UndefinedOr[typing.Sequence[special_endpoints.ComponentBuilder]] = undefined.UNDEFINED,
         embed: undefined.UndefinedOr[embeds_.Embed] = undefined.UNDEFINED,
         embeds: undefined.UndefinedOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
+        sticker: undefined.UndefinedOr[snowflakes.SnowflakeishOr[stickers_.PartialSticker]] = undefined.UNDEFINED,
+        stickers: undefined.UndefinedOr[
+            snowflakes.SnowflakeishSequence[stickers_.PartialSticker]
+        ] = undefined.UNDEFINED,
         tts: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
         reply: undefined.UndefinedOr[snowflakes.SnowflakeishOr[messages_.PartialMessage]] = undefined.UNDEFINED,
         reply_must_exist: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
@@ -1491,6 +1503,8 @@ async def create_message(
             components=components,
             embed=embed,
             embeds=embeds,
+            sticker=sticker,
+            stickers=stickers,
             tts=tts,
             mentions_everyone=mentions_everyone,
             mentions_reply=mentions_reply,
@@ -2380,7 +2394,7 @@ async def delete_emoji(
         route = routes.DELETE_GUILD_EMOJI.compile(guild=guild, emoji=emoji)
         await self._request(route, reason=reason)
 
-    async def fetch_available_sticker_packs(self) -> typing.Sequence[stickers.StickerPack]:
+    async def fetch_available_sticker_packs(self) -> typing.Sequence[stickers_.StickerPack]:
         route = routes.GET_STICKER_PACKS.compile()
         response = await self._request(route, auth=None)
         assert isinstance(response, dict)
@@ -2391,8 +2405,8 @@ async def fetch_available_sticker_packs(self) -> typing.Sequence[stickers.Sticke
 
     async def fetch_sticker(
         self,
-        sticker: snowflakes.SnowflakeishOr[stickers.PartialSticker],
-    ) -> typing.Union[stickers.StandardSticker, stickers.GuildSticker]:
+        sticker: snowflakes.SnowflakeishOr[stickers_.PartialSticker],
+    ) -> typing.Union[stickers_.StandardSticker, stickers_.GuildSticker]:
         route = routes.GET_STICKER.compile(sticker=sticker)
         response = await self._request(route)
         assert isinstance(response, dict)
@@ -2404,7 +2418,7 @@ async def fetch_sticker(
 
     async def fetch_guild_stickers(
         self, guild: snowflakes.SnowflakeishOr[guilds.PartialGuild]
-    ) -> typing.Sequence[stickers.GuildSticker]:
+    ) -> typing.Sequence[stickers_.GuildSticker]:
         route = routes.GET_GUILD_STICKERS.compile(guild=guild)
         response = await self._request(route)
         assert isinstance(response, list)
@@ -2415,8 +2429,8 @@ async def fetch_guild_stickers(
     async def fetch_guild_sticker(
         self,
         guild: snowflakes.SnowflakeishOr[guilds.PartialGuild],
-        sticker: snowflakes.SnowflakeishOr[stickers.PartialSticker],
-    ) -> stickers.GuildSticker:
+        sticker: snowflakes.SnowflakeishOr[stickers_.PartialSticker],
+    ) -> stickers_.GuildSticker:
         route = routes.GET_GUILD_STICKER.compile(guild=guild, sticker=sticker)
         response = await self._request(route)
         assert isinstance(response, dict)
@@ -2431,7 +2445,7 @@ async def create_sticker(
         *,
         description: undefined.UndefinedOr[str] = undefined.UNDEFINED,
         reason: undefined.UndefinedOr[str] = undefined.UNDEFINED,
-    ) -> stickers.GuildSticker:
+    ) -> stickers_.GuildSticker:
         route = routes.POST_GUILD_STICKERS.compile(guild=guild)
         form = data_binding.URLEncodedFormBuilder()
         form.add_field("name", name)
@@ -2446,13 +2460,13 @@ async def create_sticker(
     async def edit_sticker(
         self,
         guild: snowflakes.SnowflakeishOr[guilds.PartialGuild],
-        sticker: snowflakes.SnowflakeishOr[stickers.PartialSticker],
+        sticker: snowflakes.SnowflakeishOr[stickers_.PartialSticker],
         *,
         name: undefined.UndefinedOr[str] = undefined.UNDEFINED,
         description: undefined.UndefinedOr[str] = undefined.UNDEFINED,
         tag: undefined.UndefinedOr[str] = undefined.UNDEFINED,
         reason: undefined.UndefinedOr[str] = undefined.UNDEFINED,
-    ) -> stickers.GuildSticker:
+    ) -> stickers_.GuildSticker:
         route = routes.PATCH_GUILD_STICKER.compile(guild=guild, sticker=sticker)
         body = data_binding.JSONObjectBuilder()
         body.put("name", name)
@@ -2466,7 +2480,7 @@ async def edit_sticker(
     async def delete_sticker(
         self,
         guild: snowflakes.SnowflakeishOr[guilds.PartialGuild],
-        sticker: snowflakes.SnowflakeishOr[stickers.PartialSticker],
+        sticker: snowflakes.SnowflakeishOr[stickers_.PartialSticker],
         *,
         reason: undefined.UndefinedOr[str] = undefined.UNDEFINED,
     ) -> None:
@@ -2917,6 +2931,10 @@ async def create_forum_post(
         components: undefined.UndefinedOr[typing.Sequence[special_endpoints.ComponentBuilder]] = undefined.UNDEFINED,
         embed: undefined.UndefinedOr[embeds_.Embed] = undefined.UNDEFINED,
         embeds: undefined.UndefinedOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
+        sticker: undefined.UndefinedOr[snowflakes.SnowflakeishOr[stickers_.PartialSticker]] = undefined.UNDEFINED,
+        stickers: undefined.UndefinedOr[
+            snowflakes.SnowflakeishSequence[stickers_.PartialSticker]
+        ] = undefined.UNDEFINED,
         tts: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
         mentions_everyone: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
         mentions_reply: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
@@ -2956,6 +2974,8 @@ async def create_forum_post(
             components=components,
             embed=embed,
             embeds=embeds,
+            sticker=sticker,
+            stickers=stickers,
             tts=tts,
             mentions_everyone=mentions_everyone,
             mentions_reply=mentions_reply,
@@ -3948,8 +3968,9 @@ def interaction_autocomplete_builder(
         choices: typing.Union[
             typing.Sequence[commands.CommandChoice], typing.Sequence[special_endpoints.AutocompleteChoiceBuilder]
         ],
+        _stack_level: int = 0,
     ) -> special_endpoints.InteractionAutocompleteBuilder:
-        return special_endpoints_impl.InteractionAutocompleteBuilder(choices, _stack_level=1)
+        return special_endpoints_impl.InteractionAutocompleteBuilder(choices, _stack_level=_stack_level + 1)
 
     def interaction_message_builder(
         self, type_: typing.Union[base_interactions.ResponseType, int], /
@@ -4082,6 +4103,7 @@ async def create_autocomplete_response(
         choices: typing.Union[
             typing.Sequence[commands.CommandChoice], typing.Sequence[special_endpoints.AutocompleteChoiceBuilder]
         ],
+        _stack_level: int = 0,
     ) -> None:
         route = routes.POST_INTERACTION_RESPONSE.compile(interaction=interaction, token=token)
 
@@ -4099,6 +4121,7 @@ async def create_autocomplete_response(
                     removal_version="2.0.0.dev119",
                     additional_info="Use AutocompleteChoiceBuilder instead",
                     quote=False,
+                    stack_level=3 + _stack_level,
                 )
                 warned = True
 
diff --git a/hikari/interactions/command_interactions.py b/hikari/interactions/command_interactions.py
index eff6ce0f..5ceef418 100644
--- a/hikari/interactions/command_interactions.py
+++ b/hikari/interactions/command_interactions.py
@@ -383,7 +383,10 @@ class AutocompleteInteraction(BaseCommandInteraction):
     """Parameter values provided by the user invoking this command."""
 
     def build_response(
-        self, choices: typing.Sequence[commands.CommandChoice]
+        self,
+        choices: typing.Union[
+            typing.Sequence[commands.CommandChoice], typing.Sequence[special_endpoints.AutocompleteChoiceBuilder]
+        ],
     ) -> special_endpoints.InteractionAutocompleteBuilder:
         """Get a message response builder for use in the REST server flow.
 
@@ -392,6 +395,10 @@ def build_response(
             `AutocompleteInteraction.create_response` should be used to set
             the interaction response.
 
+        .. deprecated:: 2.0.0.dev118
+            Passing `hikari.commands.CommandChoice`s here instead of
+            `hikari.api.special_endpoints.AutocompleteChoiceBuilder`s.
+
         Examples
         --------
         .. code-block:: python
@@ -401,9 +408,9 @@ async def handle_autocomplete_interaction(interaction: AutocompleteInteraction)
                     interaction
                     .build_response(
                         [
-                            CommandChoice(name="foo", value="a"),
-                            CommandChoice(name="bar", value="b"),
-                            CommandChoice(name="baz", value="c"),
+                            AutocompleteChoiceBuilder(name="foo", value="a"),
+                            AutocompleteChoiceBuilder(name="bar", value="b"),
+                            AutocompleteChoiceBuilder(name="baz", value="c"),
                         ]
                     )
                 )
@@ -413,12 +420,18 @@ async def handle_autocomplete_interaction(interaction: AutocompleteInteraction)
         hikari.api.special_endpoints.InteractionAutocompleteBuilder
             Interaction autocomplete response builder object.
         """
-        return self.app.rest.interaction_autocomplete_builder(choices)
-
-    async def create_response(self, choices: typing.Sequence[commands.CommandChoice]) -> None:
-        """Create a response for this autocomplete interaction."""
-        await self.app.rest.create_autocomplete_response(
-            self.id,
-            self.token,
-            choices,
-        )
+        return self.app.rest.interaction_autocomplete_builder(choices, _stack_level=1)
+
+    async def create_response(
+        self,
+        choices: typing.Union[
+            typing.Sequence[commands.CommandChoice], typing.Sequence[special_endpoints.AutocompleteChoiceBuilder]
+        ],
+    ) -> None:
+        """Create a response for this autocomplete interaction.
+
+        .. deprecated:: 2.0.0.dev118
+            Passing `hikari.commands.CommandChoice`s here instead of
+            `hikari.api.special_endpoints.AutocompleteChoiceBuilder`s.
+        """
+        await self.app.rest.create_autocomplete_response(self.id, self.token, choices, _stack_level=1)
diff --git a/hikari/messages.py b/hikari/messages.py
index 02a9eef1..dec4bd9a 100644
--- a/hikari/messages.py
+++ b/hikari/messages.py
@@ -900,6 +900,10 @@ async def respond(
         components: undefined.UndefinedOr[typing.Sequence[special_endpoints.ComponentBuilder]] = undefined.UNDEFINED,
         embed: undefined.UndefinedOr[embeds_.Embed] = undefined.UNDEFINED,
         embeds: undefined.UndefinedOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
+        sticker: undefined.UndefinedOr[snowflakes.SnowflakeishOr[stickers_.PartialSticker]] = undefined.UNDEFINED,
+        stickers: undefined.UndefinedOr[
+            snowflakes.SnowflakeishSequence[stickers_.PartialSticker]
+        ] = undefined.UNDEFINED,
         tts: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
         reply: typing.Union[
             undefined.UndefinedType, snowflakes.SnowflakeishOr[PartialMessage], bool
@@ -976,6 +980,14 @@ async def respond(
             If provided, the message embed.
         embeds : hikari.undefined.UndefinedOr[typing.Sequence[hikari.embeds.Embed]]
             If provided, the message embeds.
+        sticker : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.stickers.PartialSticker]]
+            If provided, object or ID of a sticker to send on the message.
+
+            As of writing, bots can only send custom stickers from the current guild.
+        stickers : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishSequence[hikari.stickers.PartialSticker]]
+            If provided, object or ID of up to 3 stickers to send on the message.
+
+            As of writing, bots can only send custom stickers from the current guild.
         tts : hikari.undefined.UndefinedOr[bool]
             If provided, whether the message will be TTS (Text To Speech).
         reply : typing.Union[hikari.undefined.UndefinedType, hikari.snowflakes.SnowflakeishOr[hikari.messages.PartialMessage], bool]
@@ -1058,6 +1070,8 @@ async def respond(
             components=components,
             embed=embed,
             embeds=embeds,
+            sticker=sticker,
+            stickers=stickers,
             tts=tts,
             reply=reply,
             reply_must_exist=reply_must_exist,
diff --git a/hikari/stickers.py b/hikari/stickers.py
index e41dd6b9..34c1bd58 100644
--- a/hikari/stickers.py
+++ b/hikari/stickers.py
@@ -107,17 +107,16 @@ class StickerPack(snowflakes.Unique):
     sku_id: snowflakes.Snowflake = attr.field(eq=False, hash=False, repr=False)
     """The ID of the packs SKU."""
 
-    # This is not exactly how Discord documents it, but we need to keep consistency
-    banner_hash: str = attr.field(eq=False, hash=False, repr=False)
-    """The hash for the pack's banner."""
+    banner_asset_id: typing.Optional[snowflakes.Snowflake] = attr.field(eq=False, hash=False, repr=False)
+    """ID of the sticker pack's banner image, if set."""
 
     @property
-    def banner_url(self) -> files.URL:
-        """Banner URL for the pack."""
+    def banner_url(self) -> typing.Optional[files.URL]:
+        """Banner URL for the pack, if set."""
         return self.make_banner_url()
 
-    def make_banner_url(self, *, ext: str = "png", size: int = 4096) -> files.URL:
-        """Generate the pack's banner image URL.
+    def make_banner_url(self, *, ext: str = "png", size: int = 4096) -> typing.Optional[files.URL]:
+        """Generate the pack's banner image URL, if set.
 
         Parameters
         ----------
@@ -130,17 +129,20 @@ def make_banner_url(self, *, ext: str = "png", size: int = 4096) -> files.URL:
 
         Returns
         -------
-        hikari.files.URL
-            The URL of the banner.
+        typing.Optional[hikari.files.URL]
+            The URL of the banner, if set.
 
         Raises
         ------
         ValueError
             If `size` is not a power of two or not between 16 and 4096.
         """
-        return routes.CDN_STICKER_PACK_BANNER.compile_to_file(
-            urls.CDN_URL, hash=self.banner_hash, file_format=ext, size=size
-        )
+        if self.banner_asset_id is not None:
+            return routes.CDN_STICKER_PACK_BANNER.compile_to_file(
+                urls.CDN_URL, hash=self.banner_asset_id, file_format=ext, size=size
+            )
+
+        return None
 
 
 @attr_extensions.with_copy


Test patch:
diff --git a/tests/hikari/impl/test_entity_factory.py b/tests/hikari/impl/test_entity_factory.py
index 5cd96387..74b23183 100644
--- a/tests/hikari/impl/test_entity_factory.py
+++ b/tests/hikari/impl/test_entity_factory.py
@@ -5051,7 +5051,7 @@ def sticker_pack_payload(self, standard_sticker_payload):
             "cover_sticker_id": "456",
             "stickers": [standard_sticker_payload],
             "sku_id": "789",
-            "banner_asset_id": "hash123",
+            "banner_asset_id": "342123321",
         }
 
     def test_deserialize_partial_sticker(self, entity_factory_impl, partial_sticker_payload):
@@ -5099,7 +5099,7 @@ def test_deserialize_sticker_pack(self, entity_factory_impl, sticker_pack_payloa
         assert pack.description == "My sticker pack description"
         assert pack.cover_sticker_id == 456
         assert pack.sku_id == 789
-        assert pack.banner_hash == "hash123"
+        assert pack.banner_asset_id == 342123321
 
         assert len(pack.stickers) == 1
         sticker = pack.stickers[0]
@@ -5111,6 +5111,15 @@ def test_deserialize_sticker_pack(self, entity_factory_impl, sticker_pack_payloa
         assert sticker.sort_value == 96
         assert sticker.tags == ["thinking", "thonkang"]
 
+    def test_deserialize_sticker_pack_with_optional_fields(self, entity_factory_impl, sticker_pack_payload):
+        del sticker_pack_payload["cover_sticker_id"]
+        del sticker_pack_payload["banner_asset_id"]
+
+        pack = entity_factory_impl.deserialize_sticker_pack(sticker_pack_payload)
+
+        assert pack.cover_sticker_id is None
+        assert pack.banner_asset_id is None
+
     def test_stickers(self, entity_factory_impl, guild_sticker_payload):
         guild_definition = entity_factory_impl.deserialize_gateway_guild(
             {"id": "265828729970753537", "stickers": [guild_sticker_payload]}, user_id=123321
diff --git a/tests/hikari/impl/test_rest.py b/tests/hikari/impl/test_rest.py
index b3a027a4..2e3be917 100644
--- a/tests/hikari/impl/test_rest.py
+++ b/tests/hikari/impl/test_rest.py
@@ -1305,6 +1305,7 @@ def test__build_message_payload_with_singular_args(self, rest_client):
                 attachment=attachment,
                 component=component,
                 embed=embed,
+                sticker=StubModel(5412123),
                 flags=120,
                 tts=True,
                 mentions_everyone=mentions_everyone,
@@ -1318,6 +1319,7 @@ def test__build_message_payload_with_singular_args(self, rest_client):
             "content": "987654321",
             "tts": True,
             "flags": 120,
+            "sticker_ids": ["5412123"],
             "embeds": [{"embed": 1}],
             "components": [{"component": 1}],
             "attachments": [{"id": 0, "filename": "attachment.png"}, {"id": 1, "filename": "attachment2.png"}],
@@ -1399,6 +1401,7 @@ def test__build_message_payload_with_plural_args(self, rest_client):
                 attachments=[attachment1, attachment2],
                 components=[component1, component2],
                 embeds=[embed1, embed2],
+                stickers=[54612123, StubModel(123321)],
                 flags=120,
                 tts=True,
                 mentions_everyone=mentions_everyone,
@@ -1414,6 +1417,7 @@ def test__build_message_payload_with_plural_args(self, rest_client):
             "flags": 120,
             "embeds": [{"embed": 1}, {"embed": 2}],
             "components": [{"component": 1}, {"component": 2}],
+            "sticker_ids": ["54612123", "123321"],
             "attachments": [
                 {"id": 0, "filename": "attachment.png"},
                 {"id": 1, "filename": "attachment2.png"},
@@ -1564,7 +1568,7 @@ def test__build_message_payload_with_edit_and_attachment_object_passed(self, res
 
     @pytest.mark.parametrize(
         ("singular_arg", "plural_arg"),
-        [("attachment", "attachments"), ("component", "components"), ("embed", "embeds")],
+        [("attachment", "attachments"), ("component", "components"), ("embed", "embeds"), ("sticker", "stickers")],
     )
     def test__build_message_payload_when_both_single_and_plural_args_passed(
         self, rest_client, singular_arg, plural_arg
@@ -2480,6 +2484,8 @@ async def test_create_message_when_form(self, rest_client):
             components=[component_obj2],
             embed=embed_obj,
             embeds=[embed_obj2],
+            sticker=54234,
+            stickers=[564123, 431123],
             tts=True,
             mentions_everyone=False,
             user_mentions=[9876],
@@ -2498,6 +2504,8 @@ async def test_create_message_when_form(self, rest_client):
             components=[component_obj2],
             embed=embed_obj,
             embeds=[embed_obj2],
+            sticker=54234,
+            stickers=[564123, 431123],
             tts=True,
             mentions_everyone=False,
             mentions_reply=undefined.UNDEFINED,
@@ -2535,6 +2543,8 @@ async def test_create_message_when_no_form(self, rest_client):
             components=[component_obj2],
             embed=embed_obj,
             embeds=[embed_obj2],
+            sticker=543345,
+            stickers=[123321, 6572345],
             tts=True,
             mentions_everyone=False,
             user_mentions=[9876],
@@ -2553,6 +2563,8 @@ async def test_create_message_when_no_form(self, rest_client):
             components=[component_obj2],
             embed=embed_obj,
             embeds=[embed_obj2],
+            sticker=543345,
+            stickers=[123321, 6572345],
             tts=True,
             mentions_everyone=False,
             mentions_reply=undefined.UNDEFINED,
@@ -4625,6 +4637,8 @@ async def test_create_forum_post_when_no_form(
             components=[component_obj2],
             embed=embed_obj,
             embeds=[embed_obj2],
+            sticker=132543,
+            stickers=[654234, 123321],
             tts=True,
             mentions_everyone=False,
             user_mentions=[9876],
@@ -4644,6 +4658,8 @@ async def test_create_forum_post_when_no_form(
             components=[component_obj2],
             embed=embed_obj,
             embeds=[embed_obj2],
+            sticker=132543,
+            stickers=[654234, 123321],
             tts=True,
             mentions_everyone=False,
             mentions_reply=undefined.UNDEFINED,
@@ -4691,6 +4707,8 @@ async def test_create_forum_post_when_form(
             components=[component_obj2],
             embed=embed_obj,
             embeds=[embed_obj2],
+            sticker=314542,
+            stickers=[56234, 123312],
             tts=True,
             mentions_everyone=False,
             user_mentions=[9876],
@@ -4710,6 +4728,8 @@ async def test_create_forum_post_when_form(
             components=[component_obj2],
             embed=embed_obj,
             embeds=[embed_obj2],
+            sticker=314542,
+            stickers=[56234, 123312],
             tts=True,
             mentions_everyone=False,
             mentions_reply=undefined.UNDEFINED,
diff --git a/tests/hikari/interactions/test_command_interactions.py b/tests/hikari/interactions/test_command_interactions.py
index fa7d975d..523c218a 100644
--- a/tests/hikari/interactions/test_command_interactions.py
+++ b/tests/hikari/interactions/test_command_interactions.py
@@ -23,9 +23,9 @@
 import pytest
 
 from hikari import channels
-from hikari import commands
 from hikari import snowflakes
 from hikari import traits
+from hikari.impl import special_endpoints
 from hikari.interactions import base_interactions
 from hikari.interactions import command_interactions
 
@@ -124,14 +124,17 @@ def mock_autocomplete_interaction(self, mock_app):
 
     @pytest.fixture()
     def mock_command_choices(self):
-        return [commands.CommandChoice(name="a", value="b"), commands.CommandChoice(name="foo", value="bar")]
+        return [
+            special_endpoints.AutocompleteChoiceBuilder(name="a", value="b"),
+            special_endpoints.AutocompleteChoiceBuilder(name="foo", value="bar"),
+        ]
 
     def test_build_response(self, mock_autocomplete_interaction, mock_app, mock_command_choices):
         mock_app.rest.interaction_autocomplete_builder = mock.Mock()
         builder = mock_autocomplete_interaction.build_response(mock_command_choices)
 
         assert builder is mock_app.rest.interaction_autocomplete_builder.return_value
-        mock_app.rest.interaction_autocomplete_builder.assert_called_once_with(mock_command_choices)
+        mock_app.rest.interaction_autocomplete_builder.assert_called_once_with(mock_command_choices, _stack_level=1)
 
     @pytest.mark.asyncio()
     async def test_create_response(
@@ -143,7 +146,5 @@ async def test_create_response(
         await mock_autocomplete_interaction.create_response(mock_command_choices)
 
         mock_app.rest.create_autocomplete_response.assert_awaited_once_with(
-            2312312,
-            "httptptptptptptptp",
-            mock_command_choices,
+            2312312, "httptptptptptptptp", mock_command_choices, _stack_level=1
         )
diff --git a/tests/hikari/test_channels.py b/tests/hikari/test_channels.py
index 084f81d9..2e871018 100644
--- a/tests/hikari/test_channels.py
+++ b/tests/hikari/test_channels.py
@@ -281,6 +281,8 @@ async def test_send(self, model):
             components=mock_components,
             embed=mock_embed,
             embeds=mock_embeds,
+            sticker=543,
+            stickers=[132, 65423],
             reply=mock_reply,
             reply_must_exist=False,
             mentions_everyone=False,
@@ -300,6 +302,8 @@ async def test_send(self, model):
             components=mock_components,
             embed=mock_embed,
             embeds=mock_embeds,
+            sticker=543,
+            stickers=[132, 65423],
             reply=mock_reply,
             reply_must_exist=False,
             mentions_everyone=False,
diff --git a/tests/hikari/test_messages.py b/tests/hikari/test_messages.py
index 6fab19e3..ee03a805 100644
--- a/tests/hikari/test_messages.py
+++ b/tests/hikari/test_messages.py
@@ -205,6 +205,8 @@ async def test_respond(self, message):
             attachments=attachments,
             component=component,
             components=components,
+            sticker=123,
+            stickers=[543, 6542],
             tts=True,
             reply=reference_messsage,
             reply_must_exist=False,
@@ -223,6 +225,8 @@ async def test_respond(self, message):
             attachments=attachments,
             component=component,
             components=components,
+            sticker=123,
+            stickers=[543, 6542],
             tts=True,
             reply=reference_messsage,
             reply_must_exist=False,
@@ -247,6 +251,8 @@ async def test_respond_when_reply_is_True(self, message):
             attachments=undefined.UNDEFINED,
             component=undefined.UNDEFINED,
             components=undefined.UNDEFINED,
+            sticker=undefined.UNDEFINED,
+            stickers=undefined.UNDEFINED,
             tts=undefined.UNDEFINED,
             reply=message,
             reply_must_exist=undefined.UNDEFINED,
@@ -271,6 +277,8 @@ async def test_respond_when_reply_is_False(self, message):
             attachments=undefined.UNDEFINED,
             component=undefined.UNDEFINED,
             components=undefined.UNDEFINED,
+            sticker=undefined.UNDEFINED,
+            stickers=undefined.UNDEFINED,
             tts=undefined.UNDEFINED,
             reply=undefined.UNDEFINED,
             reply_must_exist=undefined.UNDEFINED,
diff --git a/tests/hikari/test_stickers.py b/tests/hikari/test_stickers.py
index 9c52fed5..0bb4238e 100644
--- a/tests/hikari/test_stickers.py
+++ b/tests/hikari/test_stickers.py
@@ -22,6 +22,7 @@
 import mock
 import pytest
 
+from hikari import snowflakes
 from hikari import stickers
 from hikari import urls
 from hikari.internal import routes
@@ -34,10 +35,10 @@ def model(self):
             id=123,
             name="testing",
             description="testing description",
-            cover_sticker_id=None,
+            cover_sticker_id=snowflakes.Snowflake(6541234),
             stickers=[],
             sku_id=123,
-            banner_hash="abc123",
+            banner_asset_id=snowflakes.Snowflake(541231),
         )
 
     def test_banner_url(self, model):
@@ -54,11 +55,16 @@ def test_make_banner_url(self, model):
 
         route.compile_to_file.assert_called_once_with(
             urls.CDN_URL,
-            hash="abc123",
+            hash=541231,
             size=512,
             file_format="url",
         )
 
+    def test_make_banner_url_when_no_banner_asset(self, model):
+        model.banner_asset_id = None
+
+        assert model.make_banner_url(ext="url", size=512) is None
+
 
 class TestPartialSticker:
     @pytest.fixture()