# Salesforce Lead Pusher — Upsert Leads & Contacts (`ryanclinton/salesforce-lead-pusher`) Actor

Imports leads from any Apify scraper directly into Salesforce CRM as Leads, Contacts, or Accounts. Email deduplication, 200-record batch upserts, custom field mapping, and free dry-run preview. B2B CRM sync at $0.05 per lead created.

- **URL**: https://apify.com/ryanclinton/salesforce-lead-pusher.md
- **Developed by:** [ryan clinton](https://apify.com/ryanclinton) (community)
- **Categories:** Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $50.00 / 1,000 lead pusheds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## Salesforce Lead Pusher

Salesforce Lead Pusher takes enriched lead data from any source and pushes it directly into your Salesforce CRM as Leads, Contacts, or Accounts — with automatic deduplication by email, 200-record batch upserts, and a dry-run preview mode that costs nothing. Built for sales teams and RevOps engineers who want a direct pipeline from Apify scrapers into Salesforce without writing Apex code.

Connect it to any Apify actor output — B2B Lead Gen Suite, Google Maps Lead Enricher, Website Contact Scraper, or a plain CSV — and your Salesforce records update automatically. The actor handles OAuth authentication, field normalization, rate-limit retries, and per-record error reporting in a single run.

### What data can you push to Salesforce?

| Data Point | Salesforce Field | Example |
|---|---|---|
| 📧 **Email** | `Email` | sarah.chen@acmecorp.com |
| 👤 **Full name** (auto-split) | `FirstName` + `LastName` | Sarah / Chen |
| 📞 **Phone** | `Phone` | +1-415-555-0192 |
| 📱 **Mobile** | `MobilePhone` | +1-415-555-8847 |
| 🏢 **Company name** | `Company` (Lead) / `Name` (Account) | Acme Corp |
| 💼 **Job title** | `Title` | VP of Engineering |
| 🌐 **Website / Domain** | `Website` | https://acmecorp.com |
| 🏭 **Industry** | `Industry` | Technology |
| 📍 **City, State, Country** | `City` / `State` / `Country` | San Francisco / CA / US |
| 🏷️ **Lead source** | `LeadSource` | Web |
| ⭐ **Rating** | `Rating` | Hot |
| 👥 **Employee count** | `NumberOfEmployees` | 250 |
| 💰 **Annual revenue** | `AnnualRevenue` | 12000000 |
| 📝 **Description / Notes** | `Description` | Met at SaaStr 2025 |
| 🏷️ **Custom fields** | Any `Field__c` | `LinkedIn_URL__c` |

### Why use Salesforce Lead Pusher?

Building a manual import workflow for every lead source is the kind of work that never actually gets done. Someone exports a CSV, someone else reformats columns to match Salesforce field names, duplicates slip in, the import fails on bad data, and by the time the leads land in CRM the outreach window has closed. Most teams fall back to copy-pasting or abandon the pipeline entirely.

This actor automates the entire process: authenticate once, point it at a dataset, and every qualifying lead lands in Salesforce as a structured record — deduplicated against what already exists, with all standard fields mapped automatically and custom fields handled via a JSON mapping config.

- **Scheduling** — run daily, weekly, or on a trigger to push fresh leads as they arrive from your scraping pipeline
- **API access** — call from Python, JavaScript, or any HTTP client to embed this in an existing orchestration layer
- **Proxy rotation** — not needed for CRM pushes, but Apify's infrastructure handles reliable outbound connectivity
- **Monitoring** — receive Slack or email alerts when a run fails, producing zero records, or hits Salesforce rate limits
- **Integrations** — chain via Dataset ID from any other Apify actor, or trigger via Zapier, Make, or webhooks

### Features

- **OAuth 2.0 username-password authentication** — connects to any Salesforce org using a Connected App Consumer Key + Secret; supports both production (`login.salesforce.com`) and sandbox (`test.salesforce.com`) orgs
- **Salesforce Composite Collections API** — pushes records 200 at a time using the `/composite/sobjects` endpoint, the fastest bulk-create path available without governor-limit concerns from Bulk API 2.0 quotas
- **Three object types** — push the same lead data as a `Lead` (unqualified prospect), `Contact` (person linked to an Account), or `Account` (company/organisation) depending on where you are in the sales cycle
- **Email-based deduplication** — before each batch, runs a SOQL query in chunks of 50 to find existing Leads or Contacts by email; for Accounts, deduplicates by company name. Existing records are skipped and logged
- **Full name splitting** — `"Sarah Chen"` becomes `FirstName: "Sarah"` and `LastName: "Chen"` automatically; single-word names go to `LastName`; pre-split `firstName`/`lastName` fields pass through unchanged
- **Flexible input normalization** — accepts `email` or `emails[]`, `phone` or `phones[]`, `companyName` or `company`, `website` or `domain`, `jobTitle` or `title` — compatible with output from any Apify actor without preprocessing
- **Custom field mapping** — pass a JSON object to map any input field to any Salesforce API field name, including custom `__c` fields: `{"linkedinUrl": "LinkedIn_URL__c"}`
- **Dry-run mode enabled by default** — previews every mapped record in the dataset output without creating anything in Salesforce; shows exactly which fields would be set on each record
- **Per-record error reporting** — each record in the output carries an `action` status (`created`, `skipped_duplicate`, `skipped_dry_run`, `failed`) and an `error` field with the Salesforce error code and message if the push failed
- **Rate-limit retry** — detects `REQUEST_LIMIT_EXCEEDED` HTTP 403 responses and waits 10 seconds before a single automatic retry; network errors get a 2-second retry
- **Spending limit enforcement** — PPE charging fires after data is saved to the dataset; stops cleanly when the run's spending cap is reached rather than crashing mid-batch
- **Summary record** — the final dataset item is a `type: "summary"` record with totals: created, updated, skipped duplicates, skipped dry-run, failed
- **Dataset chaining** — provide a `datasetId` to pull leads directly from another actor's output dataset, up to 5,000 records per run

### Use cases for Salesforce lead pushing

#### Sales prospecting pipeline

SDRs and BDRs using tools like Website Contact Scraper or Google Maps Lead Enricher end up with hundreds of qualified contacts sitting in a spreadsheet. This actor closes the loop: run the scraper, pass its dataset ID to Salesforce Lead Pusher, and every new contact appears in Salesforce within minutes — ready for assignment, sequencing, or automatic lead routing rules.

#### Marketing agency lead delivery

Agencies running lead gen campaigns for clients need to hand off structured CRM records, not CSV attachments. Point the actor at a completed B2B Lead Gen Suite dataset, set `objectType` to `Lead`, and deliver clean Salesforce records directly to the client's org. Duplicates are filtered automatically, so the client never complains about seeing the same contact twice.

#### RevOps data enrichment

Revenue operations teams enriching existing accounts with fresh firmographic data can push updated fields — employee count, annual revenue, industry — into existing Account records. The `fieldMapping` config maps any enrichment actor's output field to the correct Salesforce field without touching the existing record structure.

#### Recruiting and talent sourcing

Recruiters extracting hiring manager contacts from LinkedIn scrapers or conference attendee lists can push directly into Salesforce as Contacts or Leads, with job title, department, and company mapped automatically. The email-based deduplication prevents the same contact from appearing in multiple hiring pipelines.

#### Automated daily lead imports

Teams running scheduled Apify actors (nightly scrapes, weekly enrichment jobs) can chain Salesforce Lead Pusher at the end of the pipeline via webhooks or the Apify API. New leads from the previous day's run land in Salesforce before the sales team starts work in the morning — no manual import step required.

#### Conference and event lead capture

After events, lead lists arrive in inconsistent formats. The actor's flexible field normalization handles varying column names (`email`, `emails`, `Email Address`) without preprocessing. Push 500 event leads into Salesforce in one run, with the dry-run preview confirming the mapping looks correct before committing.

### How to push leads to Salesforce

1. **Create a Salesforce Connected App** — go to Salesforce Setup, search for "App Manager", click "New Connected App". Enable OAuth 2.0, add the `api` scope, save, and copy your Consumer Key and Consumer Secret. This takes about 5 minutes and only needs to be done once.

2. **Prepare your credentials** — your password must be your Salesforce login password concatenated with your security token (no space, no separator). If your password is `Summer2025!` and your token is `abc123XYZ`, enter `Summer2025!abc123XYZ`. Get your security token at Setup > My Personal Information > Reset Security Token.

3. **Configure the actor** — paste your Consumer Key, Consumer Secret, username, and combined password into the credential fields. Set `objectType` to `Lead` for new prospects. Leave `dryRun` set to `true` for the first run. Paste your lead records into the `leads` array, or enter a `datasetId` from a previous actor run.

4. **Preview, then push** — run with dry-run enabled and check the output dataset. Each record shows which Salesforce fields would be set. When the mapping looks correct, run again with `dryRun: false`. Results land in Salesforce in under a minute for batches under 1,000 records.

### Input parameters

| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| `salesforceUsername` | string | Yes (live) | — | Salesforce login email, e.g. `user@mycompany.com` |
| `salesforcePassword` | string | Yes (live) | — | Password + security token concatenated, no separator |
| `salesforceClientId` | string | Yes (live) | — | Consumer Key from your Salesforce Connected App |
| `salesforceClientSecret` | string | Yes (live) | — | Consumer Secret from your Salesforce Connected App |
| `salesforceLoginUrl` | string | No | `https://login.salesforce.com` | Use `https://test.salesforce.com` for sandbox orgs |
| `leads` | array | No | — | Inline lead records to push; accepts flexible field names |
| `datasetId` | string | No | — | Apify dataset ID to load leads from (up to 5,000 items) |
| `objectType` | string | No | `Lead` | Salesforce object: `Lead`, `Contact`, or `Account` |
| `skipDuplicates` | boolean | No | `true` | Query Salesforce before inserting; skip matching email/name |
| `fieldMapping` | object | No | `{}` | Map input fields to Salesforce API field names |
| `dryRun` | boolean | No | `true` | Preview mapping without writing to Salesforce |
| `maxLeads` | integer | No | `500` | Cap records per run (1–5,000) |

#### Input examples

**Push a single lead in dry-run mode (recommended first run):**
```json
{
  "leads": [
    {
      "name": "Sarah Chen",
      "email": "sarah.chen@acmecorp.com",
      "phone": "+1-415-555-0192",
      "companyName": "Acme Corp",
      "jobTitle": "VP of Engineering",
      "industry": "Technology",
      "website": "https://acmecorp.com",
      "city": "San Francisco",
      "state": "CA",
      "country": "US",
      "description": "Met at SaaStr 2025. Interested in automation tools."
    }
  ],
  "objectType": "Lead",
  "dryRun": true
}
````

**Pull from a dataset and push live to Salesforce with custom field mapping:**

```json
{
  "salesforceUsername": "admin@mycompany.com",
  "salesforcePassword": "MyPass123TOKEN456abc",
  "salesforceClientId": "3MVG9...",
  "salesforceClientSecret": "1234567890ABCDEF",
  "datasetId": "abc123xyzDatasetId",
  "objectType": "Lead",
  "skipDuplicates": true,
  "fieldMapping": {
    "linkedinUrl": "LinkedIn_URL__c",
    "score": "Lead_Score__c",
    "sourceActor": "Lead_Source_Actor__c"
  },
  "dryRun": false,
  "maxLeads": 500
}
```

**Push to a Salesforce sandbox for testing:**

```json
{
  "salesforceUsername": "admin@mycompany.com.sandbox",
  "salesforcePassword": "MyPass123TOKEN456abc",
  "salesforceClientId": "3MVG9...",
  "salesforceClientSecret": "1234567890ABCDEF",
  "salesforceLoginUrl": "https://test.salesforce.com",
  "leads": [
    {
      "name": "Marcus Rivera",
      "email": "m.rivera@betaindustries.com",
      "companyName": "Beta Industries",
      "jobTitle": "Head of Sales"
    }
  ],
  "objectType": "Lead",
  "dryRun": false
}
```

#### Input tips

- **Run dry-run first** — always preview with `dryRun: true` before committing. The output shows every Salesforce field that would be set; check that `LastName` and `Company` are populated correctly before going live.
- **Concatenate password + security token** — the most common setup error is entering only the password. Salesforce requires the security token appended immediately after the password with no separator.
- **Use sandbox for integration testing** — set `salesforceLoginUrl` to `https://test.salesforce.com` and append `.sandbox` to the username (e.g. `admin@mycompany.com.sandbox`) to push to a sandbox org without touching production data.
- **Chain via datasetId to avoid copy-paste** — pass the dataset ID from any other actor's run directly. The actor loads up to 5,000 records automatically, normalizing field name variations across different actor output formats.
- **Use fieldMapping for custom fields** — any Salesforce custom field (those ending in `__c`) must be mapped explicitly. Add `{"sourceField": "SalesforceField__c"}` to the `fieldMapping` object for each custom field you want to populate.

### Output example

```json
{
  "inputName": "Sarah Chen",
  "inputEmail": "sarah.chen@acmecorp.com",
  "inputCompany": "Acme Corp",
  "salesforceId": "00Q8Z000001GxAbUAK",
  "objectType": "Lead",
  "action": "created",
  "error": null,
  "pushedAt": "2025-09-14T09:22:11.843Z"
}
```

**Summary record (last item in every dataset):**

```json
{
  "type": "summary",
  "objectType": "Lead",
  "totalProcessed": 47,
  "created": 39,
  "updated": 0,
  "skippedDuplicates": 7,
  "skippedDryRun": 0,
  "failed": 1,
  "dryRun": false,
  "instanceUrl": "https://mycompany.my.salesforce.com",
  "completedAt": "2025-09-14T09:23:04.217Z"
}
```

**Dry-run record (no Salesforce ID, no charge):**

```json
{
  "inputName": "Marcus Rivera",
  "inputEmail": "m.rivera@betaindustries.com",
  "inputCompany": "Beta Industries",
  "salesforceId": null,
  "objectType": "Lead",
  "action": "skipped_dry_run",
  "error": null,
  "pushedAt": "2025-09-14T09:20:55.012Z"
}
```

### Output fields

| Field | Type | Description |
|---|---|---|
| `inputName` | string | null | Name from the input record as provided |
| `inputEmail` | string | null | Email resolved from `email` or first item of `emails[]` |
| `inputCompany` | string | null | Company resolved from `companyName` or `company` |
| `salesforceId` | string | null | Salesforce record ID (e.g. `00Q8Z000001GxAb`) on success; null otherwise |
| `objectType` | string | Salesforce object type: `Lead`, `Contact`, or `Account` |
| `action` | string | One of: `created`, `updated`, `skipped_duplicate`, `skipped_dry_run`, `failed` |
| `error` | string | null | Salesforce error code and message if `action` is `failed`; null otherwise |
| `pushedAt` | string | ISO 8601 timestamp of when the record was processed |
| `type` | string | `"summary"` on the final summary record only |
| `totalProcessed` | integer | Summary: total records processed in the run |
| `created` | integer | Summary: records successfully created in Salesforce |
| `updated` | integer | Summary: records updated (reserved; currently always 0) |
| `skippedDuplicates` | integer | Summary: records skipped because they already existed |
| `skippedDryRun` | integer | Summary: records skipped because dry-run was enabled |
| `failed` | integer | Summary: records that Salesforce rejected with an error |
| `instanceUrl` | string | null | Summary: Salesforce instance URL used for this run |
| `completedAt` | string | Summary: ISO 8601 timestamp when the run finished |

### How much does it cost to push leads to Salesforce?

Salesforce Lead Pusher uses **pay-per-event pricing** — you pay **$0.05 per lead successfully created in Salesforce**. Dry-run runs are completely free. Skipped duplicates are free. Failed records are free. You only pay when a record is actually written to your CRM.

| Scenario | Leads pushed | Cost per lead | Total cost |
|---|---|---|---|
| Quick test (dry-run) | Any | $0.00 | $0.00 |
| Small batch | 10 | $0.05 | $0.50 |
| Medium batch | 100 | $0.05 | $5.00 |
| Large batch | 500 | $0.05 | $25.00 |
| Enterprise batch | 1,000 | $0.05 | $50.00 |

You can set a **maximum spending limit** per run to control costs. The actor stops cleanly when your budget is reached — no partial batches left in an unknown state.

Compare this to Zapier's Salesforce integration at $49–299/month for automation tasks, or a custom Salesforce integration developer at $150+/hour. Most teams pushing 200–500 leads per week spend under $10/month with no subscription commitment.

### Push leads to Salesforce using the API

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run = client.actor("ryanclinton/salesforce-lead-pusher").call(run_input={
    "salesforceUsername": "admin@mycompany.com",
    "salesforcePassword": "MyPass123TOKEN456abc",
    "salesforceClientId": "3MVG9...",
    "salesforceClientSecret": "1234567890ABCDEF",
    "leads": [
        {
            "name": "Sarah Chen",
            "email": "sarah.chen@acmecorp.com",
            "companyName": "Acme Corp",
            "jobTitle": "VP of Engineering",
            "industry": "Technology"
        }
    ],
    "objectType": "Lead",
    "skipDuplicates": True,
    "dryRun": False
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    if item.get("type") == "summary":
        print(f"Run complete: {item['created']} created, {item['skippedDuplicates']} duplicates skipped")
    elif item.get("action") == "created":
        print(f"Created: {item['inputName']} ({item['inputEmail']}) → SF ID: {item['salesforceId']}")
    elif item.get("action") == "failed":
        print(f"Failed: {item['inputEmail']} — {item['error']}")
```

#### JavaScript

```javascript
import { ApifyClient } from "apify-client";

const client = new ApifyClient({ token: "YOUR_API_TOKEN" });

const run = await client.actor("ryanclinton/salesforce-lead-pusher").call({
    salesforceUsername: "admin@mycompany.com",
    salesforcePassword: "MyPass123TOKEN456abc",
    salesforceClientId: "3MVG9...",
    salesforceClientSecret: "1234567890ABCDEF",
    leads: [
        {
            name: "Marcus Rivera",
            email: "m.rivera@betaindustries.com",
            companyName: "Beta Industries",
            jobTitle: "Head of Sales",
        }
    ],
    objectType: "Lead",
    skipDuplicates: true,
    dryRun: false,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) {
    if (item.type === "summary") {
        console.log(`Done: ${item.created} created, ${item.skippedDuplicates} skipped, ${item.failed} failed`);
    } else if (item.action === "created") {
        console.log(`Pushed: ${item.inputName} → ${item.salesforceId}`);
    }
}
```

#### cURL

```bash
## Start the actor run
curl -X POST "https://api.apify.com/v2/acts/ryanclinton~salesforce-lead-pusher/runs?token=YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "salesforceUsername": "admin@mycompany.com",
    "salesforcePassword": "MyPass123TOKEN456abc",
    "salesforceClientId": "3MVG9...",
    "salesforceClientSecret": "1234567890ABCDEF",
    "leads": [{"name": "Sarah Chen", "email": "sarah.chen@acmecorp.com", "companyName": "Acme Corp"}],
    "objectType": "Lead",
    "dryRun": false
  }'

## Fetch results (replace DATASET_ID from the run response defaultDatasetId field)
curl "https://api.apify.com/v2/datasets/DATASET_ID/items?token=YOUR_API_TOKEN&format=json"
```

### How Salesforce Lead Pusher works

#### Authentication phase

The actor authenticates using the Salesforce OAuth 2.0 username-password flow, posting credentials to `/services/oauth2/token` with `grant_type=password`. This returns an `access_token` and `instance_url` specific to your org. The token is reused for all subsequent requests in the run — there is no token refresh logic since runs complete in well under the one-hour token expiry window. In dry-run mode, authentication is skipped entirely.

#### Deduplication query phase

Before pushing each batch of up to 200 records, the actor runs SOQL queries to find existing records. It queries in chunks of 50 values to stay within URL length limits: `SELECT Id, Email FROM Lead WHERE Email IN ('email1@co.com', 'email2@co.com', ...)`. The result set is loaded into a `Set<string>` of lowercase lookup keys. For Account objects, the lookup uses `Name` instead of `Email`. Records with a matching key are tagged `skipped_duplicate` without touching Salesforce.

#### Batch push phase

Active (non-duplicate) records in each batch are mapped to Salesforce field names using `mapToSalesforceFields()`. This function handles object-type differences — Contact uses `MailingCity` where Lead uses `City`, Account uses `BillingCity` and maps `company` to `Name`. Full names are split by whitespace with the last token becoming `LastName` and everything prior becoming `FirstName`. The mapped records are submitted to the Salesforce Composite Collections endpoint (`/composite/sobjects`) in a single POST. The `allOrNone: false` flag means individual record failures do not roll back the rest of the batch.

#### Error handling and charging phase

Each item in the Composite API response maps 1-to-1 with the submitted records by position. Records where `success: true` are logged as `created` and trigger a PPE charge event (`Actor.charge({ eventName: "lead-pushed", count: N })`). Records where `success: false` have their `errors[]` array serialized into the output `error` field (`statusCode: message` format). The actor checks `eventChargeLimitReached` after each batch charge and stops cleanly if the run's spending cap is hit.

### Tips for best results

1. **Always dry-run first.** The dry-run output shows exactly which Salesforce fields would be populated for each record. Check that `Company` is set for Leads (defaults to `"Unknown Company"` if no company field is found) and that names split correctly before committing a large batch.

2. **Concatenate password and security token correctly.** This is the most common configuration error. Your Salesforce security token is a separate alphanumeric string sent to your email when you reset it. It goes immediately after your password with no space or separator. If you change your password, Salesforce resets your token.

3. **Use sandbox for initial integration testing.** Set `salesforceLoginUrl` to `https://test.salesforce.com` and append `.sandbox` or the sandbox name to your username (e.g. `admin@mycompany.com.uat`). This lets you verify the full push pipeline against real Salesforce API behavior without risking production data.

4. **Chain with B2B Lead Gen Suite for a full pipeline.** Run [B2B Lead Gen Suite](https://apify.com/ryanclinton/b2b-lead-gen-suite) or [Google Maps Lead Enricher](https://apify.com/ryanclinton/google-maps-lead-enricher) to build your lead list, then pass the output `datasetId` directly to this actor. No CSV export, no reformatting.

5. **Set maxLeads conservatively for testing.** When testing with a real production dataset, set `maxLeads` to `5` or `10` to verify a small sample before processing the full list. This costs $0.25–$0.50 and confirms everything maps correctly.

6. **Map custom fields before you need them.** If your Salesforce org has custom fields (`Lead_Score__c`, `Source_Actor__c`, `LinkedIn_URL__c`), configure them in `fieldMapping` during the dry-run phase. Custom fields must be explicitly mapped — they are not picked up automatically.

7. **Verify the Connected App OAuth scopes.** The Connected App must have at minimum the `api` scope enabled. If you see `INSUFFICIENT_ACCESS` errors in the output, check Setup > App Manager > your app > OAuth Scopes and add `api`. The `refresh_token` scope is not required.

8. **Filter failed records for follow-up.** Filter the output dataset by `action: "failed"` and check the `error` field. Common failure reasons: `REQUIRED_FIELD_MISSING` (usually `LastName` or `Company`), `INVALID_EMAIL_ADDRESS`, or `FIELD_CUSTOM_VALIDATION_EXCEPTION` from org-specific validation rules.

### Combine with other Apify actors

| Actor | How to combine |
|---|---|
| [B2B Lead Gen Suite](https://apify.com/ryanclinton/b2b-lead-gen-suite) | Full pipeline: scrape websites → enrich → push to Salesforce via datasetId |
| [Google Maps Lead Enricher](https://apify.com/ryanclinton/google-maps-lead-enricher) | Search Google Maps for local businesses, enrich with contacts, push as Leads |
| [Website Contact Scraper](https://apify.com/ryanclinton/website-contact-scraper) | Extract emails and phones from company websites, push directly as Salesforce Leads |
| [Waterfall Contact Enrichment](https://apify.com/ryanclinton/waterfall-contact-enrichment) | Enrich partial records through 10 data sources, then push the enriched output to Salesforce |
| [Email Pattern Finder](https://apify.com/ryanclinton/email-pattern-finder) | Discover email naming patterns for a domain, build full email addresses, push to CRM |
| [Bulk Email Verifier](https://apify.com/ryanclinton/bulk-email-verifier) | Verify email deliverability before pushing — avoid invalid addresses triggering Salesforce validation errors |
| [HubSpot Lead Pusher](https://apify.com/ryanclinton/hubspot-lead-pusher) | Push the same lead dataset to HubSpot in parallel for teams using dual CRM setups |

### Limitations

- **Creates only, no updates.** The actor creates new records. It does not update existing Salesforce records — when `skipDuplicates` is `true`, existing matches are skipped; when `false`, Salesforce will return a duplicate error for records that violate your org's duplicate rules. A true upsert (update-on-match) is not currently supported.
- **Up to 5,000 leads per run from a dataset.** The `listItems` call is capped at 5,000 items. For larger datasets, split into multiple runs using `maxLeads` and offset logic in a parent orchestrator.
- **Password flow requires security token.** If your Salesforce org enforces IP restrictions, you must append the security token to the password. Orgs with "trusted IP ranges" covering Apify's IP space may not require it, but this varies by org configuration.
- **No Salesforce Bulk API support.** The Composite Collections API is used instead of Bulk API 2.0. This is intentional — Bulk API jobs require polling, add latency, and consume a separate daily job limit quota. The Composite API handles up to 200 records per call with synchronous results.
- **Contact object requires an existing Account.** When pushing as `Contact`, Salesforce requires an `AccountId` field linking to an existing Account record. The actor does not auto-create Accounts for Contacts. Use the `fieldMapping` to pass a known AccountId, or push as `Lead` instead.
- **Custom validation rules may reject records.** If your Salesforce org has custom validation rules or required custom fields, records may fail with `FIELD_CUSTOM_VALIDATION_EXCEPTION`. These are reported in the `error` field of each failed output record but cannot be handled generically.
- **Sandbox usernames differ from production.** Sandbox usernames typically have `.sandbox` or a sandbox name appended. The actor cannot auto-detect sandbox vs. production from the login URL alone — ensure the username matches the target org.
- **No support for Person Accounts.** Salesforce orgs with Person Accounts enabled treat individuals as Accounts rather than Contacts or Leads. The actor does not detect this configuration. Use `objectType: "Lead"` for person-level records in orgs with Person Accounts.

### Integrations

- [Zapier](https://apify.com/integrations/zapier) — trigger a Salesforce Lead Pusher run when new leads arrive in a Google Sheet or Airtable base
- [Make](https://apify.com/integrations/make) — chain actor runs in a Make scenario: scraper → enrichment → Salesforce push in a single automated workflow
- [Google Sheets](https://apify.com/integrations/google-sheets) — export the push results to Google Sheets for stakeholder reporting on leads created vs. duplicates skipped
- [Apify API](https://docs.apify.com/api/v2) — trigger runs programmatically from your own CRM middleware or ETL pipeline
- [Webhooks](https://docs.apify.com/platform/integrations/webhooks) — notify your team via Slack or email when a push run completes, with the summary record included in the payload
- [LangChain / LlamaIndex](https://docs.apify.com/platform/integrations) — use [Company Deep Research](https://apify.com/ryanclinton/company-deep-research) to generate AI-enriched company summaries, then push the enriched records to Salesforce via this actor

### Troubleshooting

**Authentication fails with "INVALID\_CLIENT\_CREDENTIALS" or HTTP 400** — the Consumer Key or Consumer Secret is incorrect. Double-check by copying them fresh from Setup > App Manager > your Connected App > Manage Consumer Details. Ensure the Connected App has "Enable OAuth Settings" checked and the `api` scope is listed. If you just created the Connected App, wait 2–10 minutes for Salesforce to propagate the settings before retrying.

**Records fail with "REQUIRED\_FIELD\_MISSING: LastName"** — the input records have no `name`, `firstName`, or `lastName` field. The actor defaults `LastName` to `"Unknown"` when no name data is found, but some org configurations override this. Check that your input records include a name field in any of the supported formats.

**Records fail with "REQUIRED\_FIELD\_MISSING: Company"** — Lead records require a Company value. The actor defaults to `"Unknown Company"` when no `companyName` or `company` field is found. If you see this error, your Salesforce org has a validation rule making the default value unacceptable. Add a `company` field to your input records.

**Deduplication is not catching existing records** — ensure `skipDuplicates` is `true`. Deduplication checks Salesforce's existing records by email for Leads/Contacts, or by name for Accounts. If your existing records used a different email format (uppercase vs lowercase), deduplication uses case-insensitive matching — but if emails differ entirely, duplicates will not be caught. The dedup query also does not paginate beyond 50 values per SOQL chunk — for very large batches with many pre-existing records, some may slip through.

**Run is slow for large batches** — the deduplication SOQL query runs before each batch of 200. For 1,000 leads this means 5 batch cycles, each with a SOQL query. This is expected behavior. Disable `skipDuplicates` if your dataset is known to be clean and you want maximum throughput.

### Responsible use

- This actor only writes data you explicitly provide — it does not scrape or collect data independently.
- Ensure the personal data you push to Salesforce was collected with appropriate consent under GDPR, CAN-SPAM, CCPA, and other applicable data protection laws.
- Do not use this actor to push data obtained through unauthorized scraping of protected or private systems.
- Respect your Salesforce org's data governance policies and duplicate management rules.
- For guidance on web scraping legality, see [Apify's guide](https://blog.apify.com/is-web-scraping-legal/).

### FAQ

**How do I push leads to Salesforce from another Apify actor?** — run the source actor (e.g. [B2B Lead Gen Suite](https://apify.com/ryanclinton/b2b-lead-gen-suite)), copy the dataset ID from its run detail page, and paste it into the `datasetId` field of Salesforce Lead Pusher. The actor loads up to 5,000 records automatically with no export step.

**Does Salesforce Lead Pusher update existing records or only create new ones?** — it creates new records only. When `skipDuplicates` is `true`, records with a matching email or company name in Salesforce are skipped and logged as `skipped_duplicate`. True update-on-match (upsert) is not currently supported.

**How many leads can I push to Salesforce in one run?** — up to 5,000 from a dataset, or as many as you provide inline (subject to the `maxLeads` cap, default 500). Increase `maxLeads` up to 5,000 for larger batches. For datasets over 5,000 records, split across multiple runs.

**Is it safe to test against my production Salesforce org?** — use dry-run mode (`dryRun: true`) to validate field mapping without writing anything. For full live testing, use a Salesforce sandbox org — set `salesforceLoginUrl` to `https://test.salesforce.com` and use your sandbox username.

**What Salesforce editions does this work with?** — any Salesforce edition that supports Connected Apps and the REST API: Essentials, Professional (with API add-on), Enterprise, Unlimited, and Developer Edition. The Composite Collections API endpoint used is available in all REST API-enabled orgs on API version 59.0 and later.

**How is this different from Salesforce's built-in data import wizard?** — the import wizard requires manual CSV exports, column header matching, and manual deduplication. This actor runs on a schedule, accepts data directly from other Apify actors, handles field normalization automatically, and produces per-record audit output showing exactly what was created, skipped, or failed.

**How much does it cost to push 1,000 leads to Salesforce?** — $50.00 total ($0.05 per successfully created record). Dry-run runs, skipped duplicates, and failed records are not charged. Set a spending limit on the run if you want to cap costs — the actor stops cleanly when the limit is reached.

**Can I push Salesforce Contacts instead of Leads?** — yes, set `objectType` to `Contact`. Note that Contacts in Salesforce typically require an `AccountId` linking them to an existing Account. If your Contact records do not include an AccountId, they may fail with a validation error in orgs where AccountId is required. Use `Lead` for unqualified prospects.

**Is it legal to push scraped contacts into Salesforce CRM?** — legality depends on how the contact data was collected and the jurisdiction. In the EU, GDPR requires a lawful basis for processing personal data. In the US, CAN-SPAM and CCPA apply to marketing use. You are responsible for ensuring the data you push was collected lawfully. See [Apify's web scraping legal guide](https://blog.apify.com/is-web-scraping-legal/) for detailed guidance.

**What happens if Salesforce rate limits the actor mid-run?** — the actor detects `REQUEST_LIMIT_EXCEEDED` (HTTP 403) responses and automatically waits 10 seconds before retrying the batch once. If the retry also fails, the batch is marked as failed in the output. Most orgs have a daily API request limit of 100,000–1,000,000 — a single run pushing 500 records uses 3–6 API calls total.

**Can I schedule this actor to run automatically?** — yes. Use Apify's built-in scheduler to run daily, weekly, or at custom intervals. Combine with a scheduled scraping actor upstream and use `datasetId` chaining to keep Salesforce updated automatically without any manual steps.

**How do I map a custom Salesforce field like `LinkedIn_URL__c`?** — add it to the `fieldMapping` input: `{"linkedinUrl": "LinkedIn_URL__c"}`. The left side is the field name in your input data, the right side is the Salesforce API field name. Custom fields always end in `__c`. You can map as many custom fields as needed.

### Help us improve

If you encounter issues, you can help us debug faster by enabling run sharing in your Apify account:

1. Go to [Account Settings > Privacy](https://console.apify.com/account/privacy)
2. Enable **Share runs with public Actor creators**

This lets us see your run details when something goes wrong, so we can fix issues faster. Your data is only visible to the actor developer, not publicly.

### Support

Found a bug or have a feature request? Open an issue in the [Issues tab](https://console.apify.com/actors/salesforce-lead-pusher/issues) on this actor's page. For custom Salesforce field mapping, enterprise integrations, or high-volume pipelines, reach out through the Apify platform.

# Actor input Schema

## `salesforceUsername` (type: `string`):

Your Salesforce username (email address used to log in). Example: user@mycompany.com

## `salesforcePassword` (type: `string`):

Your Salesforce password concatenated with your security token (no space). Example: MyPassword123TOKEN123. Get your security token at Setup > My Personal Information > Reset Security Token.

## `salesforceClientId` (type: `string`):

Consumer Key from your Salesforce Connected App. Create one at Setup > App Manager > New Connected App. Enable OAuth and add the 'api' scope.

## `salesforceClientSecret` (type: `string`):

Consumer Secret from your Salesforce Connected App.

## `salesforceLoginUrl` (type: `string`):

OAuth token endpoint. Use https://test.salesforce.com for sandbox orgs.

## `leads` (type: `array`):

Lead records to push to Salesforce. Each item should have at minimum an email (for deduplication) and a company name. Supports output from any Apify scraper or enrichment actor.

## `objectType` (type: `string`):

Which Salesforce object to create: Lead (unqualified prospect), Contact (person linked to an Account), or Account (company/organisation).

## `skipDuplicates` (type: `boolean`):

Query Salesforce before inserting each batch. Records with a matching Email (for Lead/Contact) or Website/Name (for Account) will be skipped rather than updated.

## `fieldMapping` (type: `object`):

Override the default field mapping. Keys are input field names, values are Salesforce API field names. Example: {"linkedinUrl": "LinkedIn\_URL\_\_c"}. Leave empty to use defaults.

## `dryRun` (type: `boolean`):

Preview the mapped Salesforce records without actually creating or updating anything. Use this to verify your field mapping before committing. Set to false to push live data.

## `maxLeads` (type: `integer`):

Maximum number of leads to process in a single run. Useful for testing with large datasets.

## Actor input object example

```json
{
  "salesforceLoginUrl": "https://login.salesforce.com",
  "leads": [
    {
      "name": "Sarah Chen",
      "email": "sarah.chen@acmecorp.com",
      "phone": "+1-415-555-0192",
      "companyName": "Acme Corp",
      "jobTitle": "VP of Engineering",
      "industry": "Technology",
      "website": "https://acmecorp.com",
      "city": "San Francisco",
      "state": "CA",
      "country": "US",
      "description": "Met at SaaStr 2025. Interested in automation tools."
    }
  ],
  "objectType": "Lead",
  "skipDuplicates": true,
  "fieldMapping": {},
  "dryRun": true,
  "maxLeads": 500
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "salesforceLoginUrl": "https://login.salesforce.com",
    "leads": [
        {
            "name": "Sarah Chen",
            "email": "sarah.chen@acmecorp.com",
            "phone": "+1-415-555-0192",
            "companyName": "Acme Corp",
            "jobTitle": "VP of Engineering",
            "industry": "Technology",
            "website": "https://acmecorp.com",
            "city": "San Francisco",
            "state": "CA",
            "country": "US",
            "description": "Met at SaaStr 2025. Interested in automation tools."
        }
    ],
    "dryRun": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("ryanclinton/salesforce-lead-pusher").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "salesforceLoginUrl": "https://login.salesforce.com",
    "leads": [{
            "name": "Sarah Chen",
            "email": "sarah.chen@acmecorp.com",
            "phone": "+1-415-555-0192",
            "companyName": "Acme Corp",
            "jobTitle": "VP of Engineering",
            "industry": "Technology",
            "website": "https://acmecorp.com",
            "city": "San Francisco",
            "state": "CA",
            "country": "US",
            "description": "Met at SaaStr 2025. Interested in automation tools.",
        }],
    "dryRun": True,
}

# Run the Actor and wait for it to finish
run = client.actor("ryanclinton/salesforce-lead-pusher").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "salesforceLoginUrl": "https://login.salesforce.com",
  "leads": [
    {
      "name": "Sarah Chen",
      "email": "sarah.chen@acmecorp.com",
      "phone": "+1-415-555-0192",
      "companyName": "Acme Corp",
      "jobTitle": "VP of Engineering",
      "industry": "Technology",
      "website": "https://acmecorp.com",
      "city": "San Francisco",
      "state": "CA",
      "country": "US",
      "description": "Met at SaaStr 2025. Interested in automation tools."
    }
  ],
  "dryRun": true
}' |
apify call ryanclinton/salesforce-lead-pusher --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=ryanclinton/salesforce-lead-pusher",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Salesforce Lead Pusher — Upsert Leads & Contacts",
        "description": "Imports leads from any Apify scraper directly into Salesforce CRM as Leads, Contacts, or Accounts. Email deduplication, 200-record batch upserts, custom field mapping, and free dry-run preview. B2B CRM sync at $0.05 per lead created.",
        "version": "1.0",
        "x-build-id": "XwET8yqVopXxSWvKb"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/ryanclinton~salesforce-lead-pusher/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-ryanclinton-salesforce-lead-pusher",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/ryanclinton~salesforce-lead-pusher/runs": {
            "post": {
                "operationId": "runs-sync-ryanclinton-salesforce-lead-pusher",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/ryanclinton~salesforce-lead-pusher/run-sync": {
            "post": {
                "operationId": "run-sync-ryanclinton-salesforce-lead-pusher",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "salesforceUsername": {
                        "title": "Salesforce Username",
                        "type": "string",
                        "description": "Your Salesforce username (email address used to log in). Example: user@mycompany.com"
                    },
                    "salesforcePassword": {
                        "title": "Salesforce Password + Security Token",
                        "type": "string",
                        "description": "Your Salesforce password concatenated with your security token (no space). Example: MyPassword123TOKEN123. Get your security token at Setup > My Personal Information > Reset Security Token."
                    },
                    "salesforceClientId": {
                        "title": "Connected App Consumer Key",
                        "type": "string",
                        "description": "Consumer Key from your Salesforce Connected App. Create one at Setup > App Manager > New Connected App. Enable OAuth and add the 'api' scope."
                    },
                    "salesforceClientSecret": {
                        "title": "Connected App Consumer Secret",
                        "type": "string",
                        "description": "Consumer Secret from your Salesforce Connected App."
                    },
                    "salesforceLoginUrl": {
                        "title": "Salesforce Login URL",
                        "type": "string",
                        "description": "OAuth token endpoint. Use https://test.salesforce.com for sandbox orgs.",
                        "default": "https://login.salesforce.com"
                    },
                    "leads": {
                        "title": "Leads (inline data)",
                        "type": "array",
                        "description": "Lead records to push to Salesforce. Each item should have at minimum an email (for deduplication) and a company name. Supports output from any Apify scraper or enrichment actor.",
                        "default": [
                            {
                                "name": "Sarah Chen",
                                "email": "sarah.chen@acmecorp.com",
                                "phone": "+1-415-555-0192",
                                "companyName": "Acme Corp",
                                "jobTitle": "VP of Engineering",
                                "industry": "Technology",
                                "website": "https://acmecorp.com",
                                "city": "San Francisco",
                                "state": "CA",
                                "country": "US",
                                "description": "Met at SaaStr 2025. Interested in automation tools."
                            }
                        ]
                    },
                    "objectType": {
                        "title": "Salesforce Object Type",
                        "enum": [
                            "Lead",
                            "Contact",
                            "Account"
                        ],
                        "type": "string",
                        "description": "Which Salesforce object to create: Lead (unqualified prospect), Contact (person linked to an Account), or Account (company/organisation).",
                        "default": "Lead"
                    },
                    "skipDuplicates": {
                        "title": "Skip duplicates",
                        "type": "boolean",
                        "description": "Query Salesforce before inserting each batch. Records with a matching Email (for Lead/Contact) or Website/Name (for Account) will be skipped rather than updated.",
                        "default": true
                    },
                    "fieldMapping": {
                        "title": "Custom field mapping (optional)",
                        "type": "object",
                        "description": "Override the default field mapping. Keys are input field names, values are Salesforce API field names. Example: {\"linkedinUrl\": \"LinkedIn_URL__c\"}. Leave empty to use defaults.",
                        "default": {}
                    },
                    "dryRun": {
                        "title": "Dry run (preview only)",
                        "type": "boolean",
                        "description": "Preview the mapped Salesforce records without actually creating or updating anything. Use this to verify your field mapping before committing. Set to false to push live data.",
                        "default": true
                    },
                    "maxLeads": {
                        "title": "Max leads to process",
                        "minimum": 1,
                        "maximum": 5000,
                        "type": "integer",
                        "description": "Maximum number of leads to process in a single run. Useful for testing with large datasets.",
                        "default": 500
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
