Integrate airfocus with Webhooks

Written by:  Morgan T
Last updated:  

Get automatic, real-time updates from airfocus by connecting your favorite apps using our Webhooks.

Benefits of using webhooks

Webhooks let airfocus and other apps work together easily and in real-time. This means updates and notifications happen quickly without needing extra apps or complicated coding.

Initial setup of a new webhook

Create a new workspace in airfocus, or select the one you would like to create a new webhook in.

Requirements:

  • “Full” permissions to the workspace in which you want to set up the webhook.
  • Paid subscription to Professional or Enterprise plan.
  • Technical knowledge for proper configuration.

You can add multiple webhooks to a given workspace (e.g. to different Slack channels for different stakeholder audiences).

To do that, simply go to the Extensions section within your workspace, click on "Add integrations" and "Connect" under Webhook.

integrate-with-webhooks-1.png

integrate-with-webhooks-2.png

Next, give your webhook a name (optional) and select which events the requests should be triggered for.

integrate-with-webhooks-3.png

In the request options, choose the placeholder format, and method and paste your webhook URL into the URL field. You can also add headers to your requests if needed.

integrate-with-webhooks-4.png

Optionally you can also configure your request's body in the placeholder format chosen above.

{
"blocks": [
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "{{title|esc}}"
},
"accessory": {
"type": "button",
"text": {
"type": "plain_text",
"text": "Open in airfocus",
"emoji": true
},
"value": "click_me_123",
"url": "{{url}}",
"action_id": "button-action"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "{{details|esc}}"
}
}
]
}

For detailed documentation of customization options for your webhooks please read the following section.

Use case - receive Slack notifications for airfocus updates

For this use case, our goal is to configure a webhook that will send a Slack message to a channel of our choice every time an item of the workspace we configure the webhook for gets its status updated.

To do so, we need to set up a Slack app to generate a webhook URL and then configure the rest of the integration in airfocus.

How to create a webhook URL to your Slack channel:

  1. Create a new Slack app in the Slack workspace where you want to receive the airfocus notifications.
    integrate-with-webhooks-5.png
    integrate-with-webhooks-6.png
  2. From the Features page, turn on the Activate Incoming Webhooks option.
    integrate-with-webhooks-7.png
  3. Click Add New Webhook to Workspace.
    integrate-with-webhooks-8.png
  4. Pick a channel that the app will post to, then click Allow.
    integrate-with-webhooks-9.png
  5. Copy the webhook URL and open the airfocus workspace for which you want to setup the updates.
    integrate-with-webhooks-9.1.png

How to configure your webhook in airfocus to send event update notifications to Slack:

  1. In the extensions popover, click on “Add integrations”.
    integrate-with-webhooks-10.png
  2. On the integrations overview, click on “Connect” underneath the “Webhooks” integration.
    integrate-with-webhooks-11.png
  3. Give your webhook a name (optional) and select which events the requests should be triggered for. → “Status updated” for this use case.
    integrate-with-webhooks-12.png
  4. In the request options, select “Slack markdown” as the placeholder format and “POST” as the method. Now paste the webhook URL you copied from Slack into the URL field.
    integrate-with-webhooks-13.png
  5. To receive properly formatted Slack messages, paste the following template into the body field and press update.
    •  

      {
      "blocks": [
      {
      "type": "divider"
      },
      {
      "type": "section",
      "text": {
      "type": "mrkdwn",
      "text": "{{title|esc}}"
      },
      "accessory": {
      "type": "button",
      "text": {
      "type": "plain_text",
      "text": "Open in airfocus",
      "emoji": true
      },
      "value": "click_me_123",
      "url": "{{url}}",
      "action_id": "button-action"
      }
      },
      {
      "type": "section",
      "text": {
      "type": "mrkdwn",
      "text": "{{details|esc}}"
      }
      }
      ]
      }

       

  6. You will now receive a Slack message to the channel you chose when any item in the workspace has its Status changed.
    integrate-with-webhooks-14.png

Get airfocus updates in Microsoft Teams

Note: The Microsoft Teams webhook connector feature is being deprecated at the end of April 2026. The guide below includes steps for how to use the Workflows feature as an alternative.

