Denly

Connect coding agents to Jira, Linear, GitHub, Slack and 11 more tools

Label a Jira issue or type a Slack command and a coding agent picks the work up. Denly connects 15 trackers and chat tools, and posts comments, status changes and worklogs back.

All members can inspect redacted connection health and recent queued, processed, or failed deliveries. Only owners and admins can create, edit, enable, disable, or delete connections.

Tracker connections support tag, assignee, and create triggers plus comments, worklogs, and status mappings. Chat connections accept slash commands and supported reactions, map channels to projects, and deliver notifications.

Loading the provider catalog…

Secrets are write-only.The inbound secret appears once after creation. Stored credentials are sealed and all later reads are redacted. Use Recent events for webhook authentication, normalization, queue, and outbound diagnostics.

How to connect any provider

These runbooks are for workspace owners and admins. A connection belongs to the workspace and is scoped to exactly one project, which every task it creates lands in. Chat connections can still send individual channels elsewhere with a channel-to-project mapping, and that mapping wins; the project scope is the floor under it, not a ceiling. A chat message that names a project explicitly beats both. For task-producing providers, leave routing blank for unassigned tasks, choose a default member, or map external users to Denly members.

Reading Recent events

Every runbook below ends by checking Workspace → Integrations → your connection → Recent events. Each delivery that gets that far shows as one of:

  • Queued or Processing – it arrived and is being worked through. Both are momentary.
  • Processed – it became a Denly task, or updated one.
  • Skipped – expected, and usually not a fault. The Diagnostic column says which rule declined it: the tag or label did not match, the assignee or project did not match, or the item was already linked to a task another delivery created first.
  • Failed – Denly reached the provider and the provider refused. The Diagnostic column carries its error verbatim.

An empty list means something different. Denly refuses a delivery with a bad secret before the queue, so it never becomes a row, and a redelivery Denly has already handled leaves no row either. A connection still reading Awaiting first event after you have tried it is therefore rejecting deliveries rather than skipping them. Check the secret on both sides, then read the provider's own webhook delivery log, the only place those attempts appear.

Trackers & project management

Jira

Import Jira issues and tagged comments, then synchronize comments, transitions, worklogs, and assignment routing.

1. Create a Jira API token

In Atlassian:

  1. Open Atlassian account security.
  2. Select Create API token.
  3. Name it Denly, create it, and copy it immediately. Jira shows it only once.

Use the token with the email address of the Jira account. Do not paste the token into a webhook payload.

2. Create the Denly connection

Open Workspace → Integrations → Connect → Jira.

  • External workspace or repository: your Jira project key, such as ENG.
  • API base URL: your Jira site, such as https://acme.atlassian.net.
  • Account email and API token: the Jira account's email address and the token from step 1.
  • Trigger tag: denly; keep Trigger on create disabled for the first test.
  • Initial Denly stage: Plan first. Enable Post worklogs to have Denly log time against the issue.

Routing is optional. Leave Default Denly assignee blank for unassigned tasks, or choose one workspace member to own everything from this connection.

For per-person routing use Route by external assignee: each row pairs one person in the provider (left) with a workspace member (right), and + adds another row. Routing follows the item's assignee in the provider, not whoever created it, and a matching row beats the default above.

The left-hand value must be the identifier the provider actually sends, which the field's placeholder names for you. Matching ignores surrounding spaces and letter case, but nothing else: a near-miss routes nothing and looks the same as a broken integration.

Read Jira webhook documentation.

3. Register the Jira webhook

In Jira open Settings → System → Webhooks → Create webhook. Set the generated Denly URL, subscribe to issue-created/updated and issue-comment events, and leave the JQL filter matching the issues you want Denly to see.

Authenticate the webhook. Jira Cloud has no custom-header field, so paste the Denly inbound secret into the webhook’s Secret box. Jira then signs each delivery and sends X-Hub-Signature: sha256=…, which Denly verifies against the same secret. Save the webhook.

Jira Data Center has no Secret box but does allow headers: send the inbound secret as X-Denly-Token instead. Denly accepts either scheme. The same applies to a Jira Automation rule using Send web request, which supports custom headers but does not sign.

A self-managed Jira server must be publicly reachable over HTTPS. Jira’s webhook delivery log is the first place to check.

4. Test and troubleshoot
  1. Create an issue in the connected project and add the denly label.
  2. Open Workspace → Integrations → Jira → Recent events.
  3. Processed means a task was created; Skipped means the label, assignee, project or create rule declined it, and the Diagnostic column says which.

