{"id":28708912,"url":"https://github.com/invokable/discord-manager","last_synced_at":"2025-06-14T19:04:58.073Z","repository":{"id":45865788,"uuid":"162669226","full_name":"invokable/discord-manager","owner":"invokable","description":null,"archived":false,"fork":false,"pushed_at":"2025-06-13T05:40:44.000Z","size":173,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-13T12:56:36.559Z","etag":null,"topics":["discord"],"latest_commit_sha":null,"homepage":"https://packagist.org/packages/revolution/discord-manager","language":"PHP","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/invokable.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["invokable"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"thanks_dev":null,"custom":null}},"created_at":"2018-12-21T05:20:14.000Z","updated_at":"2025-06-13T05:40:47.000Z","dependencies_parsed_at":"2023-12-09T02:24:51.330Z","dependency_job_id":"33628959-6a09-4df2-8d9a-a3478c6f1a0e","html_url":"https://github.com/invokable/discord-manager","commit_stats":{"total_commits":121,"total_committers":2,"mean_commits":60.5,"dds":0.03305785123966942,"last_synced_commit":"fe25ac592589b3e3190c7c4090e936e2236c5101"},"previous_names":["invokable/discord-manager","kawax/discord-manager"],"tags_count":46,"template":false,"template_full_name":null,"purl":"pkg:github/invokable/discord-manager","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/invokable%2Fdiscord-manager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/invokable%2Fdiscord-manager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/invokable%2Fdiscord-manager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/invokable%2Fdiscord-manager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/invokable","download_url":"https://codeload.github.com/invokable/discord-manager/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/invokable%2Fdiscord-manager/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259868350,"owners_count":22924231,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["discord"],"created_at":"2025-06-14T19:04:53.591Z","updated_at":"2025-06-14T19:04:58.055Z","avatar_url":"https://github.com/invokable.png","language":"PHP","funding_links":["https://github.com/sponsors/invokable"],"categories":[],"sub_categories":[],"readme":"# Laravel Discord Manager\n\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/invokable/discord-manager)\n\n\u003e **Note** As of v5, only the Interactions command is provided, which is webhook based and therefore easy to use with Laravel. All features using WebSockets have been removed.\n\n## Overview\n\nDiscord Manager is a Laravel package that provides seamless integration with Discord's Interactions API using webhook-based architecture. This package allows you to create and manage Discord slash commands, handle user interactions, and respond to Discord events directly from your Laravel application.\n\n### Key Features\n\n- **Webhook-based Architecture**: Secure and efficient handling of Discord interactions through webhooks\n- **Slash Commands Support**: Create and register both guild-specific and global Discord slash commands\n- **Laravel Integration**: Native Laravel service provider with configuration publishing and Artisan commands\n- **Automatic Command Discovery**: Automatically loads and registers interaction commands from your application\n- **Flexible Response System**: Support for immediate responses, deferred responses, and followup messages\n- **Component Support**: Built-in support for Discord UI components like buttons, select menus, and modals\n- **Event-driven**: Integrates with Laravel's event system for handling Discord interactions\n\n### How It Works\n\nThe package operates by receiving webhook requests from Discord when users interact with your bot's commands. These requests are validated, processed through middleware, and dispatched to your custom command handlers. The workflow ensures secure communication with Discord while providing a familiar Laravel development experience.\n\n### See also\n\n- [Socialite for Discord](https://github.com/invokable/socialite-discord)\n- [Laravel Notification for Discord(Webhook)](https://github.com/invokable/laravel-notification-discord-webhook)\n\n## Requirements\n- PHP \u003e= 8.2\n- Laravel \u003e= 11.0\n\n## Installation\n\n### Step 1: Install the Package\n\n```shell\ncomposer require revolution/discord-manager\n```\n\n### Step 2: Discord Application Setup\n\nBefore configuring the package, you need to create a Discord application and bot:\n\n1. Go to the [Discord Developer Portal](https://discord.com/developers/applications)\n2. Click \"New Application\" and give it a name\n3. Navigate to the \"Bot\" section and click \"Add Bot\"\n4. Copy the bot token for `DISCORD_BOT_TOKEN`\n5. Go to \"General Information\" and copy the Application ID for `DISCORD_BOT`\n6. Copy the Public Key for `DISCORD_PUBLIC_KEY`\n7. For guild-specific commands, copy your Discord server's Guild ID for `DISCORD_GUILD`\n\n### Step 3: Environment Configuration\n\nAdd the following variables to your `.env` file:\n\n```env\n# Bot token from Discord Developer Portal \u003e Bot section\nDISCORD_BOT_TOKEN=your_bot_token_here\n\n# Application ID from Discord Developer Portal \u003e General Information\nDISCORD_BOT=your_application_id_here\n\n# Public Key from Discord Developer Portal \u003e General Information  \nDISCORD_PUBLIC_KEY=your_public_key_here\n\n# Guild ID (Server ID) for guild-specific commands (optional)\nDISCORD_GUILD=your_guild_id_here\n\n# Optional: Discord API version (defaults to 10)\nDISCORD_API_VERSION=10\n```\n\n### Step 4: Publish Configuration\n\n```shell\nphp artisan vendor:publish --tag=discord-interactions-config\n```\n\nThis creates `config/discord_interactions.php` where you can define your commands and customize settings.\n\n### Uninstall\n```shell\ncomposer remove revolution/discord-manager\n```\n\n- Delete `config/discord_interactions.php`\n- Delete `app/Discord/` and other files.\n- Delete `DISCORD_*` in `.env`\n\n## Configuration\n\n### Command Configuration\n\nEdit `config/discord_interactions.php` to define your Discord commands:\n\n```php\nreturn [\n    // Guild-specific commands (only available in specified servers)\n    'guild' =\u003e [\n        [\n            'name' =\u003e 'hello',\n            'description' =\u003e 'Say hello to a user',\n            'type' =\u003e CommandType::CHAT_INPUT,\n            'guild_id' =\u003e env('DISCORD_GUILD'),\n            'options' =\u003e [\n                [\n                    'name' =\u003e 'user',\n                    'description' =\u003e 'User to greet',\n                    'type' =\u003e CommandOptionType::USER,\n                    'required' =\u003e true,\n                ],\n            ],\n        ],\n    ],\n\n    // Global commands (available in all servers)\n    'global' =\u003e [\n        [\n            'name' =\u003e 'ping',\n            'description' =\u003e 'Check if the bot is responding',\n            'type' =\u003e CommandType::CHAT_INPUT,\n        ],\n    ],\n\n    // Other configuration options\n    'commands' =\u003e app_path('Discord/Interactions'), // Path to command classes\n    'token' =\u003e env('DISCORD_BOT_TOKEN'),\n    'bot' =\u003e env('DISCORD_BOT'),\n    'public_key' =\u003e env('DISCORD_PUBLIC_KEY'),\n    'path' =\u003e 'discord/webhook', // Webhook endpoint path\n    'route' =\u003e 'discord.webhook', // Route name\n    'middleware' =\u003e 'throttle', // Additional middleware\n];\n```\n\n### Discord Developer Portal Setup\n\nSet the **Interactions Endpoint URL** in your Discord application:\n\n1. Go to [Discord Developer Portal](https://discord.com/developers/applications)\n2. Select your application\n3. Navigate to \"General Information\"\n4. Set the Interactions Endpoint URL to: `https://yourdomain.com/discord/webhook`\n\n## Usage\n\n### Quick Start\n\nHere's a complete example to get you started:\n\n#### 1. Create a Command\n\n```shell\nphp artisan discord:make:interaction HelloCommand\n```\n\nThis creates `app/Discord/Interactions/HelloCommand.php`:\n\n```php\n\u003c?php\n\nnamespace App\\Discord\\Interactions;\n\nuse Illuminate\\Http\\Request;\nuse Revolution\\DiscordManager\\Concerns\\WithInteraction;\n\nclass HelloCommand\n{\n    use WithInteraction;\n\n    public string $command = 'hello';\n\n    public function __invoke(Request $request): void\n    {\n        $user = $request-\u003ejson('member.user.id', $request-\u003ejson('user.id'));\n\n        $data = [\n            'content' =\u003e \"\u003c@$user\u003e Hello from Laravel!\",\n            'allowed_mentions' =\u003e ['parse' =\u003e ['users']],\n        ];\n\n        $response = $this-\u003efollowup(token: $request-\u003ejson('token'), data: $data);\n    }\n}\n```\n\n#### 2. Add Command to Configuration\n\nThe command you created can be used as either a guild-specific or global command. You need to add it to your `config/discord_interactions.php` file to specify where it should be registered.\n\nEdit `config/discord_interactions.php` and add your command to either the `guild` or `global` array:\n\n```php\nreturn [\n    // For guild-specific commands (only available in specified servers)\n    'guild' =\u003e [\n        [\n            'name' =\u003e 'hello',\n            'description' =\u003e 'Say hello from Laravel',\n            'type' =\u003e CommandType::CHAT_INPUT,\n            'guild_id' =\u003e env('DISCORD_GUILD'),\n        ],\n        // Add more guild commands here...\n    ],\n\n    // For global commands (available in all servers where your bot is installed)\n    'global' =\u003e [\n        [\n            'name' =\u003e 'hello',\n            'description' =\u003e 'Say hello from Laravel',\n            'type' =\u003e CommandType::CHAT_INPUT,\n        ],\n        // Add more global commands here...\n    ],\n\n    // ... rest of configuration\n];\n```\n\nChoose `guild` for testing and development, or `global` for production deployment to all servers.\n\n#### 3. Register Commands\n\n```shell\nphp artisan discord:interactions:register\n```\n\n#### 4. Create Event Listener\n\nThe Discord Manager package uses Laravel's event system to handle incoming webhook requests. When Discord sends a webhook request to your application, the package dispatches an `InteractionsWebhook` event. You need to create a listener to handle this event and process the Discord interaction.\n\n```shell\nphp artisan make:listener InteractionsListener\n```\n\nUpdate `app/Listeners/InteractionsListener.php`:\n\n```php\n\u003c?php\n\nnamespace App\\Listeners;\n\nuse Revolution\\DiscordManager\\Events\\InteractionsWebhook;\nuse Revolution\\DiscordManager\\Facades\\DiscordManager;\n\nclass InteractionsListener\n{\n    public function handle(InteractionsWebhook $event): void\n    {\n        DiscordManager::interaction($event-\u003erequest);\n    }\n}\n```\n\nThis listener receives the webhook request from Discord and passes it to the DiscordManager, which then routes it to the appropriate command class based on the interaction data.\n\n\n\n### Advanced Usage\n\n#### Commands with Options\n\n```php\n\u003c?php\n\nnamespace App\\Discord\\Interactions;\n\nuse Illuminate\\Http\\Request;\nuse Revolution\\DiscordManager\\Concerns\\WithInteraction;\n\nclass GreetCommand\n{\n    use WithInteraction;\n\n    public string $command = 'greet';\n\n    public function __invoke(Request $request): void\n    {\n        $targetUser = $request-\u003ejson('data.options.0.value');\n        $message = $request-\u003ejson('data.options.1.value', 'Hello!');\n        $user = $request-\u003ejson('member.user.id', $request-\u003ejson('user.id'));\n\n        $data = [\n            'content' =\u003e \"\u003c@$targetUser\u003e $message (from \u003c@$user\u003e)\",\n            'allowed_mentions' =\u003e ['parse' =\u003e ['users']],\n        ];\n\n        $this-\u003efollowup(token: $request-\u003ejson('token'), data: $data);\n    }\n}\n```\n\n#### Interactive Components\n\n```php\n\u003c?php\n\nnamespace App\\Discord\\Interactions;\n\nuse Illuminate\\Http\\Request;\nuse Revolution\\DiscordManager\\Concerns\\WithInteraction;\nuse Revolution\\DiscordManager\\Support\\ComponentType;\nuse Revolution\\DiscordManager\\Support\\ButtonStyle;\n\nclass ButtonCommand\n{\n    use WithInteraction;\n\n    public string $command = 'button-demo';\n\n    public function __invoke(Request $request): void\n    {\n        $data = [\n            'content' =\u003e 'Click a button below:',\n            'components' =\u003e [\n                [\n                    'type' =\u003e ComponentType::ACTION_ROW-\u003evalue,\n                    'components' =\u003e [\n                        [\n                            'type' =\u003e ComponentType::BUTTON-\u003evalue,\n                            'style' =\u003e ButtonStyle::PRIMARY-\u003evalue,\n                            'label' =\u003e 'Primary',\n                            'custom_id' =\u003e 'primary_button',\n                        ],\n                        [\n                            'type' =\u003e ComponentType::BUTTON-\u003evalue,\n                            'style' =\u003e ButtonStyle::SUCCESS-\u003evalue,\n                            'label' =\u003e 'Success',\n                            'custom_id' =\u003e 'success_button',\n                        ],\n                    ],\n                ],\n            ],\n        ];\n\n        $this-\u003efollowup(token: $request-\u003ejson('token'), data: $data);\n    }\n}\n```\n\n#### Handling Button Interactions\n\n```php\n\u003c?php\n\nnamespace App\\Discord\\Interactions;\n\nuse Illuminate\\Http\\Request;\nuse Revolution\\DiscordManager\\Concerns\\WithInteraction;\n\nclass PrimaryButtonCommand\n{\n    use WithInteraction;\n\n    public string $command = 'primary_button';\n\n    public function __invoke(Request $request): void\n    {\n        $user = $request-\u003ejson('member.user.id', $request-\u003ejson('user.id'));\n\n        $data = [\n            'content' =\u003e \"\u003c@$user\u003e You clicked the primary button!\",\n            'allowed_mentions' =\u003e ['parse' =\u003e ['users']],\n        ];\n\n        $this-\u003efollowup(token: $request-\u003ejson('token'), data: $data);\n    }\n}\n```\n\n### Command Registration\n\nAfter creating or modifying commands, always register them with Discord:\n\n```shell\n# Register all commands defined in config\nphp artisan discord:interactions:register\n```\n\n### Troubleshooting\n\n#### Common Issues\n\n1. **Webhook URL not accessible**: Ensure your application is publicly accessible and the webhook URL is correct\n2. **Invalid signature**: Verify your `DISCORD_PUBLIC_KEY` is correct\n3. **Commands not appearing**: Check that commands are properly registered and the bot has necessary permissions\n4. **Permission errors**: Ensure your bot has the necessary permissions in the Discord server\n\n#### Testing Webhook Locally\n\nFor local development, we recommend using [expose](https://expose.dev/) to expose your local server. Expose is a popular choice among Laravel/PHP developers for creating secure tunnels to localhost.\n\nFirst, install expose globally:\n\n```shell\ncomposer global require exposedev/expose\n```\n\nNext, create an expose account and set your authentication token:\n\n```shell\nexpose token YOUR_TOKEN\n```\n\nFor more information on authentication, see the [expose documentation](https://expose.dev/docs/getting-started/authentication).\n\nTo use expose, start your Laravel local server first, then run the `expose share` command:\n\n```shell\nphp artisan serve\n```\n```shell\nexpose share http://127.0.0.1:8000\n```\n\nIf you are not using `php artisan serve`, please adjust it to suit your environment.\n\nUse the generated expose URL as your webhook endpoint in Discord Developer Portal.\n\n## How It Works\n\nThe Discord Manager package follows a secure webhook-based workflow to handle Discord interactions:\n\n### Request Flow\n\n1. **Discord Webhook**: Discord sends a POST request to `https://yourdomain.com/discord/webhook` when users interact with your bot\n2. **Signature Validation**: [ValidateSignature](./src/Http/Middleware/ValidateSignature.php) middleware verifies the request authenticity using your public key\n3. **Controller Processing**: [InteractionsWebhookController](./src/Http/Controllers/InteractionsWebhookController.php) receives and processes the interaction\n4. **Deferred Response**: [DeferredResponse](./src/Http/Response/DeferredResponse.php) immediately acknowledges Discord to prevent timeout\n5. **Event Dispatch**: [DispatchInteractionsEvent](./src/Http/Middleware/DispatchInteractionsEvent.php) terminable middleware dispatches the interaction event\n6. **Event Handling**: [InteractionsWebhook](./src/Events/InteractionsWebhook.php) event is fired and handled by your listener\n7. **Command Execution**: Your `InteractionsListener` calls `DiscordManager::interaction()` which invokes the appropriate command class\n8. **Response Delivery**: Commands use the `followup()` method to send responses back to Discord\n\n### Security\n\n- All requests are cryptographically verified using Ed25519 signatures\n- Invalid signatures are automatically rejected\n- Webhook endpoints are protected against unauthorized access\n\n### Performance\n\n- Deferred responses prevent Discord timeouts (3-second limit)\n- Terminable middleware allows background processing\n- Automatic command discovery and caching\n\n## Examples and Resources\n\n### Sample Application\n\nFor a complete working example, see: https://github.com/kawax/discord-interactions\n\n### Command Types\n\nThe package supports various Discord command and component types:\n\n- **Slash Commands**: Traditional `/command` interactions\n- **User Commands**: Right-click context menu on users  \n- **Message Commands**: Right-click context menu on messages\n- **Button Components**: Interactive buttons in messages\n- **Select Menus**: Dropdown selection components\n- **Modal Forms**: Pop-up forms for user input\n\n### Response Types\n\n- **Immediate Response**: Direct reply to the interaction\n- **Deferred Response**: Acknowledge first, respond later (recommended)\n- **Followup Messages**: Additional messages after the initial response\n\n### Best Practices\n\n1. **Use Deferred Responses**: Always use `followup()` for responses that take time to process\n2. **Handle Errors Gracefully**: Implement proper error handling in your command classes\n3. **Validate Input**: Always validate user input from command options\n4. **Use Guild Commands for Development**: Guild commands are scoped to specific servers for testing\n5. **Implement Logging**: Use Laravel's logging to track interactions and debug issues\n\n## LICENSE\nMIT \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finvokable%2Fdiscord-manager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finvokable%2Fdiscord-manager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finvokable%2Fdiscord-manager/lists"}