Invalid Webhook Token on interaction - discord.js

I'm making a slash command bot for Discord and there is an issue with interactions. Apparently the webhook token is only valid for 15 minutes, after that I can no longer edit the message embed. This is usually not enough time for my users as the embed relies on a transaction to hit the blockchain (which these days can take about 30 minutes).
Is there a way to refresh the webhook token for my interaction so I can extend it past 15 minutes?

I do not believe that Discord supports refreshing webhook tokens, however, if you are waiting for your blockchain transaction to be completed before replying, you could defer the reply until that is done. You can do this with the MessageComponentInteraction.deferReply() method.
EDIT: After further thought, I realize that this may not actually solve your problem. You might be forced to use a standard message.reply() workflow for sending this.

Unfortunately, Discord (not discord.js) expires all interaction tokens after 15 minutes. This is a Discord limitation, and you will have to bring this up to Discord to give feedback. However, there is a workaround.
This is the recommended approach if you have a lot of requests coming through. According to your JSON data, you do not need ephemeral messages, which means that you can simply send the message as a bot user.
Note: This requires you to have the bot scope when users are inviting your bot.
const embed = new MessageEmbed()
.setTitle("Waiting for transaction to finish...")
// ...
await interaction.reply("See below message.");
const msg = await interaction.channel.send({ embeds: [embed] });
// Once the transaction finishes
const updatedEmbed = embed
.setTitle("Transaction finished!")
// ...
await msg.edit({ embeds: [updatedEmbed] });
By using a bot that sends a message, you get unlimited time to edit the message, even past 30 minutes.
Another workaround if you don't have the bot scope on your user's servers is to manually create server webhooks (not interactions) and edit them when needed. This requires them to invite the bot with webhook permissions, though.
This approach does not require the bot scope, however, requires webhook permissions.
const webhook = await interaction.channel.createWebhook("My Bot Name", {
avatar: "" // link to your bot's avatar (optional)
});
const embed = new MessageEmbed()
.setTitle("Waiting for transaction to finish...")
// ...
await interaction.reply("See below message.");
const msg = webhook.send({ embeds: [embed] });
// Once the transaction finishes
const updatedEmbed = embed
.setTitle("Transaction finished!")
// ...
await msg.edit({ embeds: [updatedEmbed] });

Related

Discordjs: Specifying channel for an interaction.reply

I am using Discordjs v13. I have created a slash command and I am able to "print" a message using
await interaction.reply(messageObj);
I need to send the reply to a different channel where the command was triggered, is this possible?
Something like:
interaction.setChannel(channelId).reply(...)
OR
interaction.reply({
channel: ....
....
})
What you want is not possible. The Discord API does not allow to specify the channel where the app interaction should be replied in: https://discord.com/developers/docs/interactions/receiving-and-responding#responding-to-an-interaction
However if you are concerned with the reply being shown to everyone, you can make the reply ephemeral. If you want to log interactions, you can reply to the interaction then send another message using the solution provided in the comments of your question.
this is actually possible in discordjs v14 and may be in v13 as well. Carl-bot does it with suggestions.but its not an actual reply
use
interaction.guild.channels.cache.get('channel-id').send('message')
this will send a message in a the select channel you may still want to
interaction.reply({Content:'replied in #channel' [embed], ephemeral: true })
so the user knows the reply was redirected . ephemeral: true makes the replay only visible to the user that evoked the interaction.
and if you need the message id for the new message use
const msg = await interaction.guild.channels.cache.get('channel-id').send('message');
to send the message and you can do something like const messageid = msg.id

Discord: Reading messages from one channel in a (non-admin perm) server, and posting it to another (with admin perms)