Nothing at all, and the card still on Awaiting first event, means every delivery is being rejected before the queue: re-check the webhook Secret, or the X-Denly-Token header, against the inbound secret. The secret is shown only once, so replace it on both sides rather than guessing. Jira's own webhook delivery log is where those rejected attempts are recorded.

Status mappings move the Jira issue as the task progresses. The setting appears once the connection is saved, not while you are creating it: the dropdown is read live from your project's workflow, which needs the credentials to be stored first. Until you set it, the defaults apply. Reopen the connection and each row offers your project's real statuses – so there is no name to spell. Leave a stage on Default to keep the value shown in the option, or set it to No change to leave the issue where it is. If Denly cannot read your workflow – the stored credentials have lapsed, or Jira is having a bad minute – the rows fall back to a text box plus a No change box, so the mapping stays editable rather than blocking the rest of the form. Jira transitions are edges rather than states, so a status that is not reachable from the issue's current one is skipped rather than forced.

Comments containing #denly on linked issues become revision work.

YouTrack

Import YouTrack issues and tagged comments and synchronize comments, state, work time, and assignment routing.

1. Create a YouTrack token

In YouTrack:

  1. Open your avatar → Profile.
  2. Open Account Security.
  3. Select New token.
  4. Name it Denly.
  5. Select the YouTrack scope.
  6. Create it and copy it immediately.

YouTrack only shows the token once. It is used as a bearer token for API access. Read JetBrains’ permanent token guide.

2. Create the Denly connection

Open Workspace → Integrations → Connect → YouTrack.

  • External workspace or repository: project short name, such as DEV.
  • API base URL: https://your-company.youtrack.cloud or your public HTTPS Server URL.
  • Permanent token: paste the token.
  • State field name: leave blank unless your project renamed its State field or has more than one.
  • Trigger tag: denly; leave Trigger on create disabled initially.
  • Initial Denly stage: Plan first, with Post worklogs enabled.

Routing is optional. Leave Default Denly assignee blank for unassigned tasks, or choose one workspace member to own everything from this connection.

For per-person routing use Route by external assignee: each row pairs one person in the provider (left) with a workspace member (right), and + adds another row. Routing follows the item's assignee in the provider, not whoever created it, and a matching row beats the default above.

The left-hand value must be the identifier the provider actually sends, which the field's placeholder names for you. Matching ignores surrounding spaces and letter case, but nothing else: a near-miss routes nothing and looks the same as a broken integration.

Create the connection and copy the generated webhook URL and inbound secret. The secret is shown only once.

3. Make YouTrack send events

Go to Administration → Workflows, create a JavaScript workflow, add an On-change rule, paste this script, replace DENLY_URL and DENLY_SECRET, then attach and enable the workflow for your project.

const entities = require('@jetbrains/youtrack-scripting-api/entities');
const http = require('@jetbrains/youtrack-scripting-api/http');

const DENLY_URL = 'https://your-public-host/integrations/youtrack/webhook/YOUR_CONNECTION_ID';
const DENLY_SECRET = 'paste-your-inbound-secret-here';

function sendIssue(issue, eventName) {
  const tags = [];
  issue.tags.forEach(tag => tags.push({ name: tag.name }));

  const assignee = issue.fields.Assignee;
  const reporter = issue.reporter;
  const payload = {
    event: eventName,
    issue: {
      idReadable: issue.idReadable,
      id: issue.id,
      summary: issue.summary || '',
      description: issue.description || '',
      tags: tags,
      assignee: assignee ? { login: assignee.login, name: assignee.name } : {},
      reporter: reporter ? { login: reporter.login, name: reporter.name } : {},
      project: { shortName: issue.project.shortName }
    }
  };

  const connection = new http.Connection(DENLY_URL);
  connection.addHeader('Content-Type', 'application/json');
  connection.addHeader('X-Denly-Token', DENLY_SECRET);
  const response = connection.postSync('', null, JSON.stringify(payload));
  console.log('Denly response: ' + response.code + ' ' + response.response);
}

exports.rule = entities.Issue.onChange({
  title: 'Send tagged issues to Denly',
  guard: ctx => {
    const issue = ctx.issue;
    return issue.becomesReported || issue.isChanged('tags') || issue.isChanged('Assignee');
  },
  action: ctx => {
    const issue = ctx.issue;
    const tags = [];
    issue.tags.forEach(tag => tags.push(tag.name.toLowerCase()));
    const hasDenlyTag = tags.includes('denly');
    const hasAssignee = issue.fields.Assignee != null;
    if (hasDenlyTag || hasAssignee) sendIssue(issue, issue.becomesReported ? 'created' : 'updated');
  },
  requirements: {}
});

