Back to blog
Systems IntegrationBusiness Software

Business Software API Limits: 23 Platforms and What Breaks First

API limits for 23 business platforms as of September 2026: plan gates, published caps, what happens at the limit, webhooks, and which limit you hit first.

Luka Abramovic26 min read

Business systems exchanging records through their APIs

The API limit that stops a business integration is rarely the headline number. Since November 2025, QuickBooks Online has metered reads separately from writes for developers in the US, the UK, Canada (outside Quebec) and Australia. An app on Intuit's free Builder tier gets 500,000 "CorePlus" calls a month for data-out requests such as reads, queries and reports, and CorePlus calls beyond that are blocked, not slowed, until the month resets (Intuit Developer). Xero's free Starter developer tier allows 1,000 calls a day per connected organization, a fifth of the 5,000 on its paid tiers (Xero Developer).

Below are the API limits of 23 business platforms that integration projects commonly touch. Each row gives how you get API access and what the plan gates, the published limits, what happens at the limit, how events behave, and our read on which limit you meet first and what it changes in the design. Checked in September 2026 against vendor documentation or, where a vendor's page couldn't be read directly, against copies of it and independent sources that agree. Pipedrive, Asana and Sage Intacct are left out because we couldn't verify their current figures.

The five kinds of limit, and what each one breaks

Most platforms enforce several kinds of limit at once, and each kind fails differently.

Kinds of API limit, with examples from this list
KindExamples belowWhat failure looks likeDesign response
Short window (per second, 10 seconds or minute)HubSpot 190 per 10 seconds, QuickBooks 500 a minute per company, Xero 60 a minute per organization, Jira 50 writes a secondA 429 with a wait time; recovers in secondsPace requests and honor Retry-After
Daily or rolling 24-hour quotaSalesforce, HubSpot, Xero, monday.com, Zoho CRM credits, Power Platform requestsBlocked until the window rolls, sometimes for every integration on the accountBudget calls per day, keep headroom, send bulk changes through bulk APIs
Monthly metered allowanceQuickBooks CorePlus calls, Airtable Team calls, Xero data egressBlocked, slowed or billed for the rest of the monthReplace polling with events and change feeds; alert at 50% and 80% used
ConcurrencyNetSuite 5 to 20 plus SuiteCloud Plus, QuickBooks 10, Xero 5, Dataverse 52, Salesforce 25 long-runningImmediate rejection, and not always with a 429Cap parallel workers below the limit, counting other integrations
Cost or pointsShopify query cost, monday.com complexity, Jira hourly points, SharePoint resource unitsOne request can cost many unitsAsk for fewer fields and records; read the cost from each response

A rule of thumb we use: the daily total is rarely what stops a business integration. Concurrency stops ERP integrations, the short window stops bulk jobs, and the monthly allowance stops anything that reports or reconciles, because reporting reads far more than it writes. This week: list the platforms in your stack and write next to each which of the five kinds apply, using the tables below.

CRM and sales platforms

