# hikari gives Python bots two ways to talk to Discord

> hikari is a statically typed Discord API wrapper for Python 3 and asyncio that ships two separate bot implementations, a GatewayBot that receives events over the gateway and a RESTBot that only handles interactions through an HTTP interaction server. The split is the interesting design decision, and it lets an application take only the half of Discord it actually needs.

**hikari-py/hikari** — A Discord API wrapper for Python and asyncio built on good intentions.

- Repository: https://github.com/hikari-py/hikari
- Website: https://docs.hikari-py.dev/en/stable
- Stars: 919 · Forks: 111
- Language: Python
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/hikari-py-hikari

## Two implementations, not one configurable client

Most Discord libraries give you one client with switches. hikari splits the job in two, and the README is explicit that it provides two different default bot implementations to suit your needs.
A GatewayBot connects to Discord through the gateway and receives events through there. It is the classic model: a persistent websocket connection, a stream of events, and listeners registered against them.
A RESTBot is the opposite. It spawns an interaction server to which Discord will only send interaction events, which can be handled and responded to. There is no gateway connection, no presence, no message events. Instead you expose an HTTP endpoint, and Discord posts interactions to it.
The practical effect is that a slash command bot does not need a websocket at all. The trade is that a RESTBot is an HTTP server, which means it needs a public key for signature verification and something in front of it that terminates TLS, and it competes with your other web endpoints for capacity.
The library describes itself as an opinionated, static typed Discord microframework for Python3 and asyncio that supports Discord's v10 REST and Gateway APIs. The v10 constraint is the one that will decide whether the library fits you, because it is not a compatibility layer for older Discord API versions.

## Listeners are selected by type annotation

The GatewayBot example is short enough to read in one go.
```python
import hikari

bot = hikari.GatewayBot(token="...")

@bot.listen()
async def ping(event: hikari.GuildMessageCreateEvent) -> None:
    """If a non-bot user mentions your bot, respond with 'Pong!'."""

    # Do not respond to bots nor webhooks pinging us, only user accounts
    if not event.is_human:
        return

    me = bot.get_me()

    if me.id in event.message.user_mentions_ids:
        await event.message.respond("Pong!")

bot.run()
```
The dispatch mechanism is the type annotation on the event parameter. The README states that events are determined by the type annotation, or alternatively as a type passed to the @bot.listen() decorator if you do not want to use type hints.
```python
@bot.listen(hikari.MessageCreateEvent)
async def ping(event):
    ...
```
That is a small design choice with a large effect on how a codebase reads. The event type is the registration key, so moving a listener to a different event is a change of one annotation, and a reader can see exactly which events a function handles without tracing a dispatch table.
Which event class you choose also changes the scope. The README notes that the guild message example will only respond to messages created in guilds, and that you can use DMMessageCreateEvent instead to only listen on DMs, or MessageCreateEvent to listen to both.
The bot.user check is not incidental. The is_human property excludes bots and webhooks, so your bot does not answer other bots.
The last line, bot.run(), is the entry point. hikari manages the event loop itself, so there is no asyncio.run to write.

## Intents decide which events arrive at all

A GatewayBot only receives the events it has asked for, and hikari makes that a constructor argument.
```python
import hikari

# the default is to enable all unprivileged intents (all events that do not target the
# presence, activity of a specific member nor message content).
bot = hikari.GatewayBot(intents=hikari.Intents.ALL, token="...")
```
The default enables all unprivileged intents, which the comment defines precisely: all events that do not target the presence or activity of a specific member, nor message content.
Passing hikari.Intents.ALL enables all of them, including member presence events, and the README is careful to add the operational consequence: you would need to whitelist your application first to be able to start the bot if you do this. Privileged intents on Discord are gated by the application configuration in the developer portal, so a bot that asks for everything may simply refuse to connect.
That ordering matters for a new project. A bot that starts and works is a better first milestone than a bot that requests every event and fails to connect because a portal setting is missing.
The intents are also the place where a bot that seems quiet gets explained. A bot that does not receive message content events will never see the messages it is supposed to read, and no amount of listener code changes that.

## Slash commands over an interaction server

The RESTBot side of the library is built around interactions, and the README example shows the shape of a command handler.
```python
import asyncio

import hikari


# This function will handle the interactions received
async def handle_command(interaction: hikari.CommandInteraction):
    # Create an initial response to be able to take longer to respond
    yield interaction.build_deferred_response()

    await asyncio.sleep(5)

    # Edit the initial response
    await interaction.edit_initial_response("Edit after 5 seconds!")
```
Two things stand out. The handler is a generator that yields a deferred response first, which tells Discord to acknowledge the interaction immediately so the command has time to do its work, and then it edits that initial response once the work is finished. That is the pattern Discord requires for anything that takes longer than the interaction window, and hikari models it as a yield rather than as a callback.
The second thing is that registering commands is separate from handling them. The example calls fetch_application to get the application, then set_application_commands with a list built by slash_command_builder.
```python
await bot.rest.set_application_commands(
    application=application.id,
    commands=[
        bot.rest.slash_command_builder("test", "My first test command!"),
    ],
)
```
The README itself warns about the naive version of that snippet, calling it not a nice way to manage this because it is quite spammy to do every time the bot is started. It suggests using a command handler, or running the code only in a script using RESTApp, or adding checks so the commands are only updated when something changed.
That is an honest piece of advice from the maintainers, and it tells you the library gives you the primitives rather than a policy for using them.

## Installing from PyPI and the Python version window

Installation is a single pip command.
```bash
python -m pip install -U hikari
# Windows users may need to run this instead...
py -3 -m pip install -U hikari
```
The version support is narrow and stated. The README says Python 3.11, 3.12, 3.13, 3.14 and 3.15 are currently supported, and the pyproject.toml agrees, with requires-python set to >=3.11.0,<3.16.
That upper bound is worth noticing. It means the project follows Python releases closely rather than supporting a wide range, so a deployment pinned to an older interpreter is out of scope, and each new Python release is something the project has to add.
The runtime dependencies are four and all of them are mainstream: aiohttp for HTTP, attrs for the model classes, colorlog for coloured logging, and multidict for the multi-key dictionaries that Discord's payloads need.
The build backend is hatchling with a requirement of hatchling>=1.14, and the version is read out of hikari/_about.py with a pattern that matches a typing.Final string annotation. The package also installs a console script named hikari, which maps to hikari.cli:main, so there is a command line entry point in the distribution.
The pyproject.toml carries an MIT licence text with the standard permission notice, and the authors are Nekokatt and davfsa, with davfsa as the maintainer.

## The tooling is part of the argument

A static typed library is only as useful as the type checking behind it, and the repository is set up for that.
The README badges list mypy checked and ruff, and the top level entries include a ruff.toml, a pyproject.toml, a mkdocs.yml for the documentation build, a noxfile.py for the task automation, a pipelines/ directory, a scripts/ directory, and a uv.lock. The CI workflow badge and the codecov badge are both in the README header, along with a documentation status badge pointing at the readthedocs project.
The examples directory shows the range of things the library supports. There is hello_world.py, oauth.py, slash.py, image_resources.py, a voice_message/ directory, and its own LICENSE file, which suggests the examples are treated as separate, licensed artefacts rather than loose snippets.
The repository also carries CHANGELOG.md, a changes/ directory for the change fragments, CODE_OF_CONDUCT.md, CONTRIBUTING.md and SECURITY.md.
On scale, the README lists bots running on hikari in the wild, with Invite Tracker, nMarkov, General Purpose ORG Bot, Scoreboarder and Suggestions Bot named. It invites you to contact the maintainer on the Discord server or open a pull request to add yours.
The honesty is worth noting. The project describes itself as built on good intentions and the hope that it will be extendable and reusable, rather than an obstacle for future development, which is a modest claim for a library that has been in use for years.

## MIT licensed, regular releases, and the constraint to check first

The licence is MIT, with the text in the pyproject.toml and a LICENSE file at the root of the tree. That is permissive and carries no obligation beyond keeping the notice.
The activity is steady. The last push was on 2026-10-22 and the repository is not archived. The recent releases are 2.6.0 on 2026-08-19, 2.5.0 on 2025-10-31 and 2.4.1 on 2025-09-08, which is roughly one or two releases a year for a mature project rather than a churn of patch releases.
The constraint to check before you adopt it is the Discord API version. The library supports the v10 REST and Gateway APIs. If you are building something new today, that is the current generation and you are fine. If you are maintaining an older bot, or you depend on an API behaviour from an earlier Discord version, hikari will not give it to you.
The second constraint is architectural, and it is the one that surprises people. A RESTBot needs an HTTP server that Discord can reach, with a public key so it can verify request signatures, and in most deployments something in front of it for TLS. If you expected a bot to be a single background process with no inbound traffic, the gateway model is the one to choose.

## Conclusion

Adopt hikari when you want a Discord bot in Python with strict typing, a modern asyncio API and a choice between gateway events and HTTP interactions without writing either client yourself. Do not adopt it if you need Discord API versions other than v10, since the library targets the v10 REST and Gateway APIs specifically. Before shipping, confirm your Python version falls inside the supported window, since the project requires Python 3.11 or later and caps the upper bound below 3.16.

## FAQ

### How do I install hikari?

Run python -m pip install -U hikari. The README notes that Windows users may need to run py -3 -m pip install -U hikari instead.

### What is the difference between a GatewayBot and a RESTBot in hikari?

A GatewayBot connects to Discord through the gateway and receives events through there. A RESTBot spawns an interaction server to which Discord will only send interaction events, which can be handled and responded to, so it needs no gateway connection.

### Which Python versions does hikari support?

The README states that Python 3.11, 3.12, 3.13, 3.14 and 3.15 are currently supported, and the pyproject.toml sets requires-python to >=3.11.0,<3.16.

### How do I choose which events my hikari bot listens to?

Listeners are registered by event type, either through the type annotation on the event parameter or by passing the event type to the @bot.listen() decorator. Which events arrive at all is controlled by the intents passed to the GatewayBot constructor, which defaults to all unprivileged intents.

### How does hikari handle slash commands that take a long time?

The example handler yields interaction.build_deferred_response() to acknowledge the interaction immediately, then edits that initial response once the work is done, for example with interaction.edit_initial_response.

## Sources

- [hikari-py/hikari on GitHub](https://github.com/hikari-py/hikari)
- [License: MIT](https://github.com/hikari-py/hikari/blob/master/LICENSE)
- [Project website](https://docs.hikari-py.dev/en/stable)
- [README](https://github.com/hikari-py/hikari/blob/master/README.md)
- [Releases](https://github.com/hikari-py/hikari/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/hikari-py-hikari