Read JetBrains HTTP handlers and YouTrack on-change rules.

4. Test and troubleshoot

Create or update an issue and add denly. In Recent events, Processed means it became a task and Skipped means the project, tag or assignee did not match. No row at all means X-Denly-Token is wrong – the delivery never reached the queue.

Denly finds your project's State field on its own. Name it in State field name only if the project renamed it or has more than one. Status mappings must use exact names such as In Progress, Fixed, or Blocked.

Linear

Import Linear issues and comments for a team with signed webhooks, workflow updates, and assignment routing.

1. Create a Linear API key

In Linear:

  1. Open Settings → API.
  2. Create a personal API key for an account that can read and update the target team.
  3. Name it Denly and copy it immediately.

Keep this API key for Denly's API key field. Do not put it in Linear's webhook form. Read Linear webhooks.

2. Create the Denly connection

Create the connection before creating the Linear webhook, because Denly generates the callback URL.

Open Workspace → Integrations → Connect → Linear and use:

  • External workspace or repository: the Linear team ID.
  • API base URL: https://api.linear.app/graphql.
  • API key: paste the Linear API key.
  • Trigger tag: denly.
  • Trigger on create: leave disabled for the first test.
  • Initial Denly stage: Plan first.

Routing is optional. Leave Default Denly assignee blank for unassigned tasks, or choose one workspace member to own everything from this connection.

For per-person routing use Route by external assignee: each row pairs one person in the provider (left) with a workspace member (right), and + adds another row. Routing follows the item's assignee in the provider, not whoever created it, and a matching row beats the default above.

The left-hand value must be the identifier the provider actually sends, which the field's placeholder names for you. Matching ignores surrounding spaces and letter case, but nothing else: a near-miss routes nothing and looks the same as a broken integration.

Create the connection and copy the generated Webhook URL. The initial Denly secret is only a placeholder for this Linear flow; Linear generates the signing secret in the next step. Linear connections comment back and move workflow states; they do not log time, so no worklog setting is offered.

3. Create the Linear webhook

In Linear:

  1. Open Settings → API → Webhooks.
  2. Select New webhook.
  3. For URL, paste the Webhook URL copied from Denly. It looks like https://your-public-host/integrations/linear/webhook/YOUR_CONNECTION_ID.
  4. Select the same target team.
  5. Subscribe to Issue and Comment resources.
  6. Create/save the webhook.
  7. Open the webhook details and copy Linear's generated signing secret.

Do not paste the signing secret back into Linear. Linear already stores it; Denly needs a copy to verify the Linear-Signature header.

4. Put Linear's signing secret in Denly

Return to Workspace → Integrations, open the Linear connection menu, and choose Edit. Find Linear webhook signing secret, paste the signing secret copied from Linear, and select Save changes.

This replaces Denly's initial placeholder secret with the secret Linear actually uses to sign deliveries. The value belongs in Denly, not in the Linear URL field.

5. Test and troubleshoot
  1. Create or update a Linear issue in the connected team.
  2. Add the denly label.
  3. Open Workspace → Integrations → Linear → Recent events.

Processed creates a task; Skipped means the team, label, assignee or create rule declined it. An empty list means the Linear signing secret stored in Denly does not match the webhook's current one, so nothing is reaching the queue – if you regenerated or replaced the Linear webhook, paste the new secret into Denly again. Map exact Linear workflow-state names.

GitHub Issues

Import repository issues as Denly tasks and route them by GitHub assignee or a default member.

1. Create a GitHub token

In GitHub open Settings → Developer settings → Fine-grained personal access tokens. Create a repository-limited token named Denly, grant issue read/write and issue-comment write permissions, generate it, and copy it immediately. Read GitHub token documentation.

2. Create the Denly connection

Open Workspace → Integrations → Connect → GitHub Issues. Use owner/repository, GitHub’s API base URL, the token, trigger tag denly, and Plan first. Keep Trigger on create disabled initially.

Routing is optional. Leave Default Denly assignee blank for unassigned tasks, or choose one workspace member to own everything from this connection.

For per-person routing use Route by external assignee: each row pairs one person in the provider (left) with a workspace member (right), and + adds another row. Routing follows the item's assignee in the provider, not whoever created it, and a matching row beats the default above.