API limits for CRM and sales platforms, as of September 2026
PlatformAccess and published limitsAt the limit, and eventsWhat you hit first (our read)
SalesforceProfessional Edition needs the paid API add-on (Salesforce Help). Enterprise Edition's daily allocation starts at 100,000 requests per 24 hours plus 1,000 per Salesforce license, so 15 licenses give 115,000. No more than 25 long-running requests (20 seconds or longer) at once in production orgs and sandboxes, and 5 in Developer Edition and trial orgs (limits reference). Bulk API and Bulk API 2.0 share 15,000 batches per rolling 24 hours; Bulk API 2.0 query jobs don't use them (bulk limits).The daily allocation is a soft limit. Calls keep working past it until a system protection limit blocks all API calls with 403 REQUEST_LIMIT_EXCEEDED, until usage over the previous 24 hours falls back under the allocation (Salesforce Developers blog). Too many long-running requests return the same error code.A runaway job. Because the daily limit is soft, the first sign can be every integration in the org failing together, so alert on usage, not errors. Salesforce suggests Bulk API 2.0 for operations over 2,000 records (Bulk API guide).
HubSpotAPI access on every tier. Private apps, per HubSpot's usage page: Free and Starter 100 requests per 10 seconds and 250,000 a day; Professional 190 and 625,000 (the 2024 changelog announcing the increase said 650,000); Enterprise 190 and 1,000,000. Each API Limit Increase adds 1,000,000 a day (usage guidelines). Public marketplace apps: 110 requests per 10 seconds per installing account (HubSpot changelog). CRM search has its own limit: 5 requests a second, up to 200 records per page (HubSpot changelog).429, with usage in the X-HubSpot-RateLimit headers and a policyName in the body saying which limit. The 10-second limit applies to each private app, but the daily limit is shared by all apps in the account. Webhooks: up to 10 retries over 24 hours; a response slower than 5 seconds counts as a timeout (webhooks).Search. A sync that looks each record up before updating it runs at 5 a second, far below the burst limit, so store HubSpot IDs and use batch reads or upserts. Second, one noisy private app can spend the daily budget the others depend on.
Zoho CRMAPI credits per organization over a rolling 24 hours, by edition: Free 5,000; Standard 50,000 plus 250 per user license, up to 100,000; Professional 50,000 plus 500 per license, up to 3,000,000; Enterprise 50,000 plus 1,000 per license, up to 5,000,000; Ultimate 50,000 plus 2,000 per license. Concurrent calls per organization per app: 5, 10, 15, 20 and 25 across the same editions (Zoho CRM API limits).429 with TOO_MANY_REQUESTS whether the credits ran out or the concurrency limit was hit, so the code alone doesn't tell you whether to wait seconds or hours (status codes). Credits come back 24 hours after they were spent, not at midnight.Concurrency: 10 to 20 parallel workers is a low ceiling for a backfill. And because the window rolls, a large import started at 9 a.m. Monday still counts against Tuesday's traffic until 9 a.m. Tuesday.
Microsoft Dynamics 365 (Dataverse)Two layers. Service protection, per user and per web server: 6,000 requests and 20 minutes of combined execution time in any 5-minute window, and 52 concurrent requests (Dataverse limits). Entitlement per 24 hours: 40,000 Power Platform requests per paid Dynamics 365 or Power Apps Premium user. Application users share a tenant pool of 500,000 plus 5,000 per Dynamics 365 Enterprise or Professional license, up to 10,000,000, or 25,000 if the tenant only has Power Apps or Power Automate licenses (request limits).429 with Retry-After in seconds, growing if you keep sending demanding requests; exceeding concurrency fails at once. Microsoft says it won't enforce the entitlement limits on heavy users until six months after its usage reports are generally available. Webhooks time out after 60 seconds and get one more attempt, only for 502, 503 and 504 (Dataverse webhooks; when to poll instead is in our guide to polling or webhooks).Service protection during bulk loads. Batching doesn't get around it, because the execution-time limit counts the work inside the batch. Trial environments get a single web server, so throughput measured in a trial understates production.

Two Dataverse details worth acting on. The usage report in the Power Platform admin center (Licensing, Capacity add-ons, Download reports) is in preview and covers Power Automate requests only, not Dataverse API calls, so count your integration's own calls per 24 hours. The x-ms-ratelimit-burst-remaining-xrm-requests header won't do it for you: it shows only the five-minute service protection budget left on one web server, and Microsoft says it's meant for debugging. And application users get the same limits as people, so one application user doing everything gets one person's share per web server. Salesforce and HubSpot bulk changes, with a worked example, are in our CRM integration guide.

Accounting and ERP

