Let's build something great together

When you build integrations with ActiveCampaign, you can have a positive impact on small businesses across the world. This is where you can find ActiveCampaign API documentation, SDKs, support, and a community of developers like you.

Get Started    

Configuration Walkthrough

πŸ‘

Tip

We recommend starting with the Example Configuration and substituting out CHANGEMEs with desired values to get a fully working config.

The configuration JSON file contains 4 parts: auth, api, dataintake, & workflows. In this guide, we will go over those sections in that order.

AUTH

The auth section of the config file defines how a user connects to an integration. This must be set up correctly for the rest of the config to work. See more detailed examples and explanation in the Configuration Specification AUTH section.

Currently we support these auth types:

An example OAuth2 configuration looks like this:

{
  "auth": {
    "my_oauth2_configuration": {
      "type": "oauth2",
      "configuration": {
        "authorization_base_url": "https://api.example.com/oauth2/authorize",
        "client_id": "woef2qo3hefawWEWrfh2qe21wlvdflkefnqs",
        "client_secret": "[insert your secret here]",
        "scopes": [
          "insert_scope_here_if_needed"
        ],
        "token_url": "https://api.example.com/oauth/token",
        "refresh_url": "https://api.example.com/oauth/authorize"
      }
    }
  }
}

API

The api section of the config file defines the API used in an integration. It has two sub-sections: base_url and pagination. See more detailed examples and explanation in the Configuration Specification API section.

base url

This is the base url for all API calls. Example:
"base_url": "https://api.example.com"

pagination

Some API responses are paginated, this section configures the integration to handle such responses. Remove this section if you don't need to support pagination.

Currently, we support three types of pagination: page, limitoffset or cursor. Please see the examples for each style below and choose the style that works for your API.

"pagination": {
  "style": {
    "type": "page",
     "page_number": {
       "param": "page",
       "value": 1
     },
     "page_size": {
       "param": "pageSize",
       "value": 50
     },
     "extra": {
       "param": "ordering",
       "value": "desc"
     }
  },
  "parser": {
    "total_pages": {
      "!jq": "page_count"
    }
  }
}

The above configuration will support a url that looks like:
https://api.example.com/my-endpoint/?page=1

πŸ“˜

Note

  • The β€œvalue” field represents the starting page number. It defaults to 1.
  • The β€œextra” section provides support for any custom params allowed in the API url such as filtering, ordering, etc. For example, if the url is https://api.example.com/my-endpoint/?page=1&ordering=desc, use "extra": [{"param": "ordering", "value": "desc"}]" You can remove this if you prefer to use default settings for the api.
"pagination": {
  "style": {
    "type": "limitoffset",
    "limit": {
      "param": "limit", 
      "value": 50
    },
    "offset": {
      "param": "offset", 
      "value": 0
    }
  },
  "parser": {
    "total_items": {
      "!jq": "total_items"
    }
  }
}

The configuration above will support an API endpoint that looks like this:
https://api.example.com/my-endpoint/?offset=0&limit=50

πŸ“˜

Note

These values have defaults but can be changed.

  • In the offset sub-section, "value" represents the starting index of data, this value should be changed if the data is not 0-indexed.
  • In the limit sub-section, "value" refers to the number of records that should be fetched each API call. The range of this value is dictated by the API endpoint.
  • An "extra" section can be added much in the same way as in page.
"pagination": {
  "style": {
    "type": "cursor",
    "limit": {
      "param": "limit",
      "value": 50
    },
    "ordering": {
        "param": "sort",
        "value": "age"
    }
  },
  "parser": {
    "next_result_token": {
      "!jq": "next_cursor"
    }
  }
}

The configuration above will support an API endpoint that looks like this:
https://api.example.com/my-endpoint/limit=50&sort=age

πŸ“˜

Info

  • In the limit sub-section, "value" refers to the number of records that should be fetched each API call. The range of this value is dictated by the API endpoint.
  • In the ordering sub-section, the "value" refers to the filter specified to order the results. The parameter name and ordering criteria are dictated by the API endpoint.
  • We also support 2 types of parsers to parse the response you receive from the API: previous_result_token - to parse the token needed to fetch previous page results and next_result_token - to parse the token needed to get next page results. The parameter names might vary depending on the API.