The left-hand value must be the identifier the provider actually sends, which the field's placeholder names for you. Matching ignores surrounding spaces and letter case, but nothing else: a near-miss routes nothing and looks the same as a broken integration.

3. Add the webhook

In the repository open Settings → Webhooks → Add webhook. Set the generated URL, choose application/json, paste the Denly inbound secret as the webhook secret, subscribe to Issues and Issue comments, save, and use Recent Deliveries → Redeliver for testing. Do not use the separate GitHub App lifecycle endpoint.

4. Test and troubleshoot

Open an issue and add denly. Check Recent events. Processed creates a task; Skipped means the repository, label, assignee or create rule declined it. An empty list means the webhook secret does not match, so X-Hub-Signature-256 never verified – GitHub's Recent Deliveries tab shows those attempts and can redeliver one. Comments containing #denly revise linked tasks.

GitLab Issues

Import GitLab issues and notes from GitLab.com or self-managed GitLab.

1. Create a GitLab token

In GitLab open User settings → Access tokens or create a project access token. Name it Denly, grant api, set an expiration, create it, and copy it immediately. Read GitLab access tokens.

2. Create the Denly connection

Open Workspace → Integrations → Connect → GitLab Issues. Use the full project path, such as group/platform/api, the GitLab HTTPS base URL, token, trigger label denly, and Plan first. Leave create disabled initially.

Routing is optional. Leave Default Denly assignee blank for unassigned tasks, or choose one workspace member to own everything from this connection.

For per-person routing use Route by external assignee: each row pairs one person in the provider (left) with a workspace member (right), and + adds another row. Routing follows the item's assignee in the provider, not whoever created it, and a matching row beats the default above.

The left-hand value must be the identifier the provider actually sends, which the field's placeholder names for you. Matching ignores surrounding spaces and letter case, but nothing else: a near-miss routes nothing and looks the same as a broken integration.

3. Add the webhook

In GitLab open Project → Settings → Webhooks. Paste the Denly URL and inbound secret into Secret token, enable Issues events and notes/comments, save, and run Test → Issues events. Self-managed GitLab must be publicly reachable over HTTPS.

4. Test and troubleshoot

Add denly to an issue and inspect Recent events. Processed creates a task; Skipped means the project, label, assignee or create rule declined it. An empty list means X-Gitlab-Token is wrong; GitLab's webhook page keeps its own delivery log. Notes containing #denly revise linked tasks.

Trello

Import Trello cards, synchronize comments and lists, and route by Trello member or default member.

1. Create Trello credentials

Open the Trello developer key page. Copy the API key, open the token link on that page, authorize and copy the token, and record the API secret for webhook signing.

2. Create the Denly connection

Open Workspace → Integrations → Connect → Trello. Use the board ID, API key, token, API secret, trigger label denly, and list-ID status mappings. Leave create disabled initially.

Routing is optional. Leave Default Denly assignee blank for unassigned tasks, or choose one workspace member to own everything from this connection.

For per-person routing use Route by external assignee: each row pairs one person in the provider (left) with a workspace member (right), and + adds another row. Routing follows the item's assignee in the provider, not whoever created it, and a matching row beats the default above.

The left-hand value must be the identifier the provider actually sends, which the field's placeholder names for you. Matching ignores surrounding spaces and letter case, but nothing else: a near-miss routes nothing and looks the same as a broken integration.

Trello signs the body plus the exact callback URL, so do not rewrite the generated URL.

3. Add the webhook

Create a board webhook using Trello’s webhook API. Set its callback URL to Denly’s generated URL, set the model to the board, and subscribe to card creation, updates/labels, and comments. Read Trello webhook documentation.

4. Test and troubleshoot

Create a card and add denly. Processed creates a task and Skipped means the label or create rule declined it. An empty list means the signature did not verify: Trello signs the body together with the exact callback URL, so the webhook's URL must be the generated one character for character – a trailing slash or an http/https difference is enough to fail. A tagged card comment becomes revision work.

Asana

Import Asana tasks using the webhook handshake and route by Asana assignee.

1. Create an Asana token

In Asana open the personal access-token area, create a token named Denly, copy it immediately, and confirm the account can read the target project. Read Asana personal access tokens.

2. Create the Denly connection

Open Workspace → Integrations → Connect → Asana. Use the workspace/project identifier, token, project scope, trigger tag denly, and Plan first. Leave create disabled initially.

Routing is optional. Leave Default Denly assignee blank for unassigned tasks, or choose one workspace member to own everything from this connection.

