SalesforceWatershed

Connect Salesforce with Watershed

Deep technical guide for integrating Salesforce with Watershed for ESG reporting. Covers Bulk API 2.0, OAuth JWT flows, and carbon accounting data mapping.

Published30 April 2026
Last Updated30 April 2026
Reading Time12 min read

Implementation Guide

Overview

As organizations face increasing pressure from regulatory bodies like the SEC and the EU’s CSRD, the integration between Salesforce—the primary system of record for customer, procurement, and operational data—and Watershed—the leading enterprise climate platform—has become a mission-critical architectural requirement. This integration is fundamentally about transforming raw business activity data (spend, travel, logistics, and energy usage) into actionable carbon intelligence. Unlike simple CRM-to-marketing syncs, the Salesforce-to-Watershed pipeline requires high-fidelity data mapping, strict idempotency to prevent double-counting of emissions, and robust error handling to ensure audit-grade reporting.

The technical complexity of this integration lies in the heterogeneity of the data sources within Salesforce. While procurement data might reside in standard objects like Opportunity or Contract, more granular ESG data often lives in custom objects or specialized modules like Salesforce Net Zero Cloud. Architects must decide between a push-based model using Salesforce Platform Events or a pull-based model leveraging the Bulk API 2.0 for historical backfills. This guide focuses on building a production-grade, bidirectional sync that prioritizes data integrity and scalability, ensuring that as your Salesforce instance grows, your carbon accounting remains precise and automated.

Core Prerequisites

Before initiating the integration, ensure both environments are configured for high-volume data exchange. On the Salesforce side, a dedicated Integration User is mandatory to avoid session conflicts and to adhere to the principle of least privilege. This user should be assigned a Permission Set containing 'API Enabled' and 'View All Data' (or specific access to the objects being synced). For authentication, we recommend the OAuth 2.0 JWT Bearer Flow for server-to-server communication, which avoids the fragility of refresh tokens in long-running ETL processes. The Salesforce Connected App must be configured with the following scopes: api, refresh_token, and offline_access. Use the latest stable API version (currently v60.0 or v61.0).

On the Watershed side, you will require an API Key or an OAuth Client ID/Secret depending on your organization's security policy. Watershed’s API (v1) is RESTful and expects JSON payloads. You must also define your 'Activity Types' within the Watershed dashboard beforehand, as the integration will need to map Salesforce fields to specific Watershed activity schemas. Ensure you have identified a unique identifier in Salesforce (e.g., Id or a custom External_ID__c) that will serve as the external_id in Watershed to maintain idempotency. Finally, monitor your Salesforce API limits via the Sforce-Limit-Info header; for large-scale data migrations, the Bulk API 2.0 is the only viable path to avoid hitting concurrent request limits.

Top Enterprise Use Cases

Automated Scope 3 Procurement Tracking

One of the most impactful use cases is the automated ingestion of procurement data to calculate Scope 3 emissions. By monitoring the Contract or Order objects in Salesforce, the integration can automatically push vendor spend data to Watershed. For example, when a purchase order for cloud services or hardware is marked as 'Closed/Won', the integration triggers a request to Watershed’s Activities API. This allows for real-time visibility into supply chain emissions without manual data exports. The integration must handle currency conversion and map Salesforce vendor IDs to Watershed’s supplier database to ensure accurate emission factors are applied.

Business Travel and Expense Integration

For organizations using Salesforce to track employee travel or expenses, integrating these records with Watershed provides a granular view of Scope 3 Category 6 emissions. By syncing custom Travel_Request__c or Expense_Line_Item__c records, architects can capture data points such as flight distance, hotel nights, or car rental mileage. The technical challenge here involves normalizing disparate data formats—such as converting 'miles' to 'kilometers' or 'cabin class' strings into Watershed-compatible enums—before transmission. This ensures that the carbon footprint of every business trip is accounted for as soon as the expense is approved in Salesforce.

Facility Energy and Asset Management

Large enterprises often manage physical assets and facilities within Salesforce. By syncing data from the Asset or Location objects, organizations can automate the tracking of Scope 1 and Scope 2 emissions. This includes stationary combustion from onsite generators or purchased electricity for office buildings. The integration can be configured to listen for updates to monthly utility bill records stored in Salesforce, pushing the consumption values (kWh, therms, etc.) to Watershed. This creates a continuous audit trail that links physical assets in the CRM to their environmental impact in the ESG platform.

Step-by-Step Implementation Guide

1. Salesforce Authentication via JWT Bearer Flow

To establish a secure, non-interactive connection, implement the JWT Bearer Flow. Generate a self-signed certificate or obtain one from a CA, and upload it to the Salesforce Connected App. Your integration middleware (e.g., a Node.js service or an iPaaS) will sign a JWT with the following claims:

{
  "iss": "3MVG9q2_Ylp9Fd7BS... (Consumer Key)",
  "sub": "[email protected]",
  "aud": "https://login.salesforce.com",
  "exp": 1715856000
}

Post this JWT to /services/oauth2/token to receive an access_token. This token should be cached and reused until it expires, at which point the signing process repeats.

2. Data Extraction Strategy: Bulk API 2.0 vs. CDC

For the initial sync of historical data, use the Salesforce Bulk API 2.0. Create a job by POSTing to /services/data/v60.0/jobs/ingest. For ongoing, real-time syncs, Change Data Capture (CDC) is preferred. Enable CDC on the target objects (e.g., Account, Opportunity). Your middleware subscribes to the /data/ChangeEvents CometD topic. When a change occurs, Salesforce pushes a payload containing only the modified fields and the record ID.

Example CDC Payload:

{
  "data": {
    "schema": "Lgt9...",
    "payload": {
      "ChangeEventHeader": {
        "entityName": "Opportunity",
        "changeType": "UPDATE",
        "recordIds": ["0068W0000189v8KQAQ"]
      },
      "Amount": 50000.0,
      "StageName": "Closed Won"
    }
  }
}

3. Mapping and Transformation

Once the Salesforce data is captured, it must be transformed into the Watershed Activity schema. Watershed requires an activity_type, a timestamp, and a set of data properties specific to that type. Crucially, include the Salesforce Record ID as the external_id to ensure idempotency.

Example Watershed Activity Payload (Procurement):

{
  "external_id": "0068W0000189v8KQAQ",
  "activity_type": "purchase",
  "timestamp": "2024-05-20T10:00:00Z",
  "data": {
    "currency": "USD",
    "amount": 50000.0,
    "vendor_name": "Acme Cloud Services",
    "category": "cloud_computing",
    "description": "Annual subscription for CRM hosting"
  }
}

4. Ingesting Data into Watershed

Submit the transformed data to the Watershed Activities endpoint: POST https://api.watershedclimate.com/v1/activities. Use the Authorization: Bearer <API_KEY> header. Watershed will return a 201 Created status on success. If the external_id already exists, Watershed will update the existing record rather than creating a duplicate, which is vital for handling retries in distributed systems.

5. Handling the Feedback Loop

To make carbon data visible to Salesforce users, sync the calculated emissions back to Salesforce. Watershed can emit webhooks when an activity is processed. Configure a listener to capture these webhooks and update the corresponding Salesforce record using the PATCH method on the SObject REST endpoint.

PATCH /services/data/v60.0/sobjects/Opportunity/0068W0000189v8KQAQ
{
  "Carbon_Footprint_tCO2e__c": 12.45,
  "Watershed_Status__c": "Processed"
}

Common Pitfalls & Troubleshooting

Rate Limiting and Concurrency

Salesforce enforces strict limits on the number of concurrent long-running API requests. If your integration triggers thousands of individual REST calls during peak hours, you will encounter 403 Forbidden (Total API limit exceeded) or 503 Service Unavailable. To mitigate this, batch your requests using the Salesforce Composite API or switch to the Bulk API 2.0 for any operation involving more than 2,000 records. On the Watershed side, monitor for 429 Too Many Requests. Implement an exponential backoff strategy with jitter (e.g., starting at 1s, then 2s, 4s, up to a maximum) to handle transient rate limit bursts gracefully.

Data Quality and Unit Mismatches

A frequent failure mode in ESG integrations is the 'Unit Mismatch' error. If Salesforce provides energy data in 'kWh' but the Watershed activity type expects 'MWh', the resulting carbon calculation will be off by a factor of 1,000. Implement a validation layer in your middleware that checks for required fields and unit consistency before calling the Watershed API. If a record fails validation, log it to a Dead Letter Queue (DLQ) and alert the data engineering team via Slack or PagerDuty, rather than allowing the entire sync process to fail.

Idempotency and Race Conditions

In a high-frequency environment, there is a risk of race conditions where multiple updates for the same Salesforce record are sent to Watershed simultaneously. Always use the Salesforce SystemModStamp or a versioning field to ensure you are not overwriting a newer state with an older one. Watershed’s use of external_id handles idempotency at the record level, but your middleware must ensure that it processes events in the correct chronological order. If using AWS Lambda for the integration, consider using SQS FIFO queues to maintain message ordering.

Authentication Failures (401 Unauthorized)

JWT-based authentication is robust, but clock skew between your server and Salesforce can cause 401 Unauthorized errors. Ensure your server’s clock is synchronized via NTP. Additionally, if the Salesforce Connected App's certificate expires, the integration will fail immediately. Implement monitoring for certificate expiration dates and automate the rotation process where possible. If using API keys for Watershed, treat them as secrets (e.g., store them in AWS Secrets Manager or HashiCorp Vault) and rotate them periodically to maintain a high security posture.

Need a different integration?

If you can't find the guide you need, submit a request and I'll add it to the publishing queue.

Request an integration →