The Microsoft Teams Workflows feature allows you to configure a webhook that sends a Teams message to a designated channel when items within a particular airfocus workspace are updated. To do this, you’ll need to generate a webhook URL on Microsoft Teams and then configure the rest of the integration in airfocus.

Create a webhook URL in Microsoft Teams

To generate a webhook URL in Microsoft Teams, follow these steps:

  1. Log in to Microsoft Teams.
  2. Click the three-dot menu in the navigation menu on the far left side.
  3. Select Workflows.
  4. In the search bar, search “webhook”.
  5. Select Post to a channel when a webhook request is received.
  6. Type a name for your workflow (e.g., "Airfocus updates").
  7. Click Next.
  8. Under “Details”, select the specific Team and Channel where you want the updates to appear.
  9. Click Add workflow.
  10. On the confirmation screen, copy the POST URL.
    • This is the webhook URL you will need to paste into airfocus.
  11. Click Done to finalize the setup.

Configure your webhook in airfocus

To configure your webhook in airfocus, follow these steps:

  1. Open the airfocus workspace for which you want to send updates to Microsoft Teams.
  2. Click Extensions from the top-right corner of the workspace.
  3. Select Add integrations.
  4. Under “Webhooks”, click Connect.
  5. Type a name for the webhook.
  6. Under “Events”, select what type of updates you want to be sent to Microsoft Teams.
  7. Under “Placeholder format”, select Markdown.
  8. Under “Method”, select POST then paste the URL you generated in Microsoft Teams under “URL”.
  9. Select + Add header.
  10. Under “Header name”, type “Content-Type”.
  11. Under “Header value”, type “application/json”.
    example-webhookd-form-filled-out-in-airfocus.png
  12. To receive properly formatted Microsoft Teams messages, paste the following template into the body field.
    • {
        "type": "AdaptiveCard",
        "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
        "version": "1.4",
        "body": [
          {
            "type": "TextBlock",
            "text": "{{title}}",
            "size": "Medium",
            "weight": "Bolder",
            "wrap": true
          },
          {
            "type": "TextBlock",
            "text": "{{details}}",
            "wrap": true
          }
        ],
        "actions": [
          {
            "type": "Action.OpenUrl",
            "title": "Open in airfocus",
            "url": "{{url}}"
          }
        ]
      }
  13. Click Update from the bottom-right of the page.

You’ll now receive updates to the Microsoft Teams channel you set up in the first section.
 

Configuring HTTP request - technical documentation

Method

It’s set to POST by default, but can be changed also to GET or PUT. Other methods are not supported.

URL

  • should not be empty
  • can only start with https:// (other schemes or empty scheme is not supported)
  • should have a public domain name with a well-known top-level-domain (IPs are not supported)

Headers

  • Authorization is supported
  • Content-Type is supported
  • custom headers which start with x- are supported
  • any other headers are not supported

Body

Defines a request body of the webhook.

Can contain any text up to 2000 characters long.

In order to fill out the request body with meaningful event-data, we provide a bunch of placeholders which our server replaces with event-data before sending the request.

Placeholder format

Specifies how the placeholders with RichText type should be pre-rendered by our server. For example {{title}} placeholder can contain a string like “John updated field Labels on item Fix the button” which contains some rich-text formatting like bold, italic, etc, and therefore the placeholder format specifies in which specific syntax this formatting should be transformed. Available formats:

Name Description Example
markdown default markdown John updated field Labels on item Fix the button
html <b>John</b> updated field <i>Labels</i> on item <b>Fix the button</b>
text formatting removed John updated field Labels on item Fix the button
slack special Slack mrkdwn *John* updated field *Labels* on item *Fix the button*

Placeholders

Placeholder Type Description Example
{{type}} String type of event updatedItem
{{title}} String (RichText) describes event action John updated field Labels on item Fix the button
{{details}} String (RichText) additional event details (e.g. what was changed) Old value ⇒ New value
{{url}} String call-to-action URL for each specific event (e.g. a link to a workspace or an item) https://myteam.airfocus.com/w/workspaceId?item=itemId 
*replace airfocus.com with airfocus.app if you are located in the US or APAC region and your account was created after September 2025
{{event}} JSON full JSON data about the current event See the Event Payload Model below
{{title|esc}} String (RichText) same as {{title}} but all double quotes are escaped transforms string with "double" quotes into string with \"double\" quotes
{{details|esc}} String (RichText) same as {{details}} but all double quotes are escaped transforms string with "double" quotes into string with \"double\" quotes

Data Models

Event Payload Model

A top level object, produced for each event. It contains data about the event as well as embedded basic data about all entities which are related to this event.

Field Type Required Description
event Event yes basic data about the event
embed EventEmbed yes additional data about the event - mostly names of items/workspaces/fields/etc which are related to this event
matchedFilter EventFilter yes one of the event-filters selected in the integration settings, which matched the current event

Event Model

Basic data about the event

Field Type Required Description
id UUID yes unique ID of the event
initiator EventInitiator yes information about who initiated this event
data EventData yes the actual data of the event. It’s different per each specific event-type
createdAt timestamp yes when the event has happened

EventInitiator Model

Information about who initiated this event. In most cases the userId will be defined. It’s also possible that there will be both userId and integrationId defined - e.g. if a user pressed the “synchronise integration” button which then produced the event.

Field Type Required Description
userId UUID no defined if this event was initiated by a user
appId UUID no defined if this event was initiated by an app
integrationId UUID no defined if this event was initiated by an integration
eventId UUID no defined if this event was initiated by another event
requestId UUID no defined if this event was initiated inside an HTTP request

EventEmbed Model

Additional data about the event - mostly names of items/workspaces/fields/etc which are related to this event.

Field Type Required Description
teams {UUID: TeamInfo} no a hash-map of team IDs to team data
users {UUID: UserInfo} no a hash-map of user IDs to user data
apps {UUID: AppInfo} no a hash-map of app IDs to app data
workspaces {UUID: WorkspaceInfo} no a hash-map of workspace IDs to workspace data
integrations {UUID: IntegrationInfo} no a hash-map of integration IDs to integration data
fields {UUID: FieldInfo} no a hash-map of field IDs to field data
statuses {UUID: StatusInfo} no a hash-map of status IDs to status data
items {UUID: ItemInfo} no a hash-map of item IDs to item data

TeamInfo Model

Field Type Required Description
name String yes team name
slug String yes team URL slug
baseUrl String yes example: https://myteam.airfocus.com 
*replace airfocus.com with airfocus.app if you are located in the US or APAC region and your account was created after September 2025

UserInfo Model

Field Type Required Description
teamId UUID yes ID of the team this user belongs to
fullName String yes user’s full name

AppInfo Model

Field Type Required Description
teamId UUID yes ID of the team this app belongs to
typeId String yes one of: forms, insights, mirror, portal, prioritization

WorkspaceInfo Model

Field Type Required Description
teamId UUID yes ID of the team this workspace belongs to
name String yes workspace name

IntegrationInfo Model

Field Type Required Description
workspaceId UUID yes ID of the workspace this integration belongs to
typeId String yes one of: asana, azure-devops, clubhouse, github, intercom, jira, planner, trello

StatusInfo Model

Field Type Required Description
workspaceId UUID yes ID of the workspace this status belongs to
name String yes name of the status
category String yes one of: draft, active, closed

ItemInfo Model

Field Type Required Description
workspaceId UUID yes ID of the workspace this item belongs to
statusId UUID yes ID of the item’s status
name String yes item’s name

EventData Model

EventData is a union type - it can either of the specified types:

CreatedItem

Field Type Required Description
itemId UUID yes id of the created item

UpdatedItem

Field Type Required Description
itemId UUID yes id of the updated item
status {prev: UUID, next: UUID} no old and new IDs of the status (if changed)
color {prev: String, next: String} no old and new IDs of the item colour (if changed)
assigneeUserIds {prev: UUID[], next: UUID[]} no old and new list of assigned user IDs (if changed)
name {prev: String, next: String} no old and new item name (if changed)
description {prev: RichText, next: RichText} no old and new item description (if changed)
description { UUID: { prev: JSON, next: JSON } } no a hash-map of field-ids to their changed values each value is some JSON which depends of the field-type
archived {prev: Boolean, next: Boolean} no old and new archived (if changed)

Give feedback on this article

Have feedback about this article? Tell us about your experience here.

Did you find what you were looking for?

Still have a question or want to share what you have learned? Visit our Community   to get help and collaborate with others.