- Introduction to SureContact Dashboard
- How to Install and Connect the SureContact WordPress Plugin
- What Do Contact Fields Mean in the SureContact WordPress Plugin
- How to Invite Members to a Workspace in SureContact
- How to Switch Organizations in SureContact
- Workspace-Level Contact Allocation in SureContact
- Workspace-Level Timezone Settings in SureContact
- How to Add a Custom Tracking Domain in a Workspace in SureContact
SureContact Third-Party Integration — Step-by-Step Guide
This document explains how external WordPress plugins can register their own integrations with SureContact, so they appear in the Integrations admin UI, participate in the rule engine, and send contacts to the SureContact CRM.
It assumes you are familiar with WordPress plugin development and basic OOP in PHP.
High-Level Flow
- You register your integration via the
surecontact_available_integrationsfilter. - SureContact loads your class through
Integrations_Loader, as long as your dependency is present and the integration is enabled. - Your integration class extends
SureContact\Integrations\Base_Integrationand:- Hooks into your plugin’s events (form submissions, orders, etc.).
- Builds/normalizes contact data.
- Calls
send_to_crm()to sync contacts.
- The SureContact rule engine:
- Uses your integration’s item types, events, items, fields and settings.
- Stores configuration in SureContact’s integrations database table.
1. Registering Your Integration
SureContact exposes a filter that lets you register integrations from any plugin:
- Filter:
surecontact_available_integrations - Location:
includes/class-integrations-loader.php
Your plugin should add to this filter after SureContact is active and before init priority 5 (when SureContact initializes integrations). The safest choice is to hook on plugins_loaded.
1.1. Basic Registration Example
In your main plugin file (e.g. my-addon/my-addon.php):
add_filter( 'surecontact_available_integrations', function( $integrations ) {
$integrations['my_addon'] = array(
// Human‑readable name shown in the Integrations UI.
'name' => 'My Addon',
// Fully-qualified PHP class name that extends SureContact\Integrations\Base_Integration.
'class' => 'MyAddon\\SureContact_Integration',
// Absolute path to your integration class file.
// External integrations SHOULD use "file_path" instead of "file".
'file_path' => plugin_dir_path( __FILE__ ) . 'includes/class-surecontact-integration.php',
// A class or function name that indicates your plugin is active.
// SureContact only attempts to load the integration if this exists.
'dependency' => 'MyAddon\\Plugin',
// WordPress plugin basename for your main plugin.
// Used by SureContact to show activation/install hints and to auto‑activate via REST.
'plugin_file' => 'my-addon/my-addon.php',
// Optional: URL to an icon for the Integrations UI (e.g. SVG or PNG).
// If omitted, the UI falls back to initials (first 2 letters of the name).
'icon_url' => plugin_dir_url( __FILE__ ) . 'assets/icons/my-addon.svg',
);
return $integrations;
} );
1.2. Configuration Array Reference
Each integration entry is an associative array with the following keys:
name(string, required):
Display name (e.g."My Addon").class(string, required):
Fully-qualified class name that must extendSureContact\Integrations\Base_Integration.file(string, internal-only):
Relative path undersurecontact/includes/integrations/.
Do not use this for third-party plugins. Usefile_pathinstead.file_path(string, recommended for third-party):
Absolute path to your integration file (e.g.plugin_dir_path( __FILE__ ) . 'includes/class-surecontact-integration.php').dependency(string, recommended):
A class name or function name that must exist for the integration to be considered “available”.
If this is missing or does not exist, SureContact will skip loading your integration.plugin_file(string, recommended):
WordPress plugin basename — the plugin directory and main file relative towp-content/plugins/(e.g.'my-addon/my-addon.php').
Used by the admin UI and REST API to:- Detect if your plugin is installed.
- Activate/deactivate the plugin via
/integration-rules/activate-plugin.
icon_url(string, optional):
URL to an icon image (SVG or PNG) displayed in the Integrations UI. If omitted, the UI shows a fallback initials badge (first 2 letters of the name). Can also be set via$this->icon_urlin your class constructor (class value takes priority when the instance is available).plugin_dependencies(array, optional):
Additional plugin basenames that must be active before your main plugin can be activated. Used by the/integration-rules/activate-pluginendpoint to activate prerequisite plugins first (e.g., Elementor Forms registersarray( 'elementor/elementor.php' )because Elementor Pro requires Elementor). This is separate fromget_additional_plugins()on your class, which handles per-item-type plugin requirements.
2. Implementing the Integration Class
Your integration class must:
- Live in a file pointed to by your
file_pathentry. - Extend
SureContact\Integrations\Base_Integration(from your own namespace). - Set a stable slug that matches the array key you used in the filter.
2.1. Minimal Skeleton
<?php
namespace MyAddon;
use SureContact\Integrations\Base_Integration;
class SureContact_Integration extends Base_Integration {
public function __construct() {
// Slug MUST match the key used in surecontact_available_integrations.
$this->slug = 'my_addon';
$this->name = 'My Addon';
$this->description = 'Syncs My Addon events and contacts to SureContact CRM.';
$this->docs_url = 'https://example.com/docs/my-addon-surecontact';
$this->icon_url = plugin_dir_url( __DIR__ ) . 'assets/icons/my-addon.svg';
// Optional: a class or function that must exist for this integration
// to be considered active on the filesystem level.
$this->dependency = 'MyAddon\\Plugin';
parent::__construct();
}
/**
* Initialize all hooks for this integration.
*
* This method is called ONLY when the integration is enabled in SureContact.
*/
protected function init() {
// Example: listen to your plugin's events.
add_action( 'my_addon_form_submitted', array( $this, 'handle_form_submission' ), 10, 2 );
}
/**
* Handle a form submission (example).
*
* @param array $submission Raw submission data from your plugin.
* @param int $user_id Related WordPress user ID (0 if not applicable).
*/
public function handle_form_submission( $submission, $user_id = 0 ) {
// 1) Build or normalize data into SureContact CRM format.
$data = $this->build_crm_data(
array(
'email' => $submission['email'] ?? '',
'first_name' => $submission['first_name'] ?? '',
'last_name' => $submission['last_name'] ?? '',
),
array(
'my_custom_field' => $submission['custom'] ?? '',
),
array(
'source_form_id' => $submission['form_id'] ?? '',
)
);
// 2) Optionally pass lists/tags/context from your own settings or logic.
$context = array(
'list_uuids' => array(), // e.g. mapped from your own config.
'tag_uuids' => array(),
);
// 3) Send to SureContact CRM (queues or immediate send handled by Contact_Service).
$result = $this->send_to_crm( $data, $user_id, $context );
// 4) Optional: handle WP_Error or success for logging.
if ( is_wp_error( $result ) ) {
// Your own logging or error handling.
return;
}
}
}
Key points:
parent::__construct()is required so Base_Integration can:- Initialize
Contact_Serviceand integrations DB access. - Register field mapping hooks.
- Check whether the integration is enabled.
- Call your
init()method only when enabled.
- Initialize
- Use either:
build_crm_data()directly (like form integrations), ornormalize_data()plussend_to_crm()for WordPress/user-like data.
3. Participating in the Rule Engine UI
SureContact’s React-based rule engine uses your integration class to:
- List supported item types (forms, products, videos, etc.).
- Show events per item type (e.g.,
completed,abandoned,submitted). - Populate item dropdowns with items (forms, products, etc.).
- Display and save per-item configuration and field mappings.
You can support all of these via a small set of methods on your integration class.
3.1. Declare Item Types
Implement get_item_types() to tell SureContact which item types you support:
public function get_item_types() {
return array(
array(
'key' => 'form',
'label' => __( 'Forms', 'surecontact' ),
),
array(
'key' => 'campaign',
'label' => __( 'Campaigns', 'surecontact' ),
),
);
}
These item types will show in:
- The Integrations table.
- The rule builder when users pick an integration and target.
3.2. Declare Events Per Item Type
Implement get_events_by_item_type( $item_type ) to describe which events can trigger rules:
public function get_events_by_item_type( $item_type ) {
if ( 'form' === $item_type ) {
return array(
array(
'key' => 'submitted',
'label' => __( 'Form Submitted', 'surecontact' ),
),
);
}
if ( 'campaign' === $item_type ) {
return array(
array(
'key' => 'started',
'label' => __( 'Campaign Started', 'surecontact' ),
),
array(
'key' => 'completed',
'label' => __( 'Campaign Completed', 'surecontact' ),
),
);
}
return array();
}
The keys you return here (e.g. 'submitted', 'completed') are used by:
- The rule engine UI (
eventdropdown). - The integrations DB (
eventcolumn). - Your own logic when reading configuration and deciding when to call
send_to_crm().
3.3. Provide Item Lists (Forms, Products, etc.)
The REST endpoint /integration-rules/items/{slug}?type={type} calls your integration to get items.
Note: The methods in sections 3.3 and 3.4 (
get_forms(),get_item_config_fields(),get_item_title()) are not inherited fromBase_Integration. They are convention-based methods that the REST API discovers on your class viamethod_exists(). If absent, they are silently skipped (no error). Exception:get_item_fields()— if absent, the fields endpoint returns aWP_Error(HTTP 400), so you should implement it if your integration uses the field mapping UI. This differs fromget_item_types()andget_events_by_item_type(), which are defined inBase_Integrationwith empty-array defaults that you override.
SureContact constructs the method name dynamically as get_{type}s() (e.g. get_forms(), get_products()), so you must implement a method matching each item type key you declared in get_item_types().
Example for type=form:
/**
* Return all forms for this integration.
*
* Each item should have at least: id, title, and type.
*
* @return array
*/
public function get_forms() {
$forms = array();
// Replace this with your own form retrieval logic.
foreach ( my_addon_get_forms() as $form ) {
$forms[] = array(
'id' => (string) $form->id,
'title' => $form->title,
'type' => 'form',
);
}
return $forms;
}
When the user opens the rule builder and selects your integration + item type, SureContact will call your method to populate the item dropdown.
3.4. Provide Field Definitions & Item-Level Config
When the admin edits rules for a specific item, SureContact calls:
GET /integration-rules/fields?slug={slug}&item_id={id}[&type={type}]
This ultimately calls get_item_fields( $item_id ) (if implemented) on your integration:
/**
* Return fields for a specific item (for field mapping UI).
*
* @param string $item_id Item ID.
* @return array
*/
public function get_item_fields( $item_id ) {
// Example structure:
return array(
array(
'key' => 'email',
'label' => __( 'Email', 'surecontact' ),
'type' => 'email',
),
array(
'key' => 'first_name',
'label' => __( 'First Name', 'surecontact' ),
'type' => 'text',
),
// ...
);
}
If you want to expose per-item configuration fields (for the right-hand side of the rule editor), implement get_item_config_fields( $item_id, $event = null ):
/**
* Return event‑specific configuration fields for a given item.
*
* @param string $item_id Item ID (e.g. form ID).
* @param string|null $event Event key (e.g. 'submitted').
* @return array
*/
public function get_item_config_fields( $item_id, $event = null ) {
unset( $item_id ); // Use in your own implementation.
// Example for a single event; you can branch by $event.
return array(
'add_lists' => array(
'label' => __( 'Add to Lists', 'surecontact' ),
'description' => __( 'Lists to add contacts to when this event fires.', 'surecontact' ),
'type' => 'list-select',
'default' => array(),
),
'add_tags' => array(
'label' => __( 'Add Tags', 'surecontact' ),
'description' => __( 'Tags to add when this event fires.', 'surecontact' ),
'type' => 'tag-select',
'default' => array(),
),
);
}
The admin UI will:
- Render these fields.
- Save values into SureContact’s integrations table as
config. - Pass the saved configuration back to you when you process events.
4. Using Integration Settings & Mappings in Your Code
SureContact stores integration configuration (global and per-item) in its own database table.Base_Integration provides helpers to read these settings safely.
Some commonly useful helpers:
- Global integration settings:
get_settings_fields()— you define field schema for the global settings UI.get_settings()/get_setting( $key, $default )— read values.is_setting_enabled( $key, $default )— typical boolean checks.
- Metadata mapping (IDs → UUIDs):
get_metadata_mapping( $type )update_metadata_mapping( $type, $mappings )convert_ids_to_uuids( $external_ids, $type )
- Lists/tags merging:
- Override
should_use_global_lists_tags( $context )if you want to merge global lists/tags with context-specific ones. prepare_lists_and_tags( $data, $user_id, $context )(called automatically bysend_to_crm()).
- Override
Use these helpers to:
- Respect global settings and per-item rules.
- Map your own IDs to SureContact list/tag UUIDs.
- Avoid duplicating persistence logic in your plugin.
5. Lifecycle Hooks You Can Rely On
SureContact fires several hooks around integrations and contact sync that may be useful in your plugin or for debugging.
5.1. Filter: surecontact_available_integrations
- Type: Filter
- Location:
Integrations_Loader::register_integrations() - Signature:
/** * @param array $integrations Associative array of slug => config. * @return array */ apply_filters( 'surecontact_available_integrations', $integrations );
Use this to register or modify integrations, as described in section 1.
5.2. Action: surecontact_integration_loaded
- Type: Action
- Location: After each integration instance is created in
load_integrations() - Signature:
/** * @param string $slug Integration slug. * @param \SureContact\Integrations\Base_Integration $instance Integration instance. */ do_action( 'surecontact_integration_loaded', $slug, $instance );
Use this if you need to:
- Inspect or further configure integrations after they are loaded.
- Attach cross‑integration behavior or logging.
5.3. Action: surecontact_integrations_loaded
- Type: Action
- Location: After all integrations have been processed in
load_integrations() - Signature:
/** * @param array<string, \SureContact\Integrations\Base_Integration> $loaded_integrations */ do_action( 'surecontact_integrations_loaded', $loaded_integrations );
Useful for:
- Performing logic that depends on the full set of loaded integrations.
- Diagnostics or health checks.
5.4. Action: surecontact_contact_synced
- Type: Action
- Location: At the end of
Base_Integration::send_to_crm()on immediate success only - Signature:
/** * Fires after a contact has been successfully synced to the CRM. * * Only fires on immediate success (not queued, not errored). * * @param string $slug Integration slug. * @param int $user_id WordPress user ID (0 if not applicable). * @param array $data Normalized data sent to the CRM. * @param array $result API response from the CRM. */ do_action( 'surecontact_contact_synced', $this->slug, $user_id, $data, $result );
You can hook into this from any plugin to:
- Log successful syncs.
- Trigger follow‑up actions (e.g., enqueue your own jobs).
- Maintain additional local metadata based on CRM responses.
6. Activation, Availability, and Enabling
There are three separate concepts you should keep in mind:
- Filesystem registration:
Whether your integration is present in thesurecontact_available_integrationsarray and itsdependencyexists. This controls:- Whether the integration shows up in the admin UI.
- Whether the REST API considers it a valid integration.
- WordPress plugin activation:
Whether your own plugin (and any additional plugin dependencies) is active:- Controlled by WordPress and/or SureContact’s
/integration-rules/activate-pluginendpoint. - Uses
plugin_fileand any additional plugin metadata.
- Controlled by WordPress and/or SureContact’s
- Integration enabled/disabled in SureContact:
Whether your integration is enabled in the SureContact UI:- Stored in SureContact’s custom integrations table (
statuscolumn). - Checked inside
Base_Integration::__construct()viais_enabled(). - Only when enabled does SureContact call your
init()method.
- Stored in SureContact’s custom integrations table (
As a third‑party developer, you generally do not need to manipulate the database directly. Use:
- The SureContact admin UI.
- The existing REST endpoints (e.g.
/integration-rules/toggle,/integration-rules/settings/save) if you are building automation.
7. Best Practices & Recommendations
- Use a stable slug:
- The slug is used everywhere: database keys, REST API URLs, filter keys, and UI.
- Changing it later will break existing configurations.
- Avoid heavy logic in the constructor:
- Put hooks and heavy setup in
init(). - The constructor is called even when creating temporary instances for metadata.
- Put hooks and heavy setup in
- Keep
get_item_fields()andget_item_config_fields()fast:- They are called from the admin UI.
- Avoid unnecessary remote calls; cache where possible.
- Respect existing patterns:
- Reuse the standard list/tag field structures provided by
Base_Integration::get_standard_list_tag_fields()where appropriate. - Use
build_crm_data()andsend_to_crm()instead of calling lower-level API clients directly.
- Reuse the standard list/tag field structures provided by
- Handle
WP_Errorfromsend_to_crm():send_to_crm()may returnWP_Error(validation, disabled sync, etc.) or a successful response/queue info array.- Always wrap calls with
is_wp_error()before assuming success.
8. Quick Checklist
- Add a
surecontact_available_integrationsfilter in your plugin. - Provide
name,class,file_path,dependency, andplugin_file. - Implement a class extending
SureContact\Integrations\Base_Integration. - Set a stable
$slugmatching your filter key. - Implement
init()and hook into your plugin’s events. - Implement
get_item_types()andget_events_by_item_type()for rule support. - Implement
get_{type}s()and/orget_item_fields()to populate the UI. - Optionally implement
get_item_config_fields()andget_settings_fields()for additional config. - Use
build_crm_data()/normalize_data()+send_to_crm()to sync contacts. - (Optional) Hook into
surecontact_contact_syncedfor post‑sync actions.
We don't respond to the article feedback, we use it to improve our support content.