I am new to Discord API framework.
ServerFROM is a public server that I was invited to (non-admin perms). Hence I cannot add bots there. But I can view the content in ChannelFROM (a text channel in ServerFROM)
I have my own ServerTO (in which I have admin perms and so can do anything). Inside of which, I have the target ChannelTO
I want to deploy a listener on ChannelFROM, such when there is a new message (announcement) in ChannelFROM, I want it to be read and reposted in ChannelTO.
Something similar to what is done in this Stackoverflow issue, except that I cannot have some script run locally 24x7 on my machine. Maybe use Github Actions or something similar?
How can I go about doing it? Any ideas are appreciated. Maybe some form of a server, or just a custom Discord bot
And thanks in advance.
you can use Custom bot for that. I dont know other way
here's how i do it
1st : We Get the ID of the Channel that you wanted to listen
2nd : We make a Output or where the bot copy the message from and send it
3rd : Bot required a permission to view the channel and send message
or in the nutshell ( sorry if im bad at explaining )
client.on("messageCreate", message => {
if(message.author.bot) return;
if(message.channel.id === ID_HERE) // ChannelFROM in ID_HERE
{
let MSG = message.content
let Author = message.member.displayName
let Avatar = message.author.displayAvatarURL({dynamic: true})
const Embed = new MessageEmbed()
.setAuthor(Author , Avatar )
.setDescription(MSG)
.setColor("RANDOM")
client.channels.cache.get(ID_HERE).send({ embeds: [Embed] }) // SendTo in ID_HERE
}
})
you can remove if(message.author.bot) return; if you want it also read other bot message on that specific channel

How to get permissions in discord js when we do direct message

I am trying to get a list of the permission that the user has in Discord. If it sends the message in the channel, it’s fine as we can use message.member.hasPermission, etc.
But what if the message is DM? I want my users to send a DM to the bot and the bot be able to check and see if the user has certain permissions.
I cannot find anything anywhere. I keep getting redirected to message.member, or message.guild which both are null when it’s in DM.
In DM no one has permissions. All you have is the permission to see messages and send messages which aren’t shown visually, or to bots. To make sure that it isn’t DM, just return if the channel type is dm, or guild is null.
if(!message.guild) return;
//before checking "perms"
If you want the permissions for a certain guild if the message is from DM, use this code
if(message.channel.type === 'dm') {
let guild = await client.guilds.fetch('THE ID OF THE GUILD YOU WANT TO SEE THE USER’S PERMS IN')
let member = await guild.members.fetch(message.author.id);
//you can now access member.permissions
}
Keep in mind await must be in an async callback.
You did not provide any code so I cannot give any more code than this.
You can fetch the member with the guild's context.
Fetching is recommended, as Guild#member() relies on cache and is also deprecated.
Member#hasPermission() will be deprecated as well, using MemberRoleManager#has() is recommended
The following example uses async/await, ensure you're inside an async function
// Inside async function
const guild = await client.guilds.fetch('guild-id');
const member = await guild.members.fetch(message.author.id);
const hasThisPermission = member.roles.cache.has('permission');

discord.py get webhooks of channel

I'm trying to make a webhook so if anyone says 'ez' it deletes it and sends a message with the webhook with a random message. Originally what I was doing was
if "ez" in message.content:
webhook = await message.create_webhook(name=ctx.author.name)
await webhook.send(ezmessages[random.randint(0, len(ezmessages))-1], username=message.author.name, avatar_url=message.author.avatar_url)
await message.delete()
await webhook.delete()
but the problem is this gets rate limited if webhooks are created and deleted too quickly. So instead what I want to do is check if the bot already has a webhook for the text channel, and if there is one use that but if not use a different one. I thought this would work:
for webhook in message.channel.webhooks:
await webhook.send(ezmessages[random.randint(0, len(ezmessages))-1], username=message.author.name, avatar_url=message.author.avatar_url)
but I get the error
TypeError: 'method' object is not iterable
Even though it should return a list
Anyone know how to correctly iterate over this?
TextChannel.webhooks it's not an attribute, its a function and a coroutine, so you need to call it and await it
webhooks = await message.channel.webhooks()
for webhook in webhooks:
...
docs

Creating a Discord bot to notify people when to certain text on a website has changed

const Discord = require('discord.js');
const bot = new Discord.Client();
const token = '';
bot.on('ready', () =>{
console.log('This bot is online');
})
bot.on('message', msg=>{
if(msg.content === "?rates"){
msg.reply('.')
}
})
bot.login(token);
This is what I have so far it is very basic, I understand, I'm just trying to get some sort of idea how to process. What I want is as soon as a website gets updated or changed. I would like it to tag everyone and in a certain channel and specifies what has changed. I know this will be a long process but I'm in for the ride :) would appreciate any help.
You need a webhook on the website and listen to it with your bot, if you have control over the site, this may help you, otherwise you could look if the site has one or perhaps ask an owner.
A probably working but not very nice (and not very clean) solution would be to save the text of the website every 5 seconds or so and compare it to the previous save. If it changed, you notify the members through sending a message.

Resources