Salesforce API Limitations: Which Limit Breaks Your Integration First
Salesforce API limitations that break integrations: the rolling 24-hour allocation, Bulk API 2.0 batches, query limits, owner changes and partial success.
Luka Abramovic22 min read

Salesforce counts API requests over a rolling 24 hours, with no midnight reset, so the Salesforce API limitation that takes an integration down is usually reached by a one-off job rather than by steady sync traffic. A correction job that spends 60,000 requests at 10:00 on Monday is still using your nightly sync's budget at 02:00 on Tuesday. A paid org can run past its allocation by an amount Salesforce doesn't publish. Then a hard cap answers every integration in the org with HTTP 403 and REQUEST_LIMIT_EXCEEDED until usage over the previous 24 hours falls back under the limit (Salesforce limits reference, REST API status codes).
Below are the limits in the order an integration usually meets them, and what each one changes in the design. Limits are as of September 2026. For the same facts across other platforms, see our API limits reference for business software. The last section is a budget worksheet to fill in with your Salesforce admin.
1. Read your real allocation, and what counts against it
Salesforce meters inbound API requests per org, not per user or per integration, over a rolling 24 hours. As of September 2026, Enterprise Edition, and Professional Edition with API access added, get 100,000 requests plus an amount for every license in the org (Salesforce Developer Limits and Allocations Quick Reference):
| License type | Requests added per license, per 24 hours |
|---|---|
| Salesforce | 1,000 |
| Salesforce Platform | 1,000 |
| Lightning Platform - One App, Partner Community, Customer Community Plus | 200 |
| Partner Community Login, Customer Community Plus Login | 10 |
| Customer Community, Customer Community Login | 0 |
An illustrative org with 60 Salesforce licenses, 25 Salesforce Platform licenses and 500 Customer Community users gets 100,000 + 60,000 + 25,000 + 0 = 185,000 requests per 24 hours. The 500 portal users add nothing. Unlimited and Performance Edition add 5,000 per Salesforce license instead of 1,000, and Developer Edition is fixed at 15,000. Rather than calculate yours, read it under Setup, System Overview, API Usage, or have an admin run this Salesforce CLI command, which lists the maximum and remaining amount for every org limit (Salesforce CLI):
sf org list limits --target-org prod
What counts, and what doesn't, as of September 2026:
- REST, SOAP, Bulk API and Bulk API 2.0 draw on the same allocation, as do most Connect REST APIs and installed managed packages. Calls from some Salesforce apps, such as the mobile app, don't count.
- The allocation covers inbound calls only. Calls Salesforce makes out to your systems from Apex are limited per transaction instead: 100 callouts and 120 seconds of total callout time (Apex governor limits).
- A Full sandbox gets 5,000,000 requests a day unless it was created from a template, so a volume test there proves nothing about production headroom. Count the calls a test run makes instead.
- Professional Edition has no API access until the add-on is bought, and every call returns
API_DISABLED_FOR_ORGuntil then (REST API Developer Guide). The Salesforce Integration user license, which our CRM integration guide covers, doesn't appear in the allocation table as a license type that adds requests, so plan as though it adds none.
This week: log the org's usage every hour for seven days. Schedule this with cron under a monitoring user that has the View Setup and Configuration permission (section 8 explains why that shouldn't be the integration user):
sf org list limits --target-org prod --json | jq -r '.result[]
| select(.name == "DailyApiRequests")
| "\(now | todate),\(.max),\(.max - .remaining)"' >> api-usage.csv
The third column is what the org used over the previous 24 hours at that moment. Its highest value in a normal week is your real peak, and the starting point for section 3.
2. Which Salesforce API limitation you hit first
Each kind of workload tends to meet one limit before the others. The volumes below are arithmetic, not measurements.
| Workload | Limit it meets first | Why | Design response |
|---|---|---|---|
| Polling for changes every minute | Daily API requests | Three objects polled every minute cost 3 × 1,440 = 4,320 calls a day before a single record changes | Poll every 5 to 15 minutes, or subscribe to Change Data Capture (see the CDC row) |
| Writing one record per call | Daily API requests | 30,000 changed records a day is 30,000 calls, about a sixth of the illustrative 185,000 org above | Up to 200 records per call with sObject Collections (section 4) |
| Any single job over 2,000 records | Salesforce's own threshold for moving to Bulk API 2.0, then 15,000 batches per rolling 24 hours | Bulk API 2.0 needs only a few calls per job but uses one batch per 10,000 records | Bulk API 2.0 with full-size files (section 6) |
| Owner, role, territory or sharing changes | Record locks and sharing recalculation | Salesforce lists these among the operations likely to cause lock contention | Sort by parent, re-run failures serially, schedule off-hours (section 6) |
| Custom Apex REST endpoints or slow triggers | Concurrent long-running requests | Only 25 API calls of 20 seconds or more may run at once in production. Apex transactions over 5 seconds have their own org-wide cap (one per 100 licenses, at least 10, at most 50), so a slow integration can block users' pages that run Apex. | Keep each call short; move heavy work to asynchronous Apex |
| Syncing through Change Data Capture | Event delivery allocation | 25,000 delivered events per rolling 24 hours in Enterprise Edition and 50,000 in Unlimited and Performance, shared by every API subscriber and with high-volume platform events | One subscriber that fans out internally; custom channels that carry only the objects each subscriber needs (section 6) |
| Full extracts for reporting | Query pagination, then Bulk API 2.0 query limits | 2,000 rows per page. Bulk API 2.0 allows 10,000 query jobs and 1 TB of results per 24 hours. | Bulk API 2.0 query above about a million rows (section 5) |
Sources: API request limits, Bulk API limits, Apex governor limits, Change Data Capture allocations.
3. The window rolls, and the ceiling is soft until it isn't
Salesforce's own example: a Developer Edition org, which gets 15,000 requests, makes 14,500 calls at 5:00 AM on Wednesday and 499 at 11:00 PM. It can make one more call until 5:00 AM on Thursday (API request limits). No midnight reset is coming. That has three consequences for design.
- Run one-off jobs straight after your heaviest scheduled run, not before it. Run just after, a job has almost 24 hours to roll off before the next run needs the budget.
- Treat going over as borrowing. Paid orgs in active status can exceed the allocation by some amount, "if possible", in Salesforce's words, until the hard cap described at the top of this page. The overage is still counted: Salesforce adds API activity into 30-day periods from your contract start date, including calls above the entitlement, and shows it as API Request Limit per Month on Setup's Company Information page. Trial orgs, Developer Edition and sandboxes can't go over at all.
- Know the emergency route before you need it. Salesforce Support can raise the limit temporarily for at most two weeks, and won't do it on a recurring basis. Longer increases go through your account executive (Salesforce Help). Permanent headroom means buying extra API calls or more user licenses through the Your Account app (API request limits).
The same error code has a second meaning: Salesforce also returns REQUEST_LIMIT_EXCEEDED when 25 requests of 20 seconds or more are already running (5 in Developer Edition and trial orgs). Before an integration backs off for hours, it should compare the last Sforce-Limit-Info header it logged (section 8) with the limit. If calls remain, the problem is concurrency, which fewer slow calls in parallel fixes and waiting doesn't.
Size any one-off job against a budget, not against the day's remaining count:
Budget for a one-off job =
DailyApiRequests Max
- highest (Max - Remaining) recorded in a normal week, sampled hourly
- reserve for retries and catch-up (our default: 10% of Max)
With illustrative numbers, 185,000 - 120,000 - 18,500 leaves 46,500 requests: 46,500 records at one per call, or up to 9.3 million in theory as sObject Collections. At that point API requests are no longer the constraint. Batches, locks and downstream events are.
4. Put more records in each request
The shape of a request decides how many records one unit of allocation moves. As of September 2026:
| Request | Per request | Counts as | The catch |
|---|---|---|---|
| Single record, including upsert by external ID | 1 record | 1 call | None, apart from the volume |
| sObject Collections create, update, upsert or delete | Up to 200 records | 1 call | allOrNone defaults to false, so a 200 OK can hide failed records. Mixed object types are processed in chunks, at most 10 per request. Upsert accepts one object type per request. |
| sObject Collections retrieve, sent as POST | Up to 2,000 IDs of one object | 1 call | The GET form puts the IDs in the URL, which holds about 800 before the request fails with HTTP 414 |
| Composite | Up to 25 subrequests, at most 5 of them collections or queries | 1 call | One 10-minute timeout covers the whole request. Five 200-record collections subrequests move 1,000 records in one call. |
| Composite Batch | Up to 25 subrequests | Each subrequest counts | It looks like Composite and costs like 25 calls. A failed subrequest doesn't roll back earlier ones. |
| Bulk API 2.0 ingest job | Up to 150 MB of base64 data per job, about 100 MB of raw CSV | Each HTTP request (create, upload, close, poll, fetch results) is 1 call, and every 10,000 records also uses 1 of the 15,000 daily batches | Minutes of latency, and results you must fetch |
| REST query | Up to 2,000 rows per page | Each page is 1 call | You can request 200 to 2,000 rows per page, but Salesforce may return fewer |
Sources: sObject Collections, Composite, Composite Batch, Bulk API limits, Query Options header.
Collections are the right default for continuous sync. Composite earns its place when related records must be written together, such as an account and its contacts, with later subrequests referring to earlier results as @{refAccount.id}. One trap: since API version 49.0, Composite groups unrelated subrequests for speed by default, and their order is no longer guaranteed. If a trigger on one record expects another to exist already, set collateSubrequests to false (Composite request body).
5. Reads cost calls too
The read side has limits of its own, as of September 2026 (SOQL and SOSL limits):
- Every page is a call. A query returns up to 2,000 rows, and each
nextRecordsUrlpage after that is another request. Child rows in relationship queries count toward the page size. Reading 400,000 accounts costs at least 200 calls. - OFFSET stops at 2,000 rows. Anything higher returns
NUMBER_OUTSIDE_VALID_RANGE. Page with the query locator Salesforce returns, or use keyset paging, which also restarts cleanly after a failure. - The query cursor limit is gone. Until API version 56.0, a user could hold 10 open cursors and the oldest expired after 15 minutes idle. That limit has been removed for every API version, and cursors now last 2 days (API query cursor limits), so advice to ration them is out of date.
- A query gets 2 minutes to execute and 30 minutes to process its results, or it fails with
QUERY_TIMEOUT. Retrying the same query rarely helps. Filter on an indexed field or move the extract to Bulk API 2.0. - Above about a million rows, Salesforce's large-data guidance points to Bulk API 2.0 query (Large Data Volumes guide). Query jobs don't use the 15,000 batches. They have their own allocation of 10,000 jobs and 1 TB of results per rolling 24 hours, shown as
DailyBulkV2QueryJobsandDailyBulkV2QueryFileStorageMB.
Keyset paging for a full read: leave out the WHERE line on the first page, then use the last Id of each page to fetch the next.
SELECT Id, Name, OwnerId, SystemModstamp
FROM Account
WHERE Id > '001xx000003GYk2AAG'
ORDER BY Id
LIMIT 2000
The URL limit bites before the SOQL limit
A SOQL statement can be 100,000 characters long, but a REST query travels in the URL. The URI and headers together may be at most 16,384 bytes, and longer requests fail with 414 or 431 (API request limits). That caps the WHERE Id IN (...) lists integrations build to look up records they already know:
URI and headers allowed: 16,384 bytes
Path, SELECT, headers and token: about 600 bytes (illustrative)
One quoted 18-character ID + comma: 21 characters, or 27 if your client
encodes ' and , as %27 and %2C
IDs that fit: 15,784 / 21 = about 750
15,784 / 27 = about 580
Our default is 300 IDs per IN list, leaving room for longer field lists. To fetch records by ID, the POST form of sObject Collections retrieve takes 2,000 in one call.
6. Why a bulk change breaks an integration that copes with daily volume
A territory realignment, a mass owner change or a data correction arrives all at once and meets limits that steady daily traffic never touches. The request arithmetic for one, and the echo it sets off in a two-way sync, are worked through in our CRM integration guide. These are the limits that bite once the job has moved to Bulk API 2.0.
Batches, not calls
Salesforce's guidance is that any operation over 2,000 records is a candidate for Bulk API 2.0 (Bulk API limits), which makes one batch per 10,000 records from the 15,000 per rolling 24 hours it shares with the original Bulk API (Understanding Bulk API 2.0 ingest). Tools on the original Bulk API with a small batch size waste them: 40,000 rows in batches of 200 use 200 batches where Bulk API 2.0 would use 4. Two fine-print rules make running out expensive. If the daily record limit is hit partway through a job, the rest of the data isn't processed and the job is marked failed. And results aren't recorded for batches that exceed the daily batch allocation, so the job that runs into the ceiling is the one you can't reconcile.
Owner changes lock records
Salesforce lists four operations as likely to cause lock contention: creating users, updating ownership of records with private sharing, updating user roles and updating territory hierarchies (Organize data to minimize lock contention). Bulk API 2.0 manages its batches itself and supports only parallel processing. Salesforce's response to requests for a serial mode is a pilot, Bulk API 2.0 Automatic Record Lock Handling, which you ask your account team to be nominated for. What works today:
- Sort the file by parent ID, so children of one parent land in the same batch instead of competing for its lock.
- Re-run the rows that failed on locks in serial mode on the original Bulk API. In that API, lock failures are marked failed and aren't retried when a batch is requeued (General guidelines for data loads), so they have to be resubmitted anyway. The Salesforce CLI still offers serial mode (Salesforce CLI):
sf force data bulk upsert --sobject Account --file lock-failures.csv \
--external-id Id --serial --wait 30 --target-org prod
Salesforce's large-data guidance adds two thresholds: avoid any user owning more than 10,000 records, and any parent having more than 10,000 children (Large Data Volumes guide). The first catches integrations that leave everything they create owned by the integration user. For a large realignment, the same guide describes a defer sharing calculation permission that lets an admin suspend sharing calculations and resume them in a maintenance window.
Account teams, and what moves with the new owner
When an account's owner changes through the API, related records don't all follow. SOAP API's OwnerChangeOptions header decides: open opportunities, open activities, cases, contacts, contracts and orders each have a transfer option, and KeepAccountTeam defaults to false, which deletes the account team (SOAP API Developer Guide). The header comes with a condition: every account in one call must have the same old owner and the same new owner.
Salesforce's Data Loader documentation spells out what that means for a mass update. To keep account teams, you switch Bulk API off (sfdc.useBulkApi=false), set process.keepAccountTeam=true, and upload one file per owner pair, because a file with mixed owners fails and no owner changes (Data Loader Guide). An illustrative realignment of 12,000 accounts across 90 old-and-new owner pairs becomes 90 separate runs: cheap in API calls, expensive in preparation. REST API documents no equivalent header, so test in a sandbox what an owner change through your integration's route does to account teams and child records.
Downstream, change events run out too
If anything subscribes to Change Data Capture, the change is also a burst of events. As of September 2026, Enterprise Edition delivers 25,000 change and high-volume platform events per rolling 24 hours to API subscribers by default, and Unlimited and Performance Edition 50,000 (Change Data Capture allocations). Delivery is counted per subscriber, so two subscribers receiving the same 13,000 events use 26,000. Only five objects can be selected for change events without an add-on. Past the allocation, the subscriber is disconnected with an error. Events stay in the event bus for 72 hours, so a subscriber that pauses and then resumes from its last replay ID within three days loses nothing.
Salesforce sometimes merges the same change to several records of one object, made in one transaction within one second, into a single event, so a mass owner change can produce fewer events than records (Merged change events). Measure a test run with PlatformEventUsageMetric (metric CHANGE_EVENTS_DELIVERED) rather than assume one event per record.
One more asymmetry: Apex in a Bulk API transaction gets 60,000 ms of CPU time, against 10,000 ms for a synchronous call (Apex governor limits). A 200-record chunk an admin loads through Bulk API without trouble can fail on the CPU limit when the integration sends the same records through sObject Collections.
Pre-flight checklist for a bulk change
- Count rows, distinct parents and, for owner changes, old-and-new owner pairs. Sort by parent ID.
- Remove duplicate keys (script in section 7) and every unchanged column except the key. Fix rows you know will fail: in Bulk API 2.0, errors in a batch trigger single-row processing for that batch, which Salesforce warns heavily impacts performance (Large Data Volumes guide).
- Check headroom:
DailyBulkApiBatchesremaining above rows / 10,000 plus a margin, the job's request budget from section 3, andDailyDeliveredPlatformEventsagainst expected events × subscribers. - For owner changes, decide what happens to account teams, open opportunities, cases and activities, and whether any new owner would pass 10,000 records.
- Ask the admin which triggers, flows and validation rules fire on the object, and which can be paused for the run.
- Schedule it straight after the nightly sync, and warn the owner of every downstream subscriber.
- Plan the reconciliation before the run. Result files are kept for 7 days.
7. Make re-runs safe, and read partial success correctly
A bulk change is rarely right first time, so the second run has to be harmless. The retry rules in our guide to connecting business systems apply, and Salesforce adds its own.
Upsert rules that break re-runs
- If two records in one batch call carry the same external ID, Salesforce marks both as errors and writes neither (upsert()). A correction file built from a change log lists a customer once per change, so a customer changed twice appears twice.
- Matching is case-sensitive unless the field was created as Unique with the case-insensitive option, so
c-10442andC-10442are two different customers. - Upserting on an external ID that isn't marked Unique requires the View All Data permission, which an integration user shouldn't have. Mark the key Unique.
- In a Bulk API 2.0 CSV, a column header such as
Account.ERP_Customer_Id__cpoints a contact at its parent by the parent's external ID, so the job needs no queries to look up parent IDs (Bulk API 2.0 Developer Guide).
This script keeps the last row for each key and reports how many keys remain. Run it before every bulk upsert: python3 dedupe.py changes.csv ERP_Customer_Id__c > upload.csv
import csv, sys
source, key = sys.argv[1], sys.argv[2]
with open(source, newline="", encoding="utf-8") as f:
reader = csv.DictReader(f)
latest = {}
for row in reader:
latest.pop(row[key], None) # a later row replaces an earlier one
latest[row[key]] = row
writer = csv.DictWriter(sys.stdout, fieldnames=reader.fieldnames, lineterminator="\n")
writer.writeheader()
writer.writerows(latest.values())
print(f"{len(latest)} unique keys", file=sys.stderr)
What "success" means for each request type
| Request | Rollback behavior | What a success response can hide |
|---|---|---|
| sObject Collections | allOrNone false by default: each record stands alone | HTTP 200 with a success flag and errors per record. The failed records simply weren't written. |
Composite, allOrNone true | Any error rolls back the whole request | Still HTTP 200. A collections subrequest inside it can report "success": true for a record that was rolled back and doesn't exist. |
Composite, allOrNone false | Independent subrequests run | Subrequests that depend on a failed one are skipped |
| Composite Batch | No rollback | Earlier subrequests stay committed when a later one fails |
| Bulk API 2.0 job | No all-or-none option | The state reads JobComplete with failed rows inside. A Failed or Aborted job can still have written rows. |
Sources: allOrNone in Composite and Collections, Composite Batch, Bulk API 2.0 job states.
For Bulk API 2.0, fetch all three result sets: successful rows (sf__Id, sf__Created), failed rows (sf__Error, plus sf__Id from API version 53.0), and unprocessed rows, which a failed or aborted job never reached (failed results, unprocessed results). Rows come back in no guaranteed order, so keep your own key in the file. The check is submitted = successful + failed + unprocessed. What to do with each failed record is in our section on partial batch failures.
Which errors are worth retrying:
| Error | What it means | Retry? |
|---|---|---|
REQUEST_LIMIT_EXCEEDED | The daily cap, or 25 long-running requests already running | Depends which (section 3): wait for the window, or retry soon with fewer parallel calls |
UNABLE_TO_LOCK_ROW | Another transaction held the record or its parent | Yes, later, sorted by parent. Use serial mode if it keeps happening. |
QUERY_TIMEOUT | The query ran past its 2 minutes | Not as it is. Add a selective filter, or use Bulk API 2.0 query. |
| HTTP 414 or 431 | URL and headers over 16,384 bytes | No. Split the IN list, or retrieve by POST. |
API_DISABLED_FOR_ORG | The org has no API access, typically Professional Edition without the add-on | No. It's a licensing question. |
| Validation rule or required-field errors | The data broke a rule | Never automatically. Send it to a person. |
8. Monitor usage before it becomes an outage
- Turn on API Usage Notifications. In Setup, type API Usage Notifications in Quick Find. Salesforce emails a named user when requests pass a percentage of the allocation (API request limits). Our default is about ten percentage points above your normal peak, so the email means something unusual is running instead of arriving every day.
- Log the header you already receive. Every REST response except the versions list carries a header such as
Sforce-Limit-Info: api-usage=10018/100000, meaning calls used and the org's limit (Limit Info header). Logging it costs nothing. The/limitsresource is less convenient for an integration: it needs the View Setup and Configuration permission, which a least-privilege integration user usually lacks, and its figures are only accurate to within five minutes (Limits resource). - Save the log of who used the calls, every night. The API Total Usage event log comes at no extra cost in supported editions (EventLogFile event types). It records each REST, SOAP and Bulk request with the user, connected app, client name, object and whether it counted against the limit (API Total Usage). The catch: without the Event Monitoring add-on, each daily file is kept for one day, and it appears only the day after the calls (Using Event Monitoring). Download it nightly, or the worst day's file will be gone when you look for it.
- Name each integration. Give every integration its own connected app, which the log records as
CONNECTED_APP_NAME. Since Spring '26, creating a new connected app needs Salesforce Support to switch the option on for your org, and Salesforce recommends an External Client App instead (Salesforce Help), so check how a new integration appears in the log before you rely on that column. Salesforce documents theSforce-Call-Optionsheader, for exampleclient=erp-sync, for single-record, query, search and Bulk API requests, and the name appears in the log'sCLIENT_NAMEcolumn (Call Options header). Composite and sObject Collections aren't on that list, which is why the connected app matters. - Alert on all four daily limits, not only API requests (script below).
The nightly download, run with the Salesforce CLI (Salesforce CLI) by a user with the View Event Log Files permission:
REC=$(sf data query --target-org prod --json \
--query "SELECT Id, LogDate FROM EventLogFile WHERE EventType = 'ApiTotalUsage' ORDER BY LogDate DESC LIMIT 1")
ID=$(echo "$REC" | jq -r '.result.records[0].Id')
DAY=$(echo "$REC" | jq -r '.result.records[0].LogDate[0:10]')
sf api request rest "/services/data/v66.0/sobjects/EventLogFile/$ID/LogFile" \
--target-org prod --stream-to-file "api-usage-$DAY.csv"
To see who spent the calls on a bad day, summarize that day's file:
python3 - api-usage-2026-10-19.csv <<'PY'
import csv, sys, collections
used = collections.Counter()
for row in csv.DictReader(open(sys.argv[1], newline="")):
if row.get("COUNTS_AGAINST_API_LIMIT", "").lower() in ("1", "true"):
who = " / ".join(row.get(c) or "-" for c in
("CONNECTED_APP_NAME", "CLIENT_NAME", "USER_NAME"))
used[who] += 1
for who, calls in used.most_common(10):
print(f"{calls:>8} {who}")
PY
An hourly check that prints a line for any watched limit with less than a quarter left, ready to pipe into your alerting. Run it as the monitoring user from section 1:
sf org list limits --target-org prod --json | jq -r '
.result[]
| select(.name == "DailyApiRequests" or .name == "DailyBulkApiBatches"
or .name == "DailyBulkV2QueryJobs" or .name == "DailyDeliveredPlatformEvents")
| select(.max > 0 and .remaining < .max * 0.25)
| "\(.name): \(.remaining) of \(.max) left"'
The Salesforce API budget worksheet
Fill this in with your Salesforce admin before a new integration is built or a bulk change is scheduled. A blank you can't fill in shows where the risk is.
| Item | Where to find it | Your figure |
|---|---|---|
| Daily API allocation | DailyApiRequests Max from sf org list limits | |
| Normal peak use in 24 hours | Highest Max minus Remaining over a week, sampled hourly (section 1) | |
| Reserve | Our default: 10% of Max | |
| Budget for one-off jobs | Allocation minus peak minus reserve | |
| Bulk batches left today | DailyBulkApiBatches Remaining | |
| Event delivery allocation and subscribers | DailyDeliveredPlatformEvents Max, and a count of Pub/Sub API, CometD and event relay subscribers | |
| Largest change planned this quarter | Rows, objects, distinct parents, and old-and-new owner pairs | |
| Objects with private sharing | Setup, Sharing Settings, organization-wide defaults | |
| Owners with more than 10,000 records | SELECT OwnerId, COUNT(Id) FROM Account GROUP BY OwnerId HAVING COUNT(Id) > 10000, repeated per object | |
| Slow calls | Custom Apex REST endpoints and triggers that run longer than 5 seconds | |
| Who spent the calls on the worst day | API Total Usage files from the nightly download, grouped by connected app, client name and user |
If a Salesforce integration of yours is about to meet a bulk change, or has already hit a limit, send us the worksheet above and whatever API Total Usage files the nightly download has collected. We'd start with which client spent the calls, and whether the planned job needs locks, owner pairs or change events the org can't supply that day. Answering those two questions is the first step of our systems integration work.