For per-person routing use Route by external assignee: each row pairs one person in the provider (left) with a workspace member (right), and + adds another row. Routing follows the item's assignee in the provider, not whoever created it, and a matching row beats the default above.

The left-hand value must be the identifier the provider actually sends, which the field's placeholder names for you. Matching ignores surrounding spaces and letter case, but nothing else: a near-miss routes nothing and looks the same as a broken integration.

Do not invent an inbound secret: Asana supplies X-Hook-Secret during registration and Denly stores it.

3. Register the webhook

Create an Asana webhook for the target project with Denly’s generated URL. Asana sends an X-Hook-Secret handshake; Denly echoes it and stores it. Only enable production events after the handshake succeeds. Read Asana webhooks.

4. Test and troubleshoot

Add denly to an Asana task or assign it to a mapped user. Asana's event carries little more than an ID, so Denly fetches the task before it can judge it. Skipped means the fetched tags, project, assignee or create rule declined it. Failed with a permission error means the token cannot read the task. An empty list means the handshake secret is stale – re-register the webhook so Asana sends a fresh one.

ClickUp

Import ClickUp tasks and comments, synchronize statuses and time entries, and route by ClickUp assignee.

1. Copy your ClickUp token

In ClickUp open Settings → Integrations & ClickApps → ClickUp API, and on the API tokens tab press Copy. Your personal token already exists – it starts pk_ – so there is nothing to create.

Use Regenerate only if you actually need a new token: it invalidates the current one and breaks every other integration already using it.

The token acts as you, so confirm that account can read the target list and post comments – Denly fetches each task with it. Read ClickUp authentication.

2. Create the Denly connection

Open Workspace → Integrations → Connect → ClickUp.

  • Project scope: the Denly project imported tasks land in.
  • External workspace or repository: your numeric Workspace (team) ID – the first number in any ClickUp URL, e.g. 90182959236. The same value is used to post time entries.
  • Personal API token: the token from step 1.
  • Limit to a ClickUp list ID: optional, and worth setting for a first test – see step 3.
  • Trigger tag: denly; keep Trigger on create disabled for the first test.
  • Initial Denly stage: Plan first. Enable Post worklogs to have Denly record time entries.

The tag is a ClickUp tag, not a custom field, and tags are per space – so the space you test in needs a denly tag. You can create it inline from the task's Tags menu.

Routing is optional. Leave Default Denly assignee blank for unassigned tasks, or choose one workspace member to own everything from this connection.

For per-person routing use Route by external assignee: each row pairs one person in the provider (left) with a workspace member (right), and + adds another row. Routing follows the item's assignee in the provider, not whoever created it, and a matching row beats the default above.

The left-hand value must be the identifier the provider actually sends, which the field's placeholder names for you. Matching ignores surrounding spaces and letter case, but nothing else: a near-miss routes nothing and looks the same as a broken integration.

3. The webhook registers itself

Nothing to do. ClickUp has no webhook screen – its webhooks exist only through its API – so Denly creates one for you when you save the connection, using the token from step 2. It subscribes to taskCreated, taskUpdated, taskTagUpdated, taskAssigneeUpdated and taskCommentPosted, stores the secret ClickUp mints, and names the webhook it created when it saves.

Scope it while testing: fill Limit to a ClickUp list ID in step 2 and the webhook is created against that list alone. Unscoped, it delivers every task event in the workspace, and ClickUp’s event is too thin to filter on, so each one costs a task fetch before Denly can drop it. The setting is read when the webhook is created, so it only appears while you are creating the connection – to change it later, recreate the connection.

If registration fails – usually a token without webhook scope – the connection is still created and the dialog says why, then shows the URL and secret to register by hand. You can then create the hook yourself and paste ClickUp’s secret into ClickUp webhook signing secret under Edit. Read ClickUp webhooks.

ClickUp sends a thin event carrying little more than a task ID; Denly then fetches the full task with the API token, which is why the token needs read access to the target list.

4. Test and troubleshoot

Create a ClickUp task, add the denly tag, and open Workspace → Integrations → Recent events.

  • Processed – it became a Denly task.
  • Skipped – expected, and usually not a fault. Trigger did not match after enrichment means the fetched task had no denly tag. Already linked means another event for the same task got there first.
  • Failed – the diagnostic column carries the provider's own error.

Creating an already-tagged task fires two events: taskCreated builds the task and taskTagUpdated then lands on it and is skipped as already linked. Two rows for one task is correct.

Nothing at all, and the card still on Awaiting first event, means deliveries are being rejected before the queue – the signing secret does not match. Recreate the connection so a fresh webhook is registered.

A comment containing #denly on a linked task becomes revision work.

monday.com

Import monday.com board items and updates and synchronize status columns.

1. Create monday credentials

In monday.com open the developer/API area, create or copy an API token for an account that can read and update the target board, and record the numeric board ID. Read monday authentication.

2. Create the Denly connection

Open Workspace → Integrations → Connect → monday.com. Use the board ID, API token, default GraphQL URL, trigger label or status value, and Plan first. Set Status column ID only if the board does not use monday's default status column.

Routing is optional. Leave Default Denly assignee blank for unassigned tasks, or choose one workspace member to own everything from this connection.

For per-person routing use Route by external assignee: each row pairs one person in the provider (left) with a workspace member (right), and + adds another row. Routing follows the item's assignee in the provider, not whoever created it, and a matching row beats the default above.

The left-hand value must be the identifier the provider actually sends, which the field's placeholder names for you. Matching ignores surrounding spaces and letter case, but nothing else: a near-miss routes nothing and looks the same as a broken integration.

3. Add the webhook

Create a board webhook. For monday’s built-in webhook append ?t=YOUR_INBOUND_SECRET to Denly’s URL. For a monday app, configure its signing secret and use JWT verification. Subscribe to item creation, column changes, and updates. Read monday webhooks.

4. Test and troubleshoot

Create an item, set its trigger status or label, or add an update containing #denly. Skipped means the status, label or create rule declined it. Failed on a transition usually means the status column ID is wrong – set it in Status column ID if the board does not use monday's default status column. An empty list means the URL token or JWT does not match.

Basecamp

Import Basecamp to-dos and tagged comments using a URL-token webhook.

1. Create Basecamp API access

Create a Basecamp 3 API client, authorize it for the target account, and obtain an OAuth access token. Record the account ID. Read Basecamp 3 API documentation.

2. Create the Denly connection

Open Workspace → Integrations → Connect → Basecamp. Use the account ID, OAuth token, HTTPS base URL if custom, and a #denly marker in to-do text. Basecamp has no label field, so the tag is matched in text.

Routing is optional. Leave Default Denly assignee blank for unassigned tasks, or choose one workspace member to own everything from this connection.

For per-person routing use Route by external assignee: each row pairs one person in the provider (left) with a workspace member (right), and + adds another row. Routing follows the item's assignee in the provider, not whoever created it, and a matching row beats the default above.

The left-hand value must be the identifier the provider actually sends, which the field's placeholder names for you. Matching ignores surrounding spaces and letter case, but nothing else: a near-miss routes nothing and looks the same as a broken integration.

3. Add the webhook

Create a Basecamp webhook for to-do and comment activity. Append ?t=YOUR_INBOUND_SECRET to the Denly URL and subscribe to to-do created/updated and comment-created events. Basecamp webhooks are unsigned; the URL token is the authentication.

4. Test and troubleshoot

Create a to-do containing #denly and inspect Recent events. Processed creates a task; Skipped means the marker or project scope declined it, or the to-do was already linked. An empty list means the URL token is wrong. Denly drops a retry it has already handled, which is correct and also leaves no row. Basecamp connections comment back; they do not move statuses or log time.

Team chat

Slack

Create tasks from /denly commands or reactions, route them by Slack user, and receive Denly notifications.

1. Create a Slack app

In Slack apps create an app. Copy its Signing Secret, create the /denly slash command, enable Event Subscriptions with reaction_added, and install the app to copy the bot token.

2. Create the Denly connection

Open Workspace → Integrations → Connect → Slack.

  • External workspace or repository: the Slack team ID.
  • Bot token: the token from installing the app.
  • Slack signing secret: the Signing Secret from step 1. This is what every request is verified against – the secret Denly generates is unused for Slack, so a connection without it rejects everything.
  • Slash-command aliases: /denly. Optionally set a Reaction trigger (robot_face by default) and map channels to projects.

Routing is optional. Leave Default Denly assignee blank for unassigned tasks, or choose one workspace member to own everything from this connection.

For per-person routing use Route by external assignee: each row pairs one person in the provider (left) with a workspace member (right), and + adds another row. Routing follows the item's assignee in the provider, not whoever created it, and a matching row beats the default above.

The left-hand value must be the identifier the provider actually sends, which the field's placeholder names for you. Matching ignores surrounding spaces and letter case, but nothing else: a near-miss routes nothing and looks the same as a broken integration.

Map keys are Slack member IDs (U012ABCDEF), which is what command and reaction payloads carry – not display names.

3. Configure Slack URLs
  1. Set the slash-command Request URL to Denly’s generated URL.
  2. Set the Events API Request URL to the same URL.
  3. Subscribe to reaction_added.
  4. Grant channel read permissions for reaction enrichment and chat:write for notifications.

Read Slack request verification.

4. Test and troubleshoot

Run /denly fix the failing test in a mapped channel or add the configured reaction. Processed creates a task; Skipped means the command, reaction, channel or project mapping did not match. Failed on a reaction usually means the bot cannot read the message it was added to. An empty list means the Signing Secret does not match.

Microsoft Teams

Create tasks from Teams outgoing-webhook commands and route them by Teams sender.

1. Create the Denly connection

This comes first: the Teams outgoing webhook needs a callback URL, and Denly only generates that once the connection exists.

Open Workspace → Integrations → Connect → Microsoft Teams. Fill in the team or conversation ID, the Workflow webhook URL Denly posts its cards to, the command alias, and the project scope. Leave Teams outgoing-webhook secret blank for now – Teams has not generated it yet.

Routing is optional. Leave Default Denly assignee blank for unassigned tasks, or choose one workspace member to own everything from this connection.

For per-person routing use Route by external assignee: each row pairs one person in the provider (left) with a workspace member (right), and + adds another row. Routing follows the item's assignee in the provider, not whoever created it, and a matching row beats the default above.

The left-hand value must be the identifier the provider actually sends, which the field's placeholder names for you. Matching ignores surrounding spaces and letter case, but nothing else: a near-miss routes nothing and looks the same as a broken integration.

Save, then copy the generated Webhook URL.

2. Create the Teams outgoing webhook

Add an outgoing webhook to the target team, name it Denly, and set its callback URL to the Denly URL you just copied. Teams generates a base64 security token and shows it once.

Return to Workspace → Integrations → Microsoft Teams → Edit and paste it into Teams outgoing-webhook secret. Teams signs every request with it, so nothing arrives until this is stored – the secret Denly generated is unused here. Read Teams outgoing webhooks.

3. Send the command

Mention the outgoing webhook with /denly followed by the task text. Teams signs requests as Authorization: HMAC <base64-signature>. Denly must be publicly reachable over HTTPS.

4. Test and troubleshoot

Processed means Denly created the task and answered Teams; Skipped means the command, conversation or project mapping did not match. An empty list means the base64 Teams secret is wrong, so no request from Teams ever verifies.

Discord

Create tasks from Discord slash commands and route them by Discord user ID.

1. Create a Discord application

In the Discord Developer Portal create an application and collect three values:

  • Application ID and Public Key – both on General Information.
  • Bot token – on the Bot tab (Reset Token shows it once). It is only used to register the command in step 2; Denly never stores it.

Then invite the application to the target server with an OAuth2 URL that carries the applications.commands scope:

https://discord.com/oauth2/authorize?client_id=<APPLICATION_ID>&scope=applications.commands
2. Register the slash command

Unlike Slack, the Developer Portal has no screen for slash commands – they are registered against the Discord API with the bot token. Register /denly for one server (appears instantly; best while testing):

curl -X POST "https://discord.com/api/v10/applications/<APPLICATION_ID>/guilds/<SERVER_ID>/commands" \
  -H "Authorization: Bot <BOT_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"name":"denly","description":"Send a task to the Denly agent","options":[{"type":3,"name":"task","description":"What should the agent do?","required":true}]}'

Two details are load-bearing: the option must be named task (or text) – that is the field Denly reads the request from – and the command name must match the command alias you enter on the connection in step 3. For all servers at once, drop /guilds/<SERVER_ID> from the URL; global commands can take up to an hour to appear. Read Discord application commands.

3. Create the Denly connection

Open Workspace → Integrations → Connect → Discord. Use the server/channel ID, the application Public Key from step 1 (Discord signs every request with Ed25519 against it – Denly holds no Discord secret), a channel webhook URL for outbound notification cards (Channel settings → Integrations → Webhooks), the command alias (/denly – must match the name registered in step 2), and the channel/project mapping.

Routing is optional. Leave Default Denly assignee blank for unassigned tasks, or choose one workspace member to own everything from this connection.

For per-person routing use Route by external assignee: each row pairs one person in the provider (left) with a workspace member (right), and + adds another row. Routing follows the item's assignee in the provider, not whoever created it, and a matching row beats the default above.

The left-hand value must be the identifier the provider actually sends, which the field's placeholder names for you. Matching ignores surrounding spaces and letter case, but nothing else: a near-miss routes nothing and looks the same as a broken integration.

Map keys are Discord user IDs – the numeric ID from right-click → Copy User ID (Developer Mode), belonging to whoever runs the command.

Save, then copy the generated Webhook URL for the next step. The inbound secret Denly generates alongside it is unused for Discord – every request is verified against the Public Key instead – so you can ignore it.

4. Configure interactions
  1. Open the Discord application’s General Information → Interactions Endpoint URL.
  2. Paste Denly’s generated URL.
  3. Discord sends a signed type-1 PING; Denly answers it, and Discord accepts the endpoint. If Discord rejects it, the Public Key on the connection does not match the application.
  4. Save.

Read Discord interactions.

5. Test and troubleshoot

In a mapped channel run /denly task: fix the failing test. Processed creates the task and answers with an ephemeral acknowledgement; Skipped means the command name, channel or project mapping did not match. An empty list means the Public Key does not match the application. If Discord shows “the application did not respond”, the interactions endpoint is not reachable or not saved. Discord reactions are not supported – reactions arrive only over a persistent gateway connection, which Denly deliberately does not hold; commands are the supported path.

Mattermost

Create tasks from Mattermost slash commands and route them by Mattermost user.

1. Create the Mattermost slash command

In Mattermost open Integrations → Slash Commands → Add Slash Command. Choose the team, set trigger denly, set the Request URL to Denly’s generated URL, and copy the generated command token. Read Mattermost integrations.

2. Create the Denly connection

Open Workspace → Integrations → Connect → Mattermost. Use the team or server ID, the incoming webhook URL for notifications, the command alias, and the channel-to-project mapping. Paste the token from step 1 into Mattermost command token – every command is verified against it, and the secret Denly generates is unused here.

Routing is optional. Leave Default Denly assignee blank for unassigned tasks, or choose one workspace member to own everything from this connection.

For per-person routing use Route by external assignee: each row pairs one person in the provider (left) with a workspace member (right), and + adds another row. Routing follows the item's assignee in the provider, not whoever created it, and a matching row beats the default above.

The left-hand value must be the identifier the provider actually sends, which the field's placeholder names for you. Matching ignores surrounding spaces and letter case, but nothing else: a near-miss routes nothing and looks the same as a broken integration.

Map keys can be Mattermost user IDs or usernames: the payload carries both, and Denly tries each.

3. Verify the request

Save the command and run /denly fix the failing test. Mattermost sends the command token in the form body. Keep Denly on a public HTTPS URL.

4. Test and troubleshoot

Processed means Denly created the task and replied in the channel; Skipped means the command, project mapping or message text did not match. An empty list means the command token stored in Denly is not the one Mattermost generated.

Telegram

Create tasks from Telegram bot commands and route them by Telegram sender.

1. Create a Telegram bot

In Telegram open @BotFather, run /newbot, choose the bot name and username, copy the bot token, and add the bot to the target chat. Read Telegram Bot API.

2. Create the Denly connection

Open Workspace → Integrations → Connect → Telegram. Use the bot/chat identifier, bot token, command alias /denly, chat/project mapping, and optional notification chat ID.

Routing is optional. Leave Default Denly assignee blank for unassigned tasks, or choose one workspace member to own everything from this connection.

For per-person routing use Route by external assignee: each row pairs one person in the provider (left) with a workspace member (right), and + adds another row. Routing follows the item's assignee in the provider, not whoever created it, and a matching row beats the default above.

The left-hand value must be the identifier the provider actually sends, which the field's placeholder names for you. Matching ignores surrounding spaces and letter case, but nothing else: a near-miss routes nothing and looks the same as a broken integration.

Map keys are numeric Telegram user IDs – Telegram sends the sender's numeric ID with every command, so a username will not match. Each person can get their ID by messaging @userinfobot in Telegram.

3. Register the Telegram webhook

Call Telegram’s setWebhook method with the generated URL and secret:

https://api.telegram.org/bot<BOT_TOKEN>/setWebhook?url=https://your-public-host/integrations/telegram/webhook/YOUR_CONNECTION_ID&secret_token=YOUR_INBOUND_SECRET
  1. Replace the bot token, connection ID, and secret.
  2. Run the request once.
  3. Confirm ok: true.
4. Test and troubleshoot

Send /denly fix the failing test. Processed creates the task; Skipped means the command, chat or project mapping did not match. An empty list means X-Telegram-Bot-Api-Secret-Token does not match the secret given to setWebhook.