Overview
The Salesforce (REST API) data source template connects Validatar to a Salesforce org through the Salesforce REST API. It requires no driver installation and no third-party license, and runs on any runtime that can reach *.my.salesforce.com over HTTPS — including Validatar Cloud.
Platform: Salesforce (all editions with API access)
Connection Category: Script
Connection Type: Python Script
Query language: SOQL
The template catalogs objects and fields from the Salesforce describe API and enriches the Validatar catalog with Salesforce-specific metadata: formula definitions, picklist values, external IDs, encryption flags, and lookup targets. Its macros target the data quality failures characteristic of CRM data — incomplete fields, duplicate accounts and contacts, references to deleted records, and picklist values that persist in data after being deactivated in configuration.
SQL access to the same org, including cross-object joins, is provided by the Salesforce (ODBC) Data Source Template. Salesforce: REST API or ODBC compares the two.
Requirements
| Requirement | Detail |
|---|---|
| Salesforce edition | Any edition with API access — Developer, Enterprise, Unlimited, or Performance. Professional Edition requires the API add-on. |
| Authentication | An External Client App configured for either the OAuth 2.0 client credentials flow or the JWT bearer flow |
| Runtime packages | requests and pandas. The JWT method additionally requires cryptography. |
| Network | Outbound HTTPS to the org's My Domain URL |
| Catalog fields | The Salesforce CRM Catalog Fields marketplace item, applied before the first ingestion |
Note: Ingestion columns that do not match an existing custom field reference key are discarded silently. Ingesting before the catalog fields are applied results in missing enrichment with no accompanying error.
Authentication Requirements
Three Salesforce platform changes govern how this template authenticates:
- Connected Apps can no longer be created as of the Spring '26 release. External Client Apps are the replacement. Existing Connected Apps continue to function.
- The OAuth username-password flow is blocked by default on orgs created in Summer '23 or later.
- The OAuth username-password flow is retired entirely in Winter '27.
The template therefore supports only the client credentials and JWT bearer flows, both configured on an External Client App. No username-password fallback is offered.
Connection Parameters
| Parameter | Reference key | Type | Required | Notes |
|---|---|---|---|---|
| Instance URL | instance_url |
String | Yes | The org's My Domain URL, such as https://acme.my.salesforce.com. Not login.salesforce.com. |
| Authentication Mode | auth_mode |
Dropdown | Yes | client_credentials or jwt |
| Consumer Key | client_id |
String | Yes | From the External Client App. Also serves as the JWT issuer. |
| Consumer Secret | client_secret |
Secret | For client credentials | |
| Username | sf_username |
String | For JWT | The pre-authorized user the assertion runs as |
| Private Key (PEM) | private_key_pem |
Secret | For JWT | PKCS#8 key matching the certificate uploaded to the External Client App |
| API Version | api_version |
String | No | auto (default) resolves the newest version the org supports |
| Include Objects | include_objects |
String | No | Comma-separated allowlist of object API names. Recommended on orgs where API consumption is constrained. |
| Exclude Patterns | exclude_patterns |
String | No | Comma-separated glob patterns. Blank applies the built-in exclusion list. |
| Custom Objects Only | include_custom_only |
Boolean | No | Restricts the catalog to __c objects |
| Max Objects | max_objects |
Integer | No | Hard cap on objects cataloged. 0 applies no cap. |
| Profile Sample Rows | profile_sample_rows |
Integer | No | Records sampled per object for column profiles. Default 2000. |
Authentication modes
Client credentials requires a consumer key, a consumer secret, and a designated run-as user on the External Client App. It carries no additional runtime dependency.
JWT bearer replaces the shared secret with an RSA private key that signs a short-lived assertion, and is generally preferred where a long-lived secret is not acceptable. It requires the cryptography package on the runtime, a certificate uploaded to the External Client App, and pre-authorization of the run-as user.
Both modes are verified and fully supported. Neither offers greater capability or throughput than the other.
Setting Up Salesforce Access
Configuration requires System Administrator access in Salesforce and takes approximately 20 minutes.
Note: Most third-party integration guides describe creating a Connected App. Salesforce no longer permits new Connected Apps as of Spring '26; an External Client App is required.
1. Identify the My Domain URL
The My Domain URL appears in the browser address bar after login, in the form https://acme.my.salesforce.com. This value is the Instance URL parameter. login.salesforce.com is not a valid value.
Salesforce reference: My Domain
2. Create the External Client App
Navigate to Setup → App Manager → New External Client App and configure:
- Name: any meaningful identifier, such as
Validatar Data Quality - Distribution State:
Local - API (Enable OAuth Settings): enabled
- Callback URL:
http://localhost:1717/OauthRedirect— required by the form, though neither supported flow performs a redirect - OAuth Scopes:
Manage user data via APIs (api)andPerform requests at any time (refresh_token, offline_access)
Salesforce requires 2–10 minutes to activate a newly created app. Authentication attempts made before activation completes fail with invalid_client_id.
Salesforce reference: Create an External Client App
3a. Configure the client credentials flow
In the External Client App, under Policies → Edit → OAuth Policies:
- Enable Client Credentials Flow
- Set Run As to the integration user the queries execute as. That user's permissions determine catalog and query visibility.
The consumer key and secret are then available under Settings → OAuth Settings → Consumer Key and Secret → Reveal.
Salesforce references: OAuth 2.0 Client Credentials Flow · Configure an External Client App for the Client Credentials Flow
3b. Configure the JWT bearer flow
Generate a certificate and private key:
openssl req -x509 -sha256 -nodes -days 3650 -newkey rsa:2048 \
-keyout salesforce.key -out salesforce.crt -subj "/CN=validatar-integration"
openssl pkcs8 -topk8 -nocrypt -in salesforce.key -out salesforce.pem
Then, in the External Client App:
- Under Settings → OAuth Settings → Edit, enable Use Digital Signatures and upload
salesforce.crt. The certificate must be under 4 KB. - Under Policies → Edit → OAuth Policies, set Permitted Users to
Admin approved users are pre-authorized, then use Manage Profiles to add the profile of the run-as user.
Omitting step 2 produces the error user hasn't approved this consumer, which is the most common failure in this configuration.
The connection then requires the consumer key, the username, and the contents of salesforce.pem.
Salesforce reference: OAuth 2.0 JWT Bearer Flow
4. Confirm the credentials
curl -s -X POST "https://acme.my.salesforce.com/services/oauth2/token" \
-d "grant_type=client_credentials" -d "client_id=CONSUMER_KEY" -d "client_secret=CONSUMER_SECRET"
A response containing access_token confirms the configuration is complete.
Catalog Structure
Salesforce has no schema concept, so the template derives three catalog schemas:
| Catalog schema | Contents |
|---|---|
standard |
Salesforce standard objects — Account, Contact, Opportunity, and so on |
custom |
Org-local custom objects (__c) |
| namespace | One schema per installed managed package, named for its namespace prefix |
Objects in a namespace schema are owned by an installed package and are subject to change on package upgrade.
What's Included
Catalog enrichment
Object level: label, API name, custom flag, namespace prefix, key prefix, sharing model, queryable, createable, updateable, and record type count.
Field level: label, API name, custom flag, formula flag, formula expression, required, unique, external ID, encrypted, auto-number, picklist values, and lookup targets.
Standard field properties — help text, length, precision, scale, nullability, auto-number, and primary key — populate Validatar's built-in column properties rather than custom fields.
Macros
Standard set: object_data, row_count, row_count_filtered, list_of_objects, list_of_objects_in_a_schema, field_metadata_for_an_object, distinct_values_in_a_column, row_count_grouped_by_column, standard_profile_of_a_column, key_value_list.
Salesforce-specific:
| Macro | Purpose |
|---|---|
soql |
Arbitrary SOQL. Relationship fields are flattened to dotted columns. |
field_fill_rate |
Completeness across every field on an object in a single result |
required_fields_null_count |
Null values in fields the describe API reports as required. Records loaded through the API can bypass rules the user interface enforces. |
duplicate_check_on_field |
Duplicate email addresses, account names, or external IDs |
orphaned_lookups |
References to records that no longer exist |
picklist_values_vs_actual |
Values present in data that the picklist no longer declares |
record_count_by_recordtype |
Record volume per record type |
recently_modified |
Records modified since a given timestamp |
deleted_records |
Recycle bin contents, which standard queries do not return |
object_relationships |
The lookup map for an object |
field_value_distribution |
Value distribution with percentages |
api_usage |
Remaining daily API allowance |
Orphaned references
Salesforce enforces referential integrity on lookup and master-detail fields: deleting a parent record clears the child's value, cascades the delete, or is blocked. Genuine lookup fields therefore rarely dangle.
The orphaned references that occur in practice reside in text fields holding record IDs from another object or another system, where no constraint applies. The orphaned_lookups macro supports both cases: the Parent Object parameter is optional for a true lookup field, where the target is read from the field describe, and required for a text field.
Data Profiles
Profiles are typed. Minimum and maximum are three distinct profiles by result type, so that numeric values sort numerically and dates render as dates.
Table level: record count, column count.
All column types: null count, null percent, distinct count, distinct percent, sample size.
Numeric columns: minimum, maximum, mean, standard deviation, zero count, zero percent, negative count, negative percent.
Text columns: minimum, maximum, minimum length, maximum length, mean length, blank count, blank percent.
Date columns: minimum date, maximum date.
Exact and sampled values
Null counts, distinct counts, minimums, maximums, and means are exact, computed by SOQL aggregates batched across multiple fields per query. Zero and negative counts are also exact, each issued as a separate query, as SOQL provides no conditional aggregate.
Values SOQL cannot compute server-side are derived from a single sampled page, 2,000 records by default: string lengths, standard deviation, and any statistic on a field type SOQL does not aggregate. Every column carries a sample_size profile recording the basis.
SOQL does not aggregate textarea, multipicklist, boolean, base64, address, or location fields. Statistics for those field types are derived from the sample.
Blank count is always zero. Salesforce normalizes empty text to null, so no blank value is distinct from a null. The profile is emitted as an explicit zero rather than omitted.
API Consumption
Salesforce meters API calls. Developer Edition allows 15,000 per 24-hour period; paid editions allow more but remain finite. The allowance is shared across all integrations in the org.
| Operation | Approximate cost |
|---|---|
| Metadata ingestion | One global describe, plus one describe per object |
| Profile set | One count and one sample per object, plus two per numeric field |
| Macro test | One to three calls |
The include_objects allowlist is recommended on orgs where the allowance is constrained. An unfiltered Developer Edition org exposes more than 1,600 objects. The built-in exclusion list removes platform objects (*Share, *History, *Feed, *ChangeEvent, *__e, *__mdt); an explicit allowlist is more precise.
The api_usage macro reports the remaining allowance and can be scheduled as a test.
Installation
- Apply the catalog custom fields: Settings → Catalog Custom Fields → Import, using
salesforce-crm-catalog-custom-fields.xml. This must precede the first ingestion. - Import the template: Settings → Data Source Templates → Import.
- Create a data source from the template and supply the connection parameters.
- Run technical metadata ingestion.
Known Limitations
- SOQL has no
SELECT *. Every query enumerates its fields, which requires a describe call first. Theobject_datamacro is bounded by a row limit for this reason. - Compound fields cannot appear in a field list. Address and Geolocation fields are excluded automatically. Their components, such as
BillingCityandLocation__Latitude__s, are queryable normally. - SOQL supports parent-child relationship queries only. Arbitrary joins are not available. The
orphaned_lookupsmacro resolves its comparison in a second pass; work requiring genuine joins is better served by the ODBC template. - Query limits are 2,000 records per page and 50,000 per query. The template pages transparently. Larger extracts require Bulk API 2.0.
- Encrypted fields cannot be filtered, grouped, or profiled meaningfully.
- Field-level security applies. The catalog reflects the visibility of the integration user. A field hidden from that user is absent from the describe response entirely and is indistinguishable from a field that does not exist.
Verification
Verified against a live Salesforce Developer Edition org: 26 of 26 elements passed — connection, pre-execution script, metadata ingestion, all 22 macros, and the profile set — on both the client credentials and JWT authentication modes.
The verification fixture contains 1,050 records across six objects with seven counted defects: 15 orphaned references, 5 duplicate email groups, 25 missing category values, 12 negative amounts, 9 zero quantities, 8 out-of-range close dates, and 3 case-variant account names. Every macro assertion is an exact row count against those values.