> ## Documentation Index
> Fetch the complete documentation index at: https://help.statisfy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Integration Concepts

> Shared concepts behind Statisfy's self-serve integration settings — where to find them, previews and validation, sync schedules, job status, and configuration history.

Every self-serve integration in Statisfy follows the same model: you connect it, then configure **what to pull**, **how it matches to your accounts**, and **how often to run** — all from a settings page inside Statisfy, with live previews so you can check your work before saving.

This page explains the shared concepts once. Each integration's own guide covers its specifics. Statisfy's self-serve integrations come in two families:

* **CRM integrations** — [Salesforce](/integrations/salesforce), [HubSpot](/integrations/hubspot_integration), and [Gainsight](/integrations/gainsight_integration). Their settings pages are a wizard of sections (account filtering, owner mapping, ARR & renewal, and so on).
* **Query-based integrations** — [BigQuery](/integrations/bigquery_integration), [Snowflake](/integrations/snowflake_integration), [Redshift](/integrations/redshift_integration), [PostgreSQL](/integrations/postgresql), [PostHog](/integrations/posthog_integration), and [Jira / Jira Service Desk](/integrations/jira_integration). Their settings pages are a list of queries or rules you author yourself.

The first half of this page applies to **both** families. The second half — query types, account resolvers, transformers, and date placeholders — applies to the query-based family only.

## Concepts shared by every integration

### Where to find the settings

Once an integration is connected, open **Integrations → \{integration} → Settings**. The settings page is the single place to:

* Configure what syncs (wizard sections or queries/rules)
* Set sync schedules where the integration supports them
* Run a one-off sync on demand
* Review the active configuration version and latest job status

You need **Admin** access in Statisfy to view or change these settings.

### Preview and validation

Anywhere you write a filter or query, there's a **Validate** or **Preview** button that tests it against your live data source before you save — you'll see whether it's valid, how many records match, and a few sample results:

* **Salesforce / HubSpot / Gainsight** — filters are checked against your CRM and return a match count plus sample records.
* **SQL warehouses** — syntax is checked against your warehouse's SQL flavor (Postgres, Redshift, BigQuery Standard SQL, Snowflake) and the query runs against a sample.
* **PostHog** — the preview runs the query for real; that's the validation.
* **Jira** — project keys, field IDs, and issue-type filters are checked against Jira when you save, and problems surface immediately.

<Tip>
  If a preview shows **0 matches**, your filter is valid but too narrow — loosen it before saving, or nothing will sync.
</Tip>

### Your first sync, and what runs after

* When you first connect a data source, Statisfy runs a one-time **bootstrap** sync covering roughly the **last 30 days** of data. Data typically starts appearing within a few hours.
* After that, scheduled **periodic** syncs run automatically — daily for CRM integrations, and on the cadence you configure for query-based ones.
* Both kinds of runs appear in the job history on the settings page.

<Note>
  **CRM comes first.** Non-CRM integrations (warehouse, Jira, PostHog, Gainsight) only start syncing after at least one successful CRM sync. Statisfy uses your CRM as the source of truth for which accounts exist, so other data has nothing to attach to until the CRM is loaded.
</Note>

### Running a sync on demand

Each settings page has a **Run Sync Job** button that starts an immediate sync instead of waiting for the next scheduled run. The most recent job's status (queued / running / completed / failed) and timestamps are shown on the same page. Changed a setting? Save, then click **Run Sync Job** to apply it now.

### Monitoring your integrations

Admins can see the health of every connected integration in one place: from the **Integrations** page, click **View monitoring** to open the **Integration Monitoring** page. For each integration it shows:

* A status badge — **Healthy**, **Degraded**, **Failed**, or **Disabled**
* When it last ran and how often it runs
* An expandable history of the last 10 runs

Use the search box and status filter to find a specific integration, and **Refresh** to pull the latest state. If something shows **Failed** or hasn't run when you expected, open that integration's Settings page to review its configuration, or contact [support@statisfy.com](mailto:support@statisfy.com).

### Configuration history

Every save creates a new configuration **version**, recording who saved it and when. The settings page header shows where the active config came from:

| Badge            | Meaning                                                                                           |
| ---------------- | ------------------------------------------------------------------------------------------------- |
| `Database (v3)`  | Most recent saved version is the active config                                                    |
| `Default (Code)` | No self-serve config has ever been saved; Statisfy is using a built-in fallback set up by support |
| `Not Configured` | Neither a saved version nor a code fallback exists — the integration is connected but idle        |

Older versions are preserved for rollback. If you need to revert, contact [support@statisfy.com](mailto:support@statisfy.com) — there is no in-app rollback yet.

### What you can't do (yet) from the UI

* **Rollback to an older version** — version history is preserved, but reverting requires support.
* **Bulk-edit queries across integrations** — each integration has its own settings page.
* **Pause an integration globally** — you can mark individual queries / rules as inactive, but there is no single off-switch beyond disconnecting.

## Concepts for query-based integrations

Everything below applies to the warehouse, PostHog, and Jira integrations — where you author the queries yourself. CRM integrations (Salesforce, HubSpot, Gainsight) handle account matching automatically; see their own pages.

### Query types

For warehouse and PostHog integrations, every query you author has a **type** that tells Statisfy what to do with the result rows.

| Query Type      | What it writes                            | Typical use                                |
| --------------- | ----------------------------------------- | ------------------------------------------ |
| `product_usage` | Time-series metric values per account     | MAU, API call counts, feature adoption     |
| `custom_field`  | Account- or person-level attribute values | Health score, segment, plan tier, industry |
| `custom_object` | Records of a custom object type           | Subscriptions, deployments, contracts      |

For Jira, the equivalent unit is a **project rule** — each rule says "for this project (and optionally these issue types), apply these field mappings and customer-matching logic". See the Jira page for details.

<Note>
  A single integration can have many queries / rules — for example, one `product_usage` query for daily logins and another `custom_field` query for weekly health scores, each running on its own cadence.
</Note>

### Account resolvers

Every row that comes out of a query has to be matched to a Statisfy account before it can be stored. The **account resolver** is the rule that tells Statisfy which column on the row identifies the account, and what kind of value it contains.

| Resolver                | What the column should contain                                                       |
| ----------------------- | ------------------------------------------------------------------------------------ |
| **Statisfy Account ID** | The native Statisfy account ID                                                       |
| **CRM Account ID**      | The Salesforce or HubSpot account ID for the account                                 |
| **Organization ID**     | An external org identifier you've stored on the account                              |
| **Email Domain**        | A company website domain (e.g., `acme.com`) — matched against accounts' domain field |
| **Account Name**        | The company name — uses fuzzy matching, with a tunable cutoff                        |
| **Custom Field**        | The value of any custom field defined on accounts                                    |

<Warning>
  Rows whose resolver value doesn't match an existing Statisfy account are **skipped silently**. Statisfy will not create new accounts from these syncs. If a query produces fewer matches than you expect, the resolver and its source column are the first things to check.
</Warning>

#### Fuzzy matching cutoff

The **Account Name** resolver does approximate matching to absorb small typos, casing, and "Inc." vs. "Inc" differences. The cutoff (0.0–1.0) controls how strict the match has to be. The default suits most cases; raise it if you see false positives, lower it if legitimate matches are being missed.

#### Person resolvers (warehouse and PostHog only)

For `custom_field` queries that target **people** (contacts) instead of accounts, pick an **email** column. Optionally also map first name, last name, or a single full-name column — Statisfy will use these to upsert the person record. Internal vs. external is decided by comparing the email domain against your tenant domain.

### Column transformers

Sometimes a column has the right value embedded in something else — a CRM ID with a `org_` prefix, an email field with extra whitespace, a hostname when you want just the domain. **Column transformers** let you reshape a column before it's used.

Available transforms:

| Transform           | What it does                                                                               |
| ------------------- | ------------------------------------------------------------------------------------------ |
| `strip_prefix`      | Removes a fixed prefix (e.g., strip `org_` from `org_12345`)                               |
| `split_first_token` | Splits on a delimiter and keeps the first token (e.g., extract the local part of an email) |
| `regex_extract`     | Pulls a matching part out of the column using a pattern                                    |
| `lookup`            | Replaces values via a static `{from: to}` mapping                                          |
| `skip_if_equals`    | Drops the row if the column equals a given value                                           |
| `skip_if_contains`  | Drops the row if the column contains a given substring                                     |

Transforms run in order — chain them to combine effects. They apply both to resolver columns (before account matching) and to value columns (before being written to a field).

### Field and metric mappings

A query's columns become useful only when they are mapped to Statisfy fields.

* For **`custom_field`** queries, pick a Statisfy custom field for each value column. The field must exist on the target entity (account or people); create it in **Object Manager** first if needed.
* For **`product_usage`** queries, pick the metric (product dimension) the value belongs to, and the timestamp column that places it in time. Create new product dimensions in Object Manager.
* For **`custom_object`** queries, map each attribute on the custom object record.

If you want a single column to land in multiple places, add it to the mapping more than once with different targets.

### Schedule

Each query and each Jira rule can run on its own cadence (how often it syncs). The available cadences:

`HOURLY` · `TWO_HOURS` · `FOUR_HOURS` · `SIX_HOURS` · `TWELVE_HOURS` · `DAILY` · `WEEKLY` · `MONTHLY`

If a query doesn't set its own cadence, it inherits the integration default (typically `WEEKLY`).

For warehouse `product_usage` queries that aggregate by week, the **Week Start Day** at the integration level decides which day of the week the snapshot is anchored to (0 = Monday, 6 = Sunday).

### Date placeholders (warehouse only)

Warehouse queries can reference the active sync window via placeholders, so each run pulls only new data:

* `{START_DATE}` — the start of the current window, as `YYYY-MM-DD`
* `{END_DATE}` — the end of the current window, as `YYYY-MM-DD`
* `{END_DATE_SQL}` — the end as a SQL-quoted literal, ready to drop into a `WHERE` clause

The window is derived from the query's cadence — for `WEEKLY`, the previous Monday through Sunday; for `MONTHLY`, the first to last day of the previous month; for `DAILY`, the previous day. Use these to keep queries incremental.

## Troubleshooting checklist

<Accordion title="Rows are not landing in Statisfy">
  1. Confirm the **account resolver** is using a column whose values exist in Statisfy — for CRM ID resolvers, the matching accounts must already be synced from your CRM.
  2. Run the **Preview** and verify the resolver column actually contains the expected values for those rows (no nulls, no stray prefixes).
  3. Check whether column transformers are inadvertently filtering rows (`skip_if_*` transforms).
  4. For `product_usage`, confirm the metric (product dimension) exists in Object Manager.
  5. Look at the latest job status — a failed job will show the error.
</Accordion>

<Accordion title="Some rows match but most don't">
  * Try a different resolver. CRM ID and Statisfy Account ID are the most exact; Email Domain and Account Name are best-effort.
  * For Account Name, raise or lower the **fuzzy cutoff** depending on whether you're seeing false matches or missing matches.
  * For Custom Field resolvers, make sure the field is populated on the target accounts — empty values can't be matched.
</Accordion>

<Accordion title="The query is too slow or times out">
  * Tighten the date range using `{START_DATE}` / `{END_DATE_SQL}`.
  * Drop the cadence to `DAILY` so each run covers a smaller window.
  * For warehouses, push filters into the query rather than relying on Statisfy to discard rows post-hoc.
</Accordion>

<Accordion title="A saved configuration isn't taking effect">
  * Confirm the version badge in the header shows `Database (vN)` and not `Default (Code)` — if it still says Default, your save didn't land.
  * Check that the query is marked **active** — inactive queries are kept for reference but don't run.
  * Trigger a manual sync with **Run Sync Job** and watch the job history.
</Accordion>

## Need help?

If you get stuck wiring up the resolver, picking the right query type, or understanding why a row isn't matching, reach out to [support@statisfy.com](mailto:support@statisfy.com) with the integration name and (if possible) the query or filter you're trying to save. Support can also help with multi-version rollbacks and one-off backfills outside the standard cadence.
