agentsclimarketplace

Salesforce core workflow b

Skill jeremylongshore/claude-code-plugins-plus-skills/plugins/saas-packs/salesforce-pack/skills/salesforce-core-workflow-b

425 plugins, 2,810 skills, 200 agents for Claude Code. Open-source marketplace at tonsofskills.com with the ccpi CLI package manager.

Install
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill salesforce-core-workflow-b

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its author says it does

Copied from the file, not written here

'Execute Salesforce Bulk API 2.0 and Composite API operations for high-volume data.

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

7.8 KB, as published. Nobody here has run it

Salesforce Core Workflow B — Bulk & Composite API

Overview

High-volume data operations using Bulk API 2.0 (millions of records) and Composite API (multi-step transactions in a single call).

Prerequisites

  • Completed salesforce-install-auth setup
  • Understanding of salesforce-core-workflow-a (standard CRUD)
  • jsforce installed with connection configured

Instructions

Step 1: Bulk API 2.0 — Ingest (Insert/Update/Upsert/Delete)

import { getConnection } from './salesforce/connection';
import fs from 'fs';

const conn = await getConnection();

// Create a bulk ingest job
const job = conn.bulk2.createJob({
  operation: 'insert',     // insert | update | upsert | delete
  object: 'Contact',
  // For upsert, specify: externalIdFieldName: 'External_ID__c'
});

// Upload CSV data
const csvData = `FirstName,LastName,Email,AccountId
Alice,Johnson,[email protected],001xxxxxxxxxxxx
Bob,Williams,[email protected],001xxxxxxxxxxxx
Carol,Davis,[email protected],001xxxxxxxxxxxx`;

// jsforce handles chunking automatically
const results = await conn.bulk2.loadAndWaitForResults({
  object: 'Contact',
  operation: 'insert',
  input: csvData,
});

console.log('Successful:', results.successfulResults.length);
console.log('Failed:', results.failedResults.length);

for (const failure of results.failedResults) {
  console.error(`Row ${failure.sf__Id}: ${failure.sf__Error}`);
}

Step 2: Bulk API 2.0 — Query (Export)

// Bulk query for large datasets (100K+ records)
const queryResults = await conn.bulk2.query(
  `SELECT Id, Name, Email, Account.Name
   FROM Contact
   WHERE CreatedDate >= LAST_N_DAYS:90`
);

// Stream results for memory efficiency
let recordCount = 0;
for await (const record of queryResults) {
  recordCount++;
  // Process each record
  console.log(`${record.Name} — ${record.Email}`);
}
console.log(`Total exported: ${recordCount}`);

Step 3: Bulk API 2.0 — File-Based Upload

// Upload from a CSV file (for very large datasets)
const csvStream = fs.createReadStream('contacts-import.csv');

const bulkResults = await conn.bulk2.loadAndWaitForResults({
  object: 'Contact',
  operation: 'upsert',
  externalIdFieldName: 'External_ID__c',
  input: csvStream,
  pollTimeout: 600000,   // 10 min timeout for large jobs
  pollInterval: 5000,    // Check every 5 seconds
});

console.log(`Processed: ${bulkResults.successfulResults.length} success, ${bulkResults.failedResults.length} failed`);

Step 4: Composite API — Multiple Operations in One Call

// Execute up to 25 subrequests in a single API call
// Each subrequest counts as a separate API call for limits
const compositeResult = await conn.request({
  method: 'POST',
  url: '/services/data/v59.0/composite',
  body: JSON.stringify({
    allOrNone: true,  // Rollback all if any fail
    compositeRequest: [
      {
        method: 'POST',
        url: '/services/data/v59.0/sobjects/Account/',
        referenceId: 'newAccount',
        body: { Name: 'Composite Corp', Industry: 'Technology' },
      },
      {
        method: 'POST',
        url: '/services/data/v59.0/sobjects/Contact/',
        referenceId: 'newContact',
        body: {
          FirstName: 'Jane',
          LastName: 'Doe',
          AccountId: '@{newAccount.id}',  // Reference previous result
          Email: '[email protected]',
        },
      },
      {
        method: 'POST',
        url: '/services/data/v59.0/sobjects/Opportunity/',
        referenceId: 'newOpp',
        body: {
          Name: 'Composite Deal',
          AccountId: '@{newAccount.id}',
          StageName: 'Prospecting',
          CloseDate: '2026-12-31',
          Amount: 100000,
        },
      },
    ],
  }),
  headers: { 'Content-Type': 'application/json' },
});

Step 5: Composite Batch — Independent Operations

// Batch executes up to 25 independent subrequests
// Unlike composite, subrequests can't reference each other
const batchResult = await conn.request({
  method: 'POST',
  url: '/services/data/v59.0/composite/batch',
  body: JSON.stringify({
    batchRequests: [
      {
        method: 'GET',
        url: 'v59.0/sobjects/Account/001xxxxxxxxxxxx',
      },
      {
        method: 'GET',
        url: 'v59.0/query/?q=SELECT+Id,Name+FROM+Contact+LIMIT+5',
      },
      {
        method: 'PATCH',
        url: 'v59.0/sobjects/Account/001xxxxxxxxxxxx',
        richInput: { Industry: 'Software' },
      },
    ],
  }),
  headers: { 'Content-Type': 'application/json' },
});

// Check results
for (const result of batchResult.results) {
  console.log(`Status: ${result.statusCode}`, result.result);
}

Step 6: Composite Graph — Complex Transaction Trees

// Composite Graph: multiple independent composite operations
// Each graph is an all-or-none transaction
const graphResult = await conn.request({
  method: 'POST',
  url: '/services/data/v59.0/composite/graph',
  body: JSON.stringify({
    graphs: [
      {
        graphId: 'graph1',
        compositeRequest: [
          {
            method: 'POST',
            url: '/services/data/v59.0/sobjects/Account/',
            referenceId: 'acct1',
            body: { Name: 'Graph Corp' },
          },
          {
            method: 'POST',
            url: '/services/data/v59.0/sobjects/Contact/',
            referenceId: 'contact1',
            body: {
              LastName: 'Graph',
              AccountId: '@{acct1.id}',
            },
          },
        ],
      },
    ],
  }),
  headers: { 'Content-Type': 'application/json' },
});

Bulk vs Composite Decision Guide

ScenarioAPIWhy
Import 10K+ recordsBulk API 2.0Handles millions, async processing
Export large datasetsBulk API 2.0 QueryStreaming, no memory issues
Create Account + Contact + OpportunityCompositeSingle call, references between objects
Fetch 5 unrelated recordsComposite BatchParallel fetches, 1 API call
Multi-object transactionComposite GraphAll-or-none across object types
< 200 records CRUDsObject CollectionsSimpler, synchronous, from workflow-a

Error Handling

ErrorCauseSolution
PROCESSING_HALTEDBulk job abortedCheck failedResults for row-level errors
InvalidBatchCSV format errorVerify column headers match field API names
ALL_OR_NONE_OPERATION_ROLLED_BACKComposite allOrNone failureCheck individual subrequest errors
MAX_BATCH_SIZE_EXCEEDEDToo many subrequestsComposite: max 25, Batch: max 25
EXCEEDED_ID_LIMITToo many records in single bulk jobSplit into multiple jobs (max 150M records/job)

Resources

Next Steps

For common errors and debugging, see salesforce-common-errors.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.