API limits for accounting and ERP platforms, as of September 2026
PlatformAccess and published limitsAt the limit, and eventsWhat you hit first (our read)
QuickBooks OnlineYes, QuickBooks Online has an API: the Accounting API, used through an app registered with Intuit Developer. Every app is enrolled in the Intuit App Partner Program, at the free Builder tier unless its workspace subscribes to a paid one, and usage is added up across all the apps in a workspace. Core calls, mostly data in (creating or updating invoices, bills, customers), are unmetered. CorePlus calls, mostly data out (reads, queries, reports), are metered: 500,000 a month on Builder, 1,000,000 on Silver (partner program FAQ). Throttle: 500 requests a minute per company (realm ID), no more than 10 concurrent requests per company, and 40 batch requests a minute (call limits).Throttling returns 429. Send each write with a requestid and reuse it on every retry: QuickBooks answers a repeated request ID with the original response instead of acting twice (request IDs). On Builder, CorePlus calls beyond the monthly allowance are blocked until next month; paid tiers pay metered fees instead. Catch-up: the change data capture (CDC) operation returns changed and deleted objects for a list of entity types, up to 30 days back and 1,000 objects per response, with no paging (CDC). Webhooks now use the CloudEvents format, and Intuit's final deadline for migrating off the legacy format was July 31, 2026 (Intuit announcement).Monthly reads, for anything that reports or reconciles. Polling each entity type spends CorePlus calls whether or not anything changed; one CDC call covers several types. A fixed request ID is what makes a retry safe (pattern in our ERP integration guide).
XeroSince March 2, 2026, developer pricing has five tiers (Starter, Core, Plus, Advanced, Enterprise) based on connections and data egress, meaning data extracted from Xero. Starter is free and capped at 5 connections; Core, Plus and Advanced charge AUD 2.40 per GB over their egress allowance (pricing FAQ). A Custom Connection (machine-to-machine access to one organization) costs AUD 10, NZD 10, GBP 5 or USD 5 a month and is offered only in Australia, New Zealand, the UK and the US (custom connections). Per organization: 60 calls a minute, 5 concurrent, and 5,000 a day on Core and above or 1,000 on Starter. Per app: 10,000 calls a minute across all organizations (limits).429, with X-Rate-Limit-Problem naming the limit and Retry-After the wait. Writes accept an Idempotency-Key header, but Xero remembers a key for only 6 minutes, so a retry after a longer outage has to check whether the first attempt landed (idempotency).The 60-a-minute limit during month-end pushes, then the daily cap on Starter. An in-house integration connecting five or fewer organizations can stay on free Starter, which is exactly where the 1,000-a-day cap applies. A group with UK, Australian and New Zealand organizations gets a separate budget for each, but all of them share the app's minute limit.
Oracle NetSuiteConcurrency governance rather than a daily count. Account limit by service tier: Standard 5, Premium 15, Enterprise 20, Ultimate 20 concurrent requests. Each SuiteCloud Plus license adds 10, and developer accounts get 5. SOAP web services, REST web services and RESTlets draw on the same account limit, and an admin can reserve part of it for one integration on its integration record (Oracle NetSuite SAFE Guide 2025.2).REST web services return 429. SOAP with token-based auth returns WS_REQUEST_BLOCKED. RESTlets return HTTP 400 with SSS_REQUEST_LIMIT_EXCEEDED. The account limit and request counts are at Setup > Integration > Integration Management > Integration Governance.Concurrency, shared with every other integration in the account. A RESTlet over the limit answers 400, which generic retry logic treats as a permanent error, so the request is never retried. Treat that error as retryable, and reserve an integration limit for the flow that must not stop, such as order import.
OdooThe external API is available only on Custom pricing plans, not One App Free or Standard (Odoo 19 external API). Odoo 19 adds the JSON-2 API at /json/2/<model>/<method>; the XML-RPC and JSON-RPC endpoints are scheduled for removal in Odoo 22 (fall 2028). The external API reference publishes no request rate limits.From Odoo 19, an API key needs a duration and can't last more than three months, so long-lived keys must be rotated at least quarterly; an expired key fails with 401. Each JSON-2 call runs in its own database transaction, so several calls can't be chained into one.The plan, then the key. Put key rotation in the runbook: Odoo's advice is to generate the new key before revoking the old one. For related writes, such as an order and its lines, call one server-side method that does them together.

This week: in NetSuite, open the Integration Governance page and compare your account limit with the number of integrations that call it. In QuickBooks, confirm your workspace's Intuit App Partner Program tier before deciding how often to poll, and check that your webhook receiver parses CloudEvents. In Odoo 19, check the expiry date of every integration key.

Work management, spreadsheets and files

API limits for work management, spreadsheet and file platforms, as of September 2026
PlatformAccess and published limitsAt the limit, and eventsWhat you hit first (our read)
monday.comAll plans, with four separate limits. Daily calls, reset at midnight UTC: Free and Trial 200, Basic and Standard 1,000, Pro 10,000, Enterprise 25,000 (soft on Pro and Enterprise). Per minute: 1,000, Pro 2,500, Enterprise 5,000. Concurrent: 40, Pro 100, Enterprise 250. Complexity points per minute: 5,000,000 each for reads and writes on app tokens, 10,000,000 combined on personal tokens (monday.com's API reference, in its official plugin repository).Failed calls count toward the daily limit, and rate-limit errors cost 0.1 of a call. The daily, minute, concurrency and complexity limits return 429 with an error code and retry_in_seconds (monday.com's MCP server tests). Other errors come back with HTTP 200 and an errors array, including some limits on individual fields, which return partial data with the code tooManyRequests (error reference).The daily cap on Basic and Standard. Polling four boards every five minutes is 1,152 calls a day, over the 1,000 allowed. Check the errors array on every response, because a status check alone treats a partly throttled response as a success.
AirtableMonthly calls per workspace: Free 1,000; Team 100,000, then throttled to 2 requests a second; Business no monthly cap (call limits). On every plan, 5 requests a second per base, and 50 a second across all traffic from one user's or service account's personal access tokens (rate limits). A write carries up to 10 records per request by default (Airtable's CLI guidance).429, then a 30-second wait before requests succeed again.The Team plan's monthly cap. Writing one record per call spends it ten times faster than batches of 10. Treat the 30-second lockout as a reason to pace below 5 a second, not to retry faster.
Smartsheet300 requests a minute per API access token (Smartsheet's own integration documentation).429.The limit follows the token. Our default is to issue the integration's token from a dedicated account rather than a person's, so leaving staff don't take the integration with them.
NotionAn average of three requests a second per connection, Notion's term for an integration (Notion request limits).429 rate_limited. Notion's official JavaScript SDK retries it twice by default for every method and honors Retry-After, but retries server errors (500, 503) only for GET and DELETE, to avoid repeating writes (SDK README).Sustained rate: about 10,800 requests an hour, so migrating large pages with many blocks takes hours. If you raise the SDK's retry count, keep its rule of not blindly retrying failed writes.
Jira CloudTwo layers: an hourly quota counted in points, and per-second burst limits. Hourly quotas: 65,000 points on Free; Standard 100,000 plus 10 per user; Premium 130,000 plus 20 per user; Enterprise 150,000 plus 30 per user, up to 500,000. Burst: 100 requests a second for GET and POST and 50 for PUT and DELETE, some endpoints set their own, and repeated writes to one issue have a separate limit (Jira rate limiting).429 with Retry-After and X-RateLimit headers, plus a RateLimit-Reason header saying which limit you hit.Bulk edits, against the 50-a-second write limit and the per-issue limit. Branch on RateLimit-Reason: a burst limit clears in seconds, an hourly quota takes far longer.
Google Sheets APIPer Google Cloud project: 300 read requests and 300 write requests a minute, and 60 of each per user per project (Sheets API limits).429; the quota refills each minute.The per-user limit, when one service account does everything: 60 writes a minute. Send many rows in one append or batch update rather than one request per row.
SharePoint and OneDrive (Microsoft Graph)Each app has its own budget per tenant, in resource units, set by the tenant's license count: 1,250 a minute and 1,200,000 a day up to 1,000 licenses, rising to 6,250 and 6,000,000 above 50,000. A single-item read, a delta call with a token or a download costs 1 unit; listing children, creating, updating, deleting or uploading costs 2. Batched requests are costed one by one. Per user: 3,000 requests per 5 minutes (SharePoint throttling guidance).429 or 503 with Retry-After. Throttled requests still count toward the limit, and an app that keeps exceeding it can be blocked outright, with the tenant told in the Message Center. Change notification subscriptions for lists and drive items last at most 42,300 minutes, under 30 days, and must be renewed; list notifications only say "updated", so you call delta to find what changed (subscription lifetime).The per-minute unit budget during a migration or first scan. Use delta with a token (1 unit) instead of listing folders (2), prefer Graph to CSOM and REST, which usually cost more, and label your traffic, because Microsoft prioritizes decorated traffic.
Excel workbooks (Microsoft Graph)1,500 requests per 10 seconds per app per tenant, and 5,000 per 10 seconds per app across all tenants (Graph throttling limits). For more than one call, Microsoft recommends creating a workbook session and sending its ID in a workbook-session-id header (Excel API best practices).Graph applies its global and service limits together; the first one reached triggers throttling. Creating a session on a large workbook can take long enough to time out, so send Prefer: respond-async and poll the operation.Loops that write one cell per call. 150 requests a second sounds generous until a spreadsheet-style loop meets a 10,000-row table; write a whole range or a batch of table rows per request.

Microsoft's user-agent format for an in-house SharePoint application is NONISV|CompanyName|AppName/Version, for example NONISV|Contoso|InvoiceSync/1.0, alongside a registered app ID. With Multi-Geo, each geography gets its own limits, but license-based limits use the whole tenant's license count. And Graph change notifications wait 3 seconds for your endpoint and retry for up to 4 hours, but if more than 15% of responses in 10 minutes take over 10 seconds, notifications are dropped for 10 minutes and can't be recovered (Graph webhook delivery). Acknowledge first, process on a queue, and run a scheduled delta sweep anyway.

Service desk and ITSM

API limits for service desk and ITSM platforms, as of September 2026
PlatformAccess and published limitsAt the limit, and eventsWhat you hit first (our read)
ZendeskSupport and Help Center API requests a minute by Zendesk Suite plan: Team 200, Growth 400, Professional 400, Enterprise 700, Enterprise Plus 2,500. The High Volume API add-on raises a qualifying plan to 2,500 (it replaces the plan limit, not adds to it) and needs Growth or above with at least 10 agent seats. Help Center calls have the same limits but a separate count. Endpoint limits include incremental exports at 10 a minute (30 with High Volume) and 30 updates to the same ticket per user per 10 minutes (Zendesk rate limits).429 with Retry-After; X-Rate-Limit and X-Rate-Limit-Remaining on responses.The incremental export limit, because it is the endpoint a sync should use: 10 requests a minute on any plan without the add-on. For automations, the per-ticket limit: write all changed fields in one update, not one call per field.
FreshdeskA per-minute limit set by plan and applied to the whole account: Pro 400, Enterprise 700, lower on Growth, and 50 for trial accounts. List endpoints such as tickets and contacts have lower sub-limits. Extra capacity can be bought (Freshdesk API).429 with Retry-After. Invalid requests count. A request that embeds related data can consume more than one call, and X-RateLimit-Used-CurrentRequest shows how many.Other apps. Marketplace and custom apps that call the API spend the same account-wide budget, so list them before sizing a sync, and watch the tickets-list sub-limit during backfills.
ServiceNowRate limits are rules an administrator creates in the Rate Limit Rules table (sys_rate_limit_rules), per REST resource and per hour, for a user, a role or all users. A user rule beats a role rule, which beats an all-users rule; with several role rules, the lowest limit applies. A rule can take 30 seconds to bite (inbound REST rate limiting). Default quota rules stop REST Table, Aggregate, Import Set and Attachment API transactions after 60 seconds (quota rules).A rule returns 429 with Retry-After and X-RateLimit-Limit, X-RateLimit-Reset and X-RateLimit-Rule headers. Separately, inbound API transactions wait for the instance's integration semaphores; when that queue is full (50 by default), new requests get 429 at once, without those headers (ServiceNow KB0564204).Semaphore exhaustion during bursts rather than a rule. A 429 without X-RateLimit-Rule means the instance is saturated, so slow down across all workers. Keep every call well under 60 seconds with small pages and only the fields you need.

This week: in Zendesk, check whether your sync reads through incremental exports and how many pages a full backfill needs at 10 a minute. In ServiceNow, ask the admin for any rows in sys_rate_limit_rules that match your integration user.

Commerce, construction and HR

API limits for commerce, construction and HR platforms, as of September 2026
PlatformAccess and published limitsAt the limit, and eventsWhat you hit first (our read)
ShopifyThe GraphQL Admin API charges each query a calculated cost in points, drawn from a bucket that refills at a restore rate. Every response reports maximumAvailable, currentlyAvailable and restoreRate in extensions.cost.throttleStatus (API limits).Requests are throttled when the bucket is empty. Bulk operations (bulkOperationRunQuery, bulkOperationRunMutation) run server-side and bypass the standard rate limit. Shopify's own sample app treats 5 concurrent bulk operations per app and store as the maximum, and 100 MB as the hard limit for a mutation's input file (bulk operations sample app).Query cost on backfills. Paging through orders with nested line items drains the bucket fast, while a bulk query returns the whole set as one file. Read the bucket values from each response instead of hard-coding a rate, as Shopify's sample app does.
ProcoreTwo limits: an hourly limit (a 60-minute window) and a spike limit (a 10-second window). The X-Rate-Limit-Limit, X-Rate-Limit-Remaining and X-Rate-Limit-Reset headers report whichever one you are closer to exceeding, usually the spike limit. Every request counts, including 400, 403 and 404 responses. Procore tells integrators not to assume a fixed 3,600 an hour, the figure often quoted (Procore rate limiting).429 for either limit. Under exceptional platform load, 503 with Retry-After. Procore raises limits on request, judging by production traffic, backoff behavior and error rate.The spike limit when a backfill runs in parallel, then the hourly one. Pause when X-Rate-Limit-Remaining reaches 0 until X-Rate-Limit-Reset. If your hourly limit is 3,600, 40,000 calls take at least 11 hours, so plan the first load as an overnight or weekend job and fetch lists page by page, not item by item.
WorkdayIntegrations sign in as an Integration System User (ISU), created with Do Not Allow UI Sessions set, in an integration system security group granted each data domain, with an API client from Register API Client for Integrations. Custom reports can be exposed as web services (RaaS) through the report's Web Service > View URLs option. Workday documents its limits, including request caps per 24 hours and per hour that scale with customer size, in "Reference: Integrations and Web Service Limits" (Workday developer documentation); read the current figures with your Workday administrator.A web service response is capped at 1 million instances, so large extracts need request criteria, response filters or date ranges.Access before rate. Each domain the integration reads has to be granted to its security group, and security changes stay pending until someone runs Activate Pending Security Policy Changes. List every field and domain before the build starts, because each missing grant is another round trip through your Workday security administrator.
ADPTwo routes. An ADP client buys ADP API Central to get API credentials for its own ADP tenant; software vendors that integrate with many ADP clients join the ADP Marketplace partner program (ADP developer portal). Calls also need a mutual-TLS client certificate, not just a client ID and secret. We didn't find rate limits on a public ADP page.Ask for the limits when API Central is set up.Procurement. Budget the API Central purchase, project setup and the certificate's renewal before any build estimate, and confirm which use cases the subscription enables before testing starts.

This week: in Procore, log X-Rate-Limit-Limit on every response for a day to see which limit your app is actually measured against. For Workday, send the administrator the list of domains your integration reads, before anyone writes code.

How each platform says "slow down"

Retry logic keyed on HTTP 429 alone misreads several of the platforms above. Salesforce answers 403 REQUEST_LIMIT_EXCEEDED for both the daily protection limit and too many long-running requests, so check the remaining allocation (the REST API's limits resource, or sf org list limits) before deciding. NetSuite RESTlets answer 400. monday.com can return a partly throttled response as HTTP 200 with the error inside, and Shopify's GraphQL API can report a throttled query as HTTP 200 with the error code THROTTLED. SharePoint and Procore throttle with 503 as well as 429. ServiceNow and Zoho CRM each send one 429 for two different problems. Dataverse codes name the limit: -2147015902 for requests, -2147015903 for execution time, -2147015898 for concurrency, where the fix is fewer workers rather than a longer wait.

Put this in one function that every API call passes through:

classify(platform, response):
    if platform == "monday.com" and any error code == "DAILY_LIMIT_EXCEEDED":
        return STOP_UNTIL(next midnight UTC)          # retrying only burns more calls
    if platform == "monday.com" and response.status == 200
            and any error code == "tooManyRequests":
        return WAIT(backoff)                          # partial data, not a success
    if platform == "Shopify" and response.status == 200
            and any error code == "THROTTLED":
        return WAIT(backoff)                          # cost bucket empty: see throttleStatus
    if platform == "NetSuite" and response.status == 400
            and body contains "SSS_REQUEST_LIMIT_EXCEEDED":
        return WAIT(backoff)                          # a limit, not a bad request
    if platform == "Salesforce" and response.status == 403
            and body contains "REQUEST_LIMIT_EXCEEDED":
        return CHECK_DAILY_ALLOCATION
    if platform == "ServiceNow" and response.status == 429
            and no "X-RateLimit-Rule" header:
        return SLOW_ALL_WORKERS                       # instance saturated
    if platform == "Zoho CRM" and error code == "TOO_MANY_REQUESTS":
        return REDUCE_WORKERS                         # if it persists, credits ran out
    if response.status == 429 and (HubSpot policy name is the daily one
            or Xero "X-Rate-Limit-Problem" names the daily limit):
        return STOP_UNTIL(window resets)              # retrying burns more calls
    if platform == "Dataverse" and error code == -2147015898:
        return REDUCE_WORKERS                         # concurrency, not volume
    if response.status == 429
            or (platform in [SharePoint, OneDrive, Procore] and response.status == 503):
        wait = header "Retry-After"
               or error field "retry_in_seconds"      # monday.com
               or 30 seconds if platform == "Airtable"
               or backoff
        return WAIT(wait)
    return NOT_A_LIMIT

Every WAIT resends the same request with the same idempotency key or request ID, never a new one. Why that matters, and what goes wrong without it, is in our guide to timeouts and retries.

Worked example: sizing two syncs before you build

Both examples are illustrative: the volumes are invented, the limits are those published above.

An order system pushing invoices into Xero

An order system creates 1,500 invoices a day in one Xero organization. Each takes 2 calls, one to create it and one later to read its status, and the integration polls for payments every 5 minutes.

Daily Xero calls for 1,500 invoices a day (illustrative inputs)
ItemCalculationCalls
Invoices1,500 × 23,000
Payment polling24 hours × 12 an hour288
Total a day3,288
Starter tier, 1,000 a day3,288 ÷ 1,0003.3 times the limit: if calls are spread evenly, they fail from about 30% of the way through the day
Core tier and above, 5,000 a day3,288 ÷ 5,00066% used, 34% headroom
A 5 p.m. batch of 400 invoices400 create calls ÷ 60 a minuteAt least 6.7 minutes, if nothing else calls that organization

Two inputs change the answer. Dropping the status read-back, where the create response already carries what you need, takes the day to 1,788 calls. Replacing the polling with webhooks, if Xero sends an event for the change you poll for, removes the 288; keep one daily catch-up read as a backstop for any event a receiver misses.

A group with eight QuickBooks Online companies

A group runs eight QuickBooks Online companies and one internal app on the Builder tier. It needs changes from 10 entity types (customers, invoices, payments, bills and so on) every 5 minutes. Assume each call uses one CorePlus call from the allowance.

Monthly CorePlus reads for eight QuickBooks companies (illustrative inputs)
DesignCalculationReads a monthAgainst 500,000
One query per entity type per company288 a day × 10 types × 8 companies × 30 days691,200Blocked around day 22 (500,000 ÷ 23,040 a day)
One CDC call per company, listing all 10 types288 a day × 8 companies × 30 days69,12014% used

The CDC design has a limit of its own: 1,000 objects per response, and no paging. If a company can change more than 1,000 records in 5 minutes, during a year-end journal import for example, poll that company more often or read that burst with an ordinary query filtered on the last-updated time. Writes, the Core calls, don't touch the allowance either way.

The limit budget worksheet and the questions to send

Fill in one row per platform the integration touches. Our defaults: keep planned use under 50% of any daily or monthly limit, and never plan to use a whole concurrency limit.

Limit budget worksheet
Platform and accountLimit that applies (kind, number, window, scope)Shared withPlanned useLargest burstHeadroomWhere to read live usage
e.g. Xero, UK organizationDaily, 5,000, per organizationExpense app, payroll connector3,288 a day400 calls at 5 p.m.34%X-Rate-Limit-Problem and Retry-After on 429s

The arithmetic behind each column:

daily calls   = records a day × calls per record × (1 + retry rate)
                + polls a day × object types polled
monthly reads = daily read calls × 30
burst minutes = calls in your largest burst ÷ per-minute limit
headroom      = 1 − (your daily calls + other integrations' daily calls) ÷ daily limit
workers       = concurrency limit − concurrency other integrations use − 1 spare

For the "shared with" column and the rest, send the platform admin or vendor this:

Subject: API limits for our [platform] integration

Hi [name],

Before we build the [platform] integration, could you confirm these for our account?

1. Which limits apply to us: per second or minute, daily, monthly, concurrent
   requests? Is each one per user, per app, per token or per account?
2. Which other integrations, apps or scheduled jobs already use the same limits?
3. What does the API return at each limit (status code, error code, headers)?
4. Is the daily limit hard, or soft with a block later? How long does a block last?
5. Do failed, invalid or throttled requests count against the limit?
6. Is there a bulk or export API outside the normal limit, and what are its limits?
7. Webhooks: timeout, retry schedule, what happens after the last retry, and is
   there a change feed or replay, and how far back does it go?
8. Are reads, writes or data egress metered or billed separately?
9. Does the sandbox or test environment have the same limits as production?
10. Where are limit changes announced, and how much notice do you give?

Thanks,
[name]

If you're planning an integration across several of these platforms, or one is already hitting a limit, bring the filled-in worksheet and a week of usage from the platform's own report or headers. We'd start with the limit that fails hardest, such as a monthly read cap or a shared concurrency pool, and design the sync around it. Our systems integration work starts there.

Build with Adamant Code

Is your business outgrowing its tools?

Bring one workflow or software problem. We’ll discuss where your current setup falls short and the next step worth exploring.

Talk through your workflow
Business Software API Limits: 23 Platforms and What Breaks First | Adamant Code