|
1 | 1 | # kickcom.py |
2 | 2 |
|
3 | 3 | [](https://pypi.org/project/kickcom.py) |
| 4 | +[](https://predaaa.github.io/kickcom.py) |
4 | 5 |
|
5 | 6 | Async library for Kick.com API and webhooks |
6 | 7 |
|
7 | | -> [!NOTE] |
8 | | -> This is in alpha stage, it currently only supports app access tokens. PRs to improve are very welcome! |
9 | | -
|
10 | | -Find the kick.com [API documentation here](https://docs.kick.com/) |
| 8 | +[Documentation](https://predaaa.github.io/kickcom.py) | [Kick API Reference](https://docs.kick.com/) |
11 | 9 |
|
12 | 10 | ## Installation |
13 | 11 |
|
14 | 12 | ```bash |
15 | 13 | pip install kickcom.py |
16 | 14 | ``` |
17 | 15 |
|
18 | | -## Client |
| 16 | +Optional speed extras: |
| 17 | + |
| 18 | +```bash |
| 19 | +pip install kickcom.py[speed] |
| 20 | +``` |
19 | 21 |
|
20 | | -All endpoints available for app access tokens are available. |
| 22 | +## Quick Start |
| 23 | + |
| 24 | +### App Access Token (Bot / Server-side) |
21 | 25 |
|
22 | 26 | ```python |
23 | | -from kickpy.client import Client |
| 27 | +import asyncio |
| 28 | +from kickpy import KickClient |
| 29 | + |
| 30 | +async def main(): |
| 31 | + client = KickClient("KICK_CLIENT_ID", "KICK_CLIENT_SECRET") |
24 | 32 |
|
25 | | -kick_client = Client("KICK_CLIENT_ID", "KICK_CLIENT_SECRET") |
| 33 | + user = await client.fetch_user(4377088) |
| 34 | + print(user.name) |
26 | 35 |
|
27 | | -user = await kick_client.fetch_user(4377088) |
28 | | -# Returns: |
29 | | -# User(user_id=4377088, name='KickBot', email='', profile_picture='https://files.kick.com/images/user/4377088/profile_image/conversion/8dde6c21-7008-43d1-b6ac-7d9c34b7d9cc-fullsize.webp') |
| 36 | + channel = await client.fetch_channel(slug="kickbot") |
| 37 | + print(channel.stream_title) |
30 | 38 |
|
31 | | -channel = await kick_client.fetch_channel(4377088) |
32 | | -# Returns: |
33 | | -# Channel(broadcaster_user_id=4377088, slug='kickbot', channel_description='Official bot of https://kickbot.app, the #1 tool for Kick streamers. | VOD Downloader | !clip command | Custom Commands | Timed Messages | Customizable overlays | Stream Deck Plugin |\n\nContact: contact@kickbot.app', banner_picture='https://files.kick.com/images/channel/4295080/banner_image/b0d66fa3-3a4e-45d5-94ea-84d0590990d7', stream=Stream(url='', key='', is_live=False, is_mature=False, language='', start_time='0001-01-01T00:00:00Z', viewer_count=0), stream_title='', category=Category(id=0, name='', thumbnail='')) |
| 39 | + await client.close() |
| 40 | + |
| 41 | +asyncio.run(main()) |
34 | 42 | ``` |
35 | 43 |
|
36 | | -## Webhook server |
| 44 | +### User Access Token (OAuth 2.1 + PKCE) |
| 45 | + |
| 46 | +Some endpoints require a user token. The library handles the full OAuth flow with a built-in local callback server: |
| 47 | + |
| 48 | +```python |
| 49 | +import asyncio |
| 50 | +from kickpy import KickClient, Scope |
| 51 | + |
| 52 | +async def main(): |
| 53 | + client = KickClient("KICK_CLIENT_ID", "KICK_CLIENT_SECRET") |
| 54 | + |
| 55 | + # Opens browser, captures callback on localhost, exchanges code for tokens |
| 56 | + await client.authenticate( |
| 57 | + scopes=[Scope.CHAT_WRITE, Scope.MODERATION_BAN], |
| 58 | + port=3000, # redirect URI must be http://127.0.0.1:3000/callback in your Kick app settings |
| 59 | + ) |
| 60 | + |
| 61 | + # User token endpoints are now available |
| 62 | + await client.send_chat_message("Hello from kickcom.py!", broadcaster_user_id=4377088) |
37 | 63 |
|
38 | | -Support for receiving webhooks events from Kick is also available. |
| 64 | + await client.close() |
| 65 | + |
| 66 | +asyncio.run(main()) |
| 67 | +``` |
| 68 | + |
| 69 | +If you handle OAuth externally, you can inject tokens directly: |
39 | 70 |
|
40 | 71 | ```python |
41 | | -from kickpy.client import Client |
| 72 | +client.set_user_token( |
| 73 | + access_token="...", |
| 74 | + refresh_token="...", |
| 75 | + expires_in=3600, |
| 76 | + scope="chat:write moderation:ban", |
| 77 | +) |
| 78 | +``` |
| 79 | + |
| 80 | +## API Reference |
| 81 | + |
| 82 | +### Users |
| 83 | + |
| 84 | +| Method | Description | Token | |
| 85 | +|--------|-------------|-------| |
| 86 | +| `fetch_user(user_id)` | Get a user by ID | App | |
| 87 | + |
| 88 | +### Channels |
| 89 | + |
| 90 | +| Method | Description | Token | |
| 91 | +|--------|-------------|-------| |
| 92 | +| `fetch_channel(user_id?, slug?)` | Get a channel by broadcaster ID or slug | App | |
| 93 | +| `update_channel(category_id?, stream_title?, custom_tags?)` | Update channel metadata | User (`channel:write`) | |
| 94 | + |
| 95 | +### Livestreams |
| 96 | + |
| 97 | +| Method | Description | Token | |
| 98 | +|--------|-------------|-------| |
| 99 | +| `fetch_livestream(broadcaster_user_id)` | Get a single livestream | App | |
| 100 | +| `fetch_livestreams(broadcaster_user_id?, category_id?, language?, limit?, sort?)` | Get multiple livestreams | App | |
| 101 | +| `fetch_livestream_stats()` | Get global livestream stats | App | |
| 102 | + |
| 103 | +### Categories |
| 104 | + |
| 105 | +| Method | Description | Token | |
| 106 | +|--------|-------------|-------| |
| 107 | +| `fetch_categories(query?, name?, tag?, category_id?, cursor?, limit?)` | Search categories (v2) | App | |
| 108 | + |
| 109 | +### Chat |
| 110 | + |
| 111 | +| Method | Description | Token | |
| 112 | +|--------|-------------|-------| |
| 113 | +| `send_chat_message(content, message_type?, broadcaster_user_id?, reply_to_message_id?)` | Send a chat message | User (`chat:write`) | |
| 114 | +| `delete_chat_message(message_id)` | Delete a chat message | User (`moderation:chat_message:manage`) | |
| 115 | + |
| 116 | +### Moderation |
| 117 | + |
| 118 | +| Method | Description | Token | |
| 119 | +|--------|-------------|-------| |
| 120 | +| `ban_user(broadcaster_user_id, user_id, duration?, reason?)` | Ban or timeout a user | User (`moderation:ban`) | |
| 121 | +| `unban_user(broadcaster_user_id, user_id)` | Unban a user | User (`moderation:ban`) | |
| 122 | + |
| 123 | +### Channel Rewards |
| 124 | + |
| 125 | +| Method | Description | Token | |
| 126 | +|--------|-------------|-------| |
| 127 | +| `fetch_channel_rewards()` | List channel point rewards | User (`channel:rewards:read`) | |
| 128 | +| `create_channel_reward(cost, title, ...)` | Create a reward | User (`channel:rewards:write`) | |
| 129 | +| `update_channel_reward(reward_id, ...)` | Update a reward | User (`channel:rewards:write`) | |
| 130 | +| `delete_channel_reward(reward_id)` | Delete a reward | User (`channel:rewards:write`) | |
| 131 | +| `fetch_reward_redemptions(reward_id?, status?, ids?, cursor?)` | Get redemptions | User (`channel:rewards:read`) | |
| 132 | +| `accept_reward_redemptions(ids)` | Accept pending redemptions | User (`channel:rewards:write`) | |
| 133 | +| `reject_reward_redemptions(ids)` | Reject pending redemptions | User (`channel:rewards:write`) | |
| 134 | + |
| 135 | +### KICKs |
| 136 | + |
| 137 | +| Method | Description | Token | |
| 138 | +|--------|-------------|-------| |
| 139 | +| `fetch_kicks_leaderboard(top?)` | Get KICKs leaderboard | User (`kicks:read`) | |
| 140 | + |
| 141 | +### Events / Subscriptions |
| 142 | + |
| 143 | +| Method | Description | Token | |
| 144 | +|--------|-------------|-------| |
| 145 | +| `fetch_events_subscriptions()` | List event subscriptions | App | |
| 146 | +| `subscribe_to_event(event_type, user_id)` | Subscribe to a webhook event | App | |
| 147 | +| `unsubscribe_from_event(subscription_id)` | Unsubscribe from an event | App | |
| 148 | + |
| 149 | +### Other |
| 150 | + |
| 151 | +| Method | Description | Token | |
| 152 | +|--------|-------------|-------| |
| 153 | +| `fetch_public_key()` | Get the Kick public key for webhook verification | App | |
| 154 | + |
| 155 | +## OAuth Scopes |
| 156 | + |
| 157 | +```python |
| 158 | +from kickpy import Scope |
| 159 | + |
| 160 | +Scope.USER_READ # user:read |
| 161 | +Scope.CHANNEL_READ # channel:read |
| 162 | +Scope.CHANNEL_WRITE # channel:write |
| 163 | +Scope.CHANNEL_REWARDS_READ # channel:rewards:read |
| 164 | +Scope.CHANNEL_REWARDS_WRITE # channel:rewards:write |
| 165 | +Scope.CHAT_WRITE # chat:write |
| 166 | +Scope.STREAMKEY_READ # streamkey:read |
| 167 | +Scope.EVENTS_SUBSCRIBE # events:subscribe |
| 168 | +Scope.MODERATION_BAN # moderation:ban |
| 169 | +Scope.MODERATION_CHAT_MESSAGE_MANAGE # moderation:chat_message:manage |
| 170 | +Scope.KICKS_READ # kicks:read |
| 171 | +``` |
| 172 | + |
| 173 | +## Webhook Server |
| 174 | + |
| 175 | +Receive and process webhook events from Kick: |
| 176 | + |
| 177 | +```python |
| 178 | +import asyncio |
| 179 | +from kickpy import KickClient, WebhookEvent, WebhookServer |
42 | 180 | from kickpy.models.webhooks.chat_message import ChatMessage |
43 | | -from kickpy.webhooks.enums import WebhookEvent |
44 | | -from kickpy.webhooks.server import WebhookServer |
45 | 181 |
|
46 | 182 | def on_chat_message(payload: ChatMessage): |
47 | | - print(payload) |
48 | | - |
| 183 | + print(f"{payload.sender.username}: {payload.content}") |
49 | 184 |
|
50 | 185 | async def main(): |
51 | | - kick_client = Client("KICK_CLIENT_ID", "KICK_CLIENT_SECRET") |
52 | | - webhook_server = WebhookServer(kick_client, callback_route="KICK_CALLBACK_ROUTE") |
53 | | - webhook_server.dispatcher.listen(WebhookEvent.CHAT_MESSAGE_SENT, on_chat_message) |
54 | | - |
55 | | - await webhook_server.listen(host="localhost", port=3000, access_log=None) |
| 186 | + client = KickClient("KICK_CLIENT_ID", "KICK_CLIENT_SECRET") |
| 187 | + server = WebhookServer(client, callback_route="/webhooks/kick") |
| 188 | + server.dispatcher.listen(WebhookEvent.CHAT_MESSAGE_SENT, on_chat_message) |
56 | 189 |
|
| 190 | + await server.listen(host="localhost", port=3000, access_log=None) |
57 | 191 |
|
58 | 192 | loop = asyncio.new_event_loop() |
59 | 193 | asyncio.set_event_loop(loop) |
60 | 194 | loop.run_until_complete(main()) |
61 | 195 | loop.run_forever() |
62 | 196 | ``` |
| 197 | + |
| 198 | +### Webhook Events |
| 199 | + |
| 200 | +| Event | Enum | |
| 201 | +|-------|------| |
| 202 | +| `chat.message.sent` | `WebhookEvent.CHAT_MESSAGE_SENT` | |
| 203 | +| `channel.followed` | `WebhookEvent.CHANNEL_FOLLOWED` | |
| 204 | +| `channel.subscription.new` | `WebhookEvent.CHANNEL_SUB_NEW` | |
| 205 | +| `channel.subscription.gifts` | `WebhookEvent.CHANNEL_SUB_GIFTS` | |
| 206 | +| `channel.subscription.renewal` | `WebhookEvent.CHANNEL_SUB_RENEWAL` | |
| 207 | +| `livestream.status.updated` | `WebhookEvent.LIVESTREAM_STATUS_UPDATED` | |
| 208 | +| `livestream.metadata.updated` | `WebhookEvent.LIVESTREAM_METADATA_UPDATED` | |
| 209 | +| `channel.moderation.user_banned` | `WebhookEvent.MODERATION_USER_BANNED` | |
| 210 | +| `kicks.gifted` | `WebhookEvent.KICKS_GIFTED` | |
| 211 | +| `channel.reward.redemption.updated` | `WebhookEvent.CHANNEL_REWARD_REDEMPTION_UPDATED` | |
0 commit comments