Zendesk Support Custom Objects Example

This config showcases how to define a CX app that uses Custom Objects. One object must be defined with ac_object set to "Contact" to map any contact data to the core Contact. One or more objects can be defined without ac_object and will be stored as records bound to the associated Contact.

To learn how to define these objects in detail, please refer to our Custom Objects reference.

{
  "$version": "2",
  "api": {
    "base_url": "https://${subdomain}.zendesk.com"
  },
  "auth": {
    "zendesk-auth": {
      "type": "oauth2",
      "configuration": {
        "authorization_base_url": "https://${subdomain}.zendesk.com/oauth/authorizations/new",
        "client_id": "",
        "client_secret": "",
        "token_url": "https://${subdomain}.zendesk.com/oauth/tokens",
        "scopes": [
          "targets:write",
          "tickets:write",
          "users:write",
          "triggers:write",
          "read"
        ],
        "refresh_url": "https://${subdomain}.zendesk.com/oauth/tokens"
      },
      "defined_fields": {
        "subdomain": {
          "label": "Account Subdomain",
          "placeholder": "Enter your Account Subdomain",
          "help_text": "Your subdomain immediately precedes the .zendesk.com portion of your Zendesk url."
        }
      }
    }
  },
  "data_intake": [
    {
      "name": "form_webhook",
      "type": "webhook",
      "scope": "workflow",
      "create": {
        "!pipe": [
          {
            "!http": {
              "path": "api/v2/targets.json",
              "method": "POST",
              "headers": {
                "content-type": "application/json"
              },
              "body": {
                "target": {
                  "type": "http_target",
                  "title": "ActiveCampaign webhook target",
                  "target_url": "${webhook.url}",
                  "method": "post",
                  "content_type": "application/json"
                }
              }
            }
          },
          {
            "!jq": "{target_id: .target.id}"
          },
          {
            "!save": {
              "scope": "workflow"
            }
          },
          {
            "!http": {
              "method": "POST",
              "path": "/api/v2/triggers",
              "headers": {
                "content-type": "application/json"
              },
              "body": {
                "trigger": {
                  "title": "Ticket Created",
                  "conditions": {
                    "all": [
                      {
                        "field": "update_type",
                        "value": "Create"
                      }
                    ]
                  },
                  "actions": [
                    {
                      "field": "notification_target",
                      "value": [
                        "${piped_content.2.target_id}",
                        "{\"type\": \"ticket_created\", \"data\": {\"ticket_id\": \"{{ticket.id}}\", \"requester_id\": \"{{ticket.requester.id}}\"}}"
                      ]
                    }
                  ]
                }
              }
            }
          },
          {
            "!jq": ".trigger | {ticket_created_trigger_id: .id}"
          },
          {
            "!save": {
              "scope": "workflow"
            }
          },
          {
            "!http": {
              "method": "POST",
              "path": "/api/v2/triggers",
              "headers": {
                "content-type": "application/json"
              },
              "body": {
                "trigger": {
                  "title": "Ticket Updated",
                  "conditions": {
                    "all": [
                      {
                        "field": "update_type",
                        "value": "Change"
                      }
                    ]
                  },
                  "actions": [
                    {
                      "field": "notification_target",
                      "value": [
                        "${piped_content.2.target_id}",
                        "{\"type\": \"ticket_updated\", \"data\": {\"ticket_id\": \"{{ticket.id}}\", \"requester_id\": \"{{ticket.requester.id}}\"}}"
                      ]
                    }
                  ]
                }
              }
            }
          },
          {
            "!jq": ".trigger | {ticket_updated_trigger_id: .id}"
          },
          {
            "!save": {
              "scope": "workflow"
            }
          }
        ]
      },
      "delete": {
        "!pipe": [
          {
            "!http": {
              "method": "DELETE",
              "path": "/api/v2/triggers/${data.workflow.ticket_created_trigger_id}"
            }
          },
          {
            "!http": {
              "method": "DELETE",
              "path": "/api/v2/triggers/${data.workflow.ticket_updated_trigger_id}"
            }
          },
          {
            "!http": {
              "method": "DELETE",
              "path": "/api/v2/targets/${data.workflow.target_id}"
            }
          }
        ]
      }
    }
  ],
  "objects": [
    {
      "name": "user",
      "labels": {
        "singular": "User",
        "plural": "Users"
      },
      "description": "Zendesk Support User",
      "ac_object": "Contact",
      "from_reference": {
        "!http": {
          "method": "GET",
          "path": "/api/v2/users/${reference}"
        }
      },
      "external_id": "id",
      "fields": []
    },
    {
      "name": "ticket",
      "labels": {
        "singular": "Zendesk Support Ticket",
        "plural": "Zendesk Support Tickets"
      },
      "description": "Tickets created in Zendesk Support",
      "event_type_field": ".type",
      "event_types": [
        {
          "value": "ticket_created",
          "display": "Ticket Created",
          "description": "Occurs when a ticket is created"
        },
        {
          "value": "ticket_updated",
          "display": "Ticket Updated",
          "description": "Occurs when a ticket is updated"
        }
      ],
      "from_reference": {
        "!http": {
          "path": "/api/v2/tickets/${reference}.json",
          "method": "GET"
        }
      },
      "transform": {
        "status": ".status",
        "id": ".id",
        "priority": ".priority",
        "type": ".type",
        "updated_at": ".updated_at",
        "assignee_id": ".assignee_id",
        "brand_id": ".brand_id",
        "created_at": ".created_at",
        "description": ".description",
        "due_at": ".due_at",
        "external_id": ".external_id",
        "forum_topic_id": ".forum_topic_id",
        "group_id": ".group_id",
        "organization_id": ".organization_id",
        "problem_id": ".problem_id",
        "raw_subject": ".raw_subject",
        "recipient": ".recipient",
        "requester_id": ".requester_id",
        "subject": ".subject",
        "submitter_id": ".submitter_id",
        "ticket_form_id": ".ticket_form_id",
        "url": "[\"https://\", ${subdomain}, \".zendesk.com/agent/tickets/\", (.id|tostring)] | join(\"\")"
      },
      "relationships": [
        {
          "description": "User that requested this ticket",
          "object": "user",
          "has_many": false,
          "field": ".data.requester_id",
          "type": "reference",
          "id": "user",
          "labels": {
            "singular": "User",
            "plural": "Users"
          }
        }
      ],
      "fields": [
        {
          "id": "status",
          "labels": {
            "singular": "Status",
            "plural": "Statuses"
          },
          "description": "Status of the ticket",
          "type": "text",
          "is_required": false
        },
        {
          "id": "id",
          "labels": {
            "singular": "Ticket ID",
            "plural": "Ticket IDs"
          },
          "description": "Main identifier of the ticket",
          "type": "number",
          "is_required": true
        },
        {
          "id": "priority",
          "labels": {
            "singular": "Priority",
            "plural": "Priorities"
          },
          "description": "Priority of the ticket",
          "type": "text",
          "is_required": false
        },
        {
          "id": "type",
          "labels": {
            "singular": "Type",
            "plural": "Types"
          },
          "description": "Type of ticket",
          "type": "text",
          "is_required": false
        },
        {
          "id": "updated_at",
          "labels": {
            "singular": "Updated At",
            "plural": "Updated Ats"
          },
          "description": "The time the ticket was last updated",
          "type": "datetime",
          "is_required": false
        },
        {
          "id": "assignee_id",
          "labels": {
            "singular": "Assignee ID",
            "plural": "Assignee IDs"
          },
          "description": "The user currently assigned to the ticket",
          "type": "number",
          "is_required": false
        },
        {
          "id": "brand_id",
          "labels": {
            "singular": "Brand ID",
            "plural": "Brand IDs"
          },
          "description": "The id of the brand this ticket is associated with",
          "type": "number",
          "is_required": false
        },
        {
          "id": "created_at",
          "labels": {
            "singular": "Created At",
            "plural": "Created Ats"
          },
          "description": "When this ticket was created",
          "type": "datetime",
          "is_required": false
        },
        {
          "id": "description",
          "labels": {
            "singular": "Ticket Description",
            "plural": "Ticket Descriptions"
          },
          "description": "First comment of the ticket",
          "type": "text",
          "is_required": true
        },
        {
          "id": "due_at",
          "labels": {
            "singular": "Due At",
            "plural": "Due Ats"
          },
          "description": "Due date for the ticket",
          "type": "datetime",
          "is_required": false
        },
        {
          "id": "external_id",
          "labels": {
            "singular": "External ID",
            "plural": "External ID"
          },
          "description": "An id you can use to link Zendesk Support tickets to local records",
          "type": "text",
          "is_required": false
        },
        {
          "id": "forum_topic_id",
          "labels": {
            "singular": "Forum Topic ID",
            "plural": "Forum Topic IDs"
          },
          "description": "The topic in the Zendesk Web portal this ticket originated from",
          "type": "number",
          "is_required": false
        },
        {
          "id": "group_id",
          "labels": {
            "singular": "Group ID",
            "plural": "Group IDs"
          },
          "description": "The group this ticket is assigned to",
          "type": "number",
          "is_required": false
        },
        {
          "id": "organization_id",
          "labels": {
            "singular": "Organization ID",
            "plural": "Organization IDs"
          },
          "description": "The organization of the ticket requester",
          "type": "number",
          "is_required": false
        },
        {
          "id": "problem_id",
          "labels": {
            "singular": "Problem ID",
            "plural": "Problem IDs"
          },
          "description": "For tickets of type \"incident\", the ID of the problem the incident is linked to",
          "type": "number",
          "is_required": false
        },
        {
          "id": "raw_subject",
          "labels": {
            "singular": "Raw Subject",
            "plural": "Raw Subjects"
          },
          "description": "The dynamic content placeholder, if present, or the \"subject\" value, if not",
          "type": "text",
          "is_required": false
        },
        {
          "id": "recipient",
          "labels": {
            "singular": "Recipient",
            "plural": "Recipients"
          },
          "description": "The original recipient e-mail address of the ticket",
          "type": "text",
          "is_required": false
        },
        {
          "id": "requester_id",
          "labels": {
            "singular": "Requester ID",
            "plural": "Requester IDs"
          },
          "description": "The user who requested the ticket",
          "type": "number",
          "is_required": true
        },
        {
          "id": "subject",
          "labels": {
            "singular": "Ticket Subject",
            "plural": "Ticket Subjects"
          },
          "description": "Subject of the ticket",
          "type": "text",
          "is_required": true
        },
        {
          "id": "submitter_id",
          "labels": {
            "singular": "Submitter ID",
            "plural": "Submitter IDs"
          },
          "description": "The user who submitted the ticket",
          "type": "number",
          "is_required": false
        },
        {
          "id": "ticket_form_id",
          "labels": {
            "singular": "Ticket Form ID",
            "plural": "Ticket Form IDs"
          },
          "description": "The id of the ticket form to render for the ticket",
          "type": "number",
          "is_required": false
        },
        {
          "id": "url",
          "labels": {
            "singular": "Ticket URL",
            "plural": "Ticket URLs"
          },
          "description": "The url of this ticket",
          "type": "text",
          "is_required": false
        }
      ],
      "external_id": "${subdomain} + \".\" + (.id|tostring)"
    }
  ],
  "workflows": [
    {
      "name": "create-or-update-contacts",
      "type": "generic",
      "resource_type": {
        "singular": "Ticket",
        "plural": "Tickets"
      },
      "label": "Create or Update Contacts from Zendesk Support Tickets",
      "description": "Create or update a contact in ActiveCampaign based on the ticket requester in Zendesk Support",
      "data_intake": "form_webhook",
      "auth": "zendesk-auth",
      "setup": {
        "connect": {
          "label": "Connect",
          "describe_connection": {
            "!pipe": [
              {
                "!http": {
                  "method": "GET",
                  "path": "/api/v2/users/me",
                  "headers": {
                    "content-type": "application/json"
                  }
                }
              },
              {
                "!jq": ".user | {account_id: .id, description: [.name, .email] | join(\" - \")}"
              }
            ]
          }
        },
        "select": {
          "label": "Zendesk Support Select Step",
          "description": "This is an empty select step.",
          "form_fields": [],
          "describe_selection": {
            "resource_id": {
              "!jq": "\"Zendesk\""
            },
            "display": {
              "!jq": "\"Ticket\""
            }
          }
        },
        "map": {
          "label": "Mapping",
          "describe_source": {
            "label": "Zendesk Support",
            "options": {
              "!pipe": [
                {
                  "!http": {
                    "method": "GET",
                    "path": "/api/v2/user_fields",
                    "headers": {
                      "content-type": "application/json"
                    }
                  }
                },
                {
                  "!jq": "[.user_fields[] | {id: ([\"user_fields__\", .key] | add), title:  .raw_title, type: \"string\"}]"
                },
                {
                  "!jq": "([\"active\", \"alias\", \"chat_only\", \"first_name\", \"last_name\", \"email\", \"created_at\", \"custom_role_id\", \"default_group_id\", \"details\", \"external_id\", \"iana_time_zone\", \"id\", \"last_login_at\", \"locale\", \"locale_id\", \"moderator\", \"name\", \"notes\", \"only_private_comments\", \"organization_id\", \"phone\", \"report_csv\", \"restricted_agent\", \"role\", \"role_type\", \"shared\", \"shared_agent\", \"shared_phone_number\", \"signature\", \"suspended\", \"ticket_restriction\", \"time_zone\", \"two_factor_auth_enabled\", \"updated_at\", \"url\", \"verified\"] | map({id: ., title: . | split(\"_\") | join(\" \"), type: \"string\"})) + ."
                }
              ]
            }
          },
          "describe_target": {
            "label": "ActiveCampaign",
            "options": {
              "!resource": "ActiveCampaignContact.fields"
            }
          }
        }
      },
      "data_pipeline": {
        "source": {
          "!pipe": [
            {
              "!resource": {
                "action": "ActiveCampaignCustomObject.from_reference",
                "object": "ticket",
                "data": "${piped_content.0.data.ticket_id}"
              }
            },
            {
              "!jq": ".ticket"
            },
            {
              "!resource": {
                "action": "ActiveCampaignCustomObject.transform",
                "object": "ticket",
                "data": "${piped_content.2}"
              }
            },
            {
              "!resource": {
                "action": "ActiveCampaignCustomObject.from_reference",
                "object": "user",
                "data": "${piped_content.0.data.requester_id}"
              }
            },
            {
              "!jq": ".user | . + { first_name: .name | split(\" \") | first, last_name: (.name | split(\" \") as $name | $name - ($name | [first]) | join(\" \")) } + ([paths as $path | select($path[0]==\"user_fields\") |  {\"key\": $path | join(\"__\"), \"value\": getpath($path)}] | from_entries)"
            }
          ]
        },
        "target": {
          "!pipe": [
            {
              "!resource": "ActiveCampaignContact"
            },
            {
              "!resource": {
                "action": "ActiveCampaignCustomObject.sync",
                "object": "ticket",
                "data": {
                  "external_id": "${subdomain} + \".\" + (.id|tostring)}",
                  "fields": "${source_data.piped_content.3}",
                  "relationships": [
                    {
                      "name": "primary-contact",
                      "value": [
                        "${piped_content.1.contact_id}"
                      ]
                    }
                  ]
                }
              }
            }
          ]
        }
      }
    }
  ]
}