domsom
domsom

Reputation: 3171

How to retrieve Slack messages via API identified by permalink?

I'm trying to retrieve a list of Slack reminders, which works fine using Slack API's reminders.list method. However, reminders that are set using SlackBot (i.e. by asking Slackbot to remind me of a message) return the respective permalink of that message as text:

{
    "ok": true,
    "reminders": [
        {
            "id": "Rm012C299C1E",
            "creator": "UV09YANLX",
            "text": "https:\/\/team.slack.com\/archives\/DUNB811AM\/p1583441290000300",
            "user": "UV09YANLX",
            "recurring": false,
            "time": 1586789303,
            "complete_ts": 0
        },

Instead of showing the permalink, I'd naturally like to show the message I wanted to be reminded of. However, I couldn't find any hints in the Slack API docs on how to retrieve a message identified by a permalink. The link is presumably generated by chat.getPermalink, but there seems to be no obvious chat.getMessageByPermalink or so.

I tried to interpet the path elements as channel and timestamp, but the timestamp (transformed from the example above: 1583441290.000300) doesn't seem to really match. At least I don't end up with the message I expected to retrieve when passing this as latest to conversations.history and limiting to 1.

Upvotes: 1

Views: 1883

Answers (1)

domsom
domsom

Reputation: 3171

After fiddling a while longer, here's how I finally managed in JS:

async function downloadSlackMsgByPermalink(permalink) {
  const pathElements = permalink.substring(8).split('/');
  const channel = pathElements[2];

  var url;
  if (permalink.includes('thread_ts')) {
    // Threaded message, use conversations.replies endpoint
    var ts = pathElements[3].substring(0, pathElements[3].indexOf('?'));
    ts = ts.substring(0, ts.length-6) + '.' + ts.substring(ts.length-6);

    var latest = pathElements[3].substring(pathElements[3].indexOf('thread_ts=')+10);
    if (latest.indexOf('&') != -1) latest = latest.substring(0, latest.indexOf('&'));

    url = `https://slack.com/api/conversations.replies?token=${encodeURIComponent(slackAccessToken)}&channel=${channel}&ts=${ts}&latest=${latest}&inclusive=true&limit=1`;
  } else {
    // Non-threaded message, use conversations.history endpoint
    var latest = pathElements[3].substring(1);
    if (latest.indexOf('?') != -1) latest = latest.substring(0, latest.indexOf('?'));
    latest = latest.substring(0, latest.length-6) + '.' + latest.substring(latest.length-6);
    url = `https://slack.com/api/conversations.history?token=${encodeURIComponent(slackAccessToken)}&channel=${channel}&latest=${latest}&inclusive=true&limit=1`;
  }
  const response = await fetch(url);
  const result = await response.json();
  if (result.ok === true) {
    return result.messages[0];
  }
}

It's not been tested to the latest extend, but first results look alright:

  • The trick with the conversations.history endpoint was to include the inclusive=true parameter
  • Messages might be threaded - the separate endpoint conversations.replies is required to fetch those
  • As the Slack API docs state: ts and thread_ts look like timestamps, but they aren't. Using them a bit like timestamps (i.e. cutting off some characters at the back and inserting a dot) seems to work, gladly, however.
  • Naturally, the slackAccessToken variable needs to be set beforehand

I'm aware the way to extract & transform the URL components in the code above might not the most elegant solution, but it proves the concept :-)

Upvotes: 2

Related Questions