DATAINTAKE (INBOUND ONLY)

This section contains a list of data_intakes.
A data_intake can have 6 fields: name, type, scope, create, update, delete.
Each configuration file may contain one or more data_intakes, each dedicated to a different task. See more detailed examples and explanation in the Configuration Specification Data Intake section.

name

The unique identifier of a data_intake, we recommend using the publisher APIs event notification approach name. Example:
"name": "form_webhook"

type

Defines the data_intake type i.e., the event notification capability used by a publisher API to send data to ActiveCampaign. For further information, please see data_intake type values

scope

The scope defines the level of the webhook. For further information, please see data_intake scope values

create

To collect user submissions data and to convert it to data in ActiveCampaign, the integration needs to subscribe to a data stream by creating a webhook. The data flow from a resource to ActiveCampaign is controlled by a toggle in the UI:

"create": {
    "!http": {
      "body": {
        "enabled": true,
        "url": "${webhook::url}"
      },
      "method": "PUT",
      "path": "CHANGEME"
    }
  }

update (optional)

The update step defines how to update the webhooks when an external resource that is already subscribed to in ActiveCampaign is updated on the 3rd party application end. The associated webhook may need to be updated to continue receiving data. It is optional and depends on the publisher API definition.

"update": {
    "!pipe": [
      {
        "!http": {
          "method": "GET",
          "path": "CHANGEME"
        }
      },
      {
        "!jq": "CHANGEME"
      },
      {
        "!save": {"scope": "CHANGEME"}
      }
    ]
  }

The !save command allows the publisher to save data related to a subscribed resource for future reference.

delete

The delete step defines how to remove previously created webhooks to stop receiving unneeded user submissions data.

"delete": {
    "!http": {
      "method": "DELETE",
      "path": "CHANGEME"
    }
  }

WORKFLOWS

This section contains a list of workflows.
Each workflow has 6 fields: name, description, label, type, data_pipeline, setup.
Each configuration file may contain one or more workflows, each dedicated to a different task.

When discovered, they will be shown next to each other:

name

The unique identifier of this workflow, we recommend using the slug of "label" (see below). Example:
"name": "create-a-contact"

description

A short and clear description of the workflow:
"description": "Sync newly created contacts from ActiveCampaign to XYZ"

label

The visible name of this workflow. Example:
"label": "Create a Contact"

type

Declaring the workflow type is a way to associate the integration to a specific component in ActiveCampaign's system so users can easily discover your integration(s). For further information, please see workflow type values

setup

This section is where you can define a guided experience for users.

You can add supported "steps" in the guided experience. Typically, it consists of 2 or more of these steps:

  • connect
  • select
  • map

connect

This step allows the user to connect to the integration through OAuth.
When you include this step in your setup, our integration layer will handle the OAuth logic, and provide the UI for this, but you still need to define the following fields:

"connect": {
  "label": "Connect",
  "describe_connection": {
    "!pipe": [
      {
        "!http": {
          "method": "GET",
          "path": "CHANGEME"
        }
      },
      {
        "!jq": "CHANGEME"
      }
    ]
  }

"describe_connection" is specific to the "connect" step, it provides information about the currently connected user.

This information is normally obtained from the publisher via an api call, and the response is manipulated into a desired format via jq. As a result, the run sub section will contain two commands: !http and !jq.

Consider the following:

{
  "label": "Connect",
  "describe_connection": {
    "!pipe": [
      {
        "!http": {
          "method": "GET",
          "path": "/me"
        }
      },
      {
        "!jq": "{account_id: .id, description: (.name + \" - \" + .email), image_url: .picture}"
      }
    ]
}

Example Breakdown:
Two commands are chained by !pipe to complete the "describe_connection" action:

"!pipe": [
    {
      "!http": { ... }
    },
    {
      "!jq": ...
    }
]

The first command makes an API call to get account info from https://api.example-integration.com/me/

{
  "!http": {
    "method": "GET",
    "path": "/me"
  }
}

The second command transforms data to a desired format that ActiveCampaign can use.

{
  "!jq": "{account_id: .id, description: (.name + \" - \" + .email), image_url: .picture}"
}

If the response from https://api.example-integration.com/me/ looks like:

{
  "alias": "Perrin Aybara",
  "email": "[email protected]",
  "picture": "https://cdn.example.com/photo123"
}

It will be converted by the jq command to support the UI element:

{
  "account_id": "[email protected]",
  "description": "Perrin Aybara - [email protected]",
  "image_url": "https://cdn.example.com/photo123"
}

select

The select step allows users to select which external resource is used to sync data. For example, if an integration syncs changes within ActiveCampaign to Google Sheets, users can specify which sheet to send data to in this step.

You can have one of more form fields to allow users to pin-point their desired external resource. See the form fields section of the Workflow specification for information on how to set up the different types of form fields.

The data powers this portion of the UI:

The dropdowns in screenshot above are defined through form_fields, see example below:

{
  "label": "Select",
  "form_fields": [
    {
      "label": "Folder",
      "id": "folder",
      "type": "dropdown",
      "placeholder": "Select Folder",
      "options": {
        "!pipe": [
          {
            "!http": {
              "method": "GET",
              "path": "/folders/"
            }
          },
          {
            "!jq": "[.folders[] | {display: .name, value: .id}]"
          }
        ]
      }
    },
    {
      "label": "File",
      "id": "file",
      "type": "dropdown",
      "placeholder": "Select File",
      "options": {
        "!pipe": [
          {
            "!http": {
              "method": "GET",
              "path": "/folders/${custom_data::folder.value}/files"
            }
          },
          {
            "!jq": "[.files[] | {display: .file_info.name, value: .file_info.id}]"
          }
        ]
      }
    }
  ]
}

The integration needs data to support options for a form field.

In this example, data for options are pulled in using piped commands. A piped command is a chain of developer commands that achieve a goal together. Read more about commands and piped commands here.

The piped command for the first dropdown will make an API call to https://api.example-integration.com/folders/, which might return:

{
    "folders": [
        {
            "id": "1",
            "name": "Folder 1",
        },
        {
            "id": "2",
            "name": "Folder 2",
        },
    ]
}

The jq expression will transform the response above into the following to render the first dropdown list:

[
  {
    "display": "Folder 1",
    "value": "1"
  },
  {
    "name": "Folder 2",
    "value": "2"
  }
]

Once the user selects a folder in the first drop down, their selection can be referenced via the "custom_data" shortcut.

${custom_data::ID.ATTRIBUTE}

For example, if the user selected the first folder, the expression below would evaluate to "Folder 1":

${custom_data::folder.display}

As shown in this example, once the folder is selected, it can be used in a subsequent dropdown to list available files.

map

The map step allows users to define mapping information so data between the integration and ActiveCampaign are transformed properly. The source determines where data is coming from, where as the target determines where the mapped data will end up. For instance, if you'd like data from ActiveCampaign to go to a third party service, you'd most likely want to use a !resource command for source, and a !pipe command that make an http request to the third party service for target. In the case of fields that would be unchanging or which don't have a endpoint to define them you can provide a static list.

Example inbound mapping configuration :

{
   "label":"Mapping",
   "describe_source":{
      "label":"Example Inbound Integration",
      "options":{
         "!pipe":[
            {
               "!http":{
                  "method":"GET",
                  "path":"/forms/${resource::id}"
               }
            },
            {
               "!jq":"[.fields[]|{title, id, type}]"
            }
         ]
      }
   },
   "describe_target":{
      "label":"ActiveCampaign",
      "options":{
         "!resource":"ActiveCampaignContact.fields"
      }
   }
}

Example outbound mapping configuration :

{
  "label": "Mapping",
  "describe_source": {
    "label": "ActiveCampaign",
    "options": {
      "!resource": "ActiveCampaignContact.fields"
    }
  },
  "describe_target": {
    "label": "Example Outbound Integration",
    "options": {
      "!pipe": [
        {
          "!http": {
            "method": "GET",
            "path": "/contact/fields"
          }
        },
        {
          "!jq": ".fields[] | {display: .title, value: .id}"
        }
      ]
    }
  }
}

The describe_source section defines how to populate available data fields of the source. In this case, we are pulling fields available for a contact from ActiveCampaign.
They are in the following format:

[
  {
    "id": "email", "title": "Email"
  },
  {
    "id": "firstName", "title": "First Name"
  },
  {
    "id": "lastName", "title": "Last Name"
  }
]

The describe_target section defines how to populate available fields for the external data source.

Suppose "https://api.example-integration.com/contact/fields" returns the following definition:

{
    "fields": [
        {
            "field": "field1",
            "label": "Contact Email"
        },
        {
            "field": "field2",
            "label": "Contact First Name"
        },
        {
            "field": "field3",
            "label": "Contact Last Name"
        }
    ]
}

The jq command converts this payload to a desired format to support the UI:

[
  {
    "title": "Contact Email",
    "id": "field1"
  },
  {
    "title": "Contact First Name",
    "id": "field2"
  },
  {
    "title": "Contact Last Name",
    "id": "field3"
  }
]

After setting mapping info from the UI, the following data will be saved for future data processing:

{
  "email": "field1",
  "firstName": "field2",
  "lastName": "field3"
}

Each key in the object is the value of a field in the source and is mapped to the corresponding value field in target.

data_pipeline

A data_pipeline makes sure data from the source arrives at the target in the correct format. The source and target sections handle the input and output of the data pipeline respectively.

Typically it is expected to see a mapping step before a data_pipeline so that users are able to choose which fields they want to send or receive, and so they can choose where inbound or outbound data ends up at rest. We want to ensure that only meaningful data is sent with the integration. This is especially true when sending data from ActiveCampaign to any third party. Also, keep in mind that some ActiveCampaignContact records can have hundreds, even thousands of fields.

Example inbound data_pipeline configuration - to sync data from a third party to ActiveCampaign such as Unbounce, you can define the source as:

{
  "source": {
    "!jq": ".data | [.[] | {name: .attributes.name, id: .id}]"
  },
  "target": {
    "!resource": "ActiveCampaignContact"
  }
}

The !jq command extracts the required data from the incoming payload and saves it in a format that ActiveCampaign can understand. This data will be passed as input to the "target" section to create a contact in ActiveCampaign.

Example outbound data_pipeline configuration - to sync data from ActiveCampaign to a third party such as Google sheets, you can define the source as:

{
  "source": {
    "!resource": "ActiveCampaignContact"
  },
  "target": {
    "!pipe": [
      {
        "!jq": "{data: ${piped_content::0}, action: update}"
      },
      {
        "!http": {
          "method": "POST",
          "path": "/contacts/create",
          "body": {
            "contact_data": "${piped_content::1}"
          }
        }
      }
    ]
  }
}

In the above sample, ${piped_content::0} refers to the output of the mapping step that was explained further above. The output of one section of a workflow, if there is any, is implicitly piped to the next section. ${piped_content::0} will refer to the contact object's email, first_name, last_name since that is what was mapped out.

By default, ActiveCampaignContact has 4 fields, email, first_name, last_name and phone. It can also have as many more custom fields to suit a users needs. This is one of the reasons it is recommend to always provide a mapping step if the outbound data can vary between implementations.

If there wasn't a preceding workflow step with output, then ${piped_content::0} would have referred to the output of the !resource command, which would have been the full ActiveCampaignContact for the contact record that is being processed through the workflow.

This tells the integration to expect input data in a specific format and convert if needed.

{
  "email": "[email protected]", 
  "first_name": "Campy",
  "last_name": "Cool"
}

This data is converted to the new format automatically based on the mapping info supplied in the map step.

{
  "field1": "[email protected]", 
  "field2": "Campy",
  "field3": "Cool",
}

πŸ‘

Tip

In a !pipe command, you can reference the initial input and output from all steps using the ${piped_content::INDEX} expansion. Read more here

Then this data will become the input to the "target" section, where it will be further transformed by !jq into:

{
  "data": {
    "field1": "[email protected]", 
    "field2": "Campy",
    "field3": "Cool"
  },
  "action": "update"
}

Finally, this is sent out using the !http command.

Updated 7 days ago

Configuration Walkthrough


Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.