Write bots for Discord in Haskell https://github.com/aquarial/discord-haskell

Latest on Hackage:0.8.2

This package is not currently in any snapshots. If you're interested in using it, we recommend adding it to Stackage Nightly. Doing so will make builds more reliable, and allow stackage.org to host generated Haddocks.

MIT licensed by Karl
Maintained by ksfish5@gmail.com

discord-haskell Build Status

Please refer to Getting Started and Notes when relevant. A few minutes of reading can save you hours of debugging.

Recent change: master branch has the potentially broken, most recent commits, stable has the most recent working version. Pull requests are automatically made against master and it’s nice to merge pull requests to test them.

Getting Started

1 Create an application at the Developer Portal: https://discordapp.com/developers/applications.

2 Add a ‘Bot User’ using the settings pane on the left. Take note of CLIENT ID on this page.

3 Use the BOT PERMISSIONS tab to compute a Permissions Int (this does not immediately affect anything, hold onto this number)

3 Invite the bot to a server filling in the <> information. Client ID and Permissions come from previous steps. https://discordapp.com/oauth2/authorize?client_id=<CLIENT_ID>&scope=bot&permissions=<PERMISSIONS>

4 Connect to the gateway once in order to send CreateMessage events. This is a Discord requirement.

5 Look at the examples. examples/gateway.hs, examples/rest.hs, examples/cache.hs, and examples/ping-pong.hs

6 Understand what’s available to the bot. Rest API calls can modify Channels, Emoji, Guilds, etc. Most endpoints are covered with very similar names. List Guild Emojis becomes ListGuildEmojis. You can use :info in ghci on type constructors to explore the ADTs.

Gateway Events provide the other source of info, using nextEvent and sendCommand. Use :info to explore Event and GatewaySendable ADTs.

7 Add this library to your dependencies. discord-haskell is on hackage with strict version bounds to stackage lts-12.10. You can also use the github repo.

# in stack.yaml (if using stack)
resolver: lts-12.10
- git: git@github.com:aquarial/discord-haskell.git
  commit: <most recent stable commit>
  extra-dep: true

# in project.cabal
  build-depends:       base
                     , discord-haskell


loginRest allows restCall. loginRestGateway allows restCall, nextEvent, sendCommand, and readCache. Use loginRest if you don’t need the gateway.

Use Control.Exception.finally with stopDiscord to safely kill background threads when running examples in ghci (otherwise exit ghci and reopen to kill threads).

The examples will work on the stable branch. The master branch has the most recent (potentially) breaking changes.

To get the format to use for Emoji, type \:emoji: into a discord chat. You should copy-paste that into the request. This can be a bit finicky. The equivalent of :thumbsup::skin-tone-3: is "👍\127997" for example, and a custom emoji will look like <name:id_number> or name:id_number.


This library was originally forked from discord.hs. After rewriting the gateway/rest loops and extending the types I think it makes more sense to present this library as separate from the source. The APIs are not compatible.


In roughly the order I’m working on them:

  • Finish REST request ADT. Search for -- todo pattern
  • Add data types for permissions and presences
  • Update channel types (fill out guildcategory)
  • Modify cache with Events
  • Add gateway ToJSON for events
  • Update comments on ADT types



View on github for newest version: https://github.com/aquarial/discord-haskell/blob/master/changelog.md



Hardcode CreateReaction delay so bots can add reactions 4 times faster

MP2E Fixed parse error on GuildBanAdd + GuildBanRevoke: user_object instead the whole object


MP2E Fixed parse error on GuildRoleDelete: role_id instead of role


MessageUpdate does not contain a full Message object, just ChannelId MessageId

Message Author changed from User to Either WebhookId User

Add Webhook ADT

Add requests: GetInvite, DeleteInvite

UpdateStatusVoiceOpts takes Bool for Mute

Unavailable becomes GuildUnavailable


t1m0thyj Typo in RequestGuildMemberOpts fields fixed.

t1m0thyj Added Activity, ActivityType ADT

UpdateStatusTypes became UpdateStatusType (singular ADT)

t1m0thyj Retry connection on 1001 websocket close


Snowflake -> named id

Add requests: ModifyChanPositions, CreateGuildChannel

Changed constructors of Channel to have prefix “Channel”, isGuildChannel –> channelIsInGuild

Change Emoji Id ADTs


Add requests: CreateGuildEmoji, GroupDMRemoveRecipient, ModifyCurrentUser, EditChannelPermissions, CreateChannelInvite, GroupDMAddRecipient, ModifyGuild

restCall, readCache pass errors as an ADT, including underling http exceptions

Only add “Bot “ prefix to secret token if it’s not there


sendCommand with GatewaySendable types


restCall with Request types

nextEvent with Event types

comments powered byDisqus