Skip to content

NetSuite vs SAP for AI Agents: The 2026 ERP Integration Guide

Step-by-step guide to connecting AI agents to Oracle NetSuite and SAP. Covers SuiteQL queries, OData patterns, MCP tool schemas, OAuth 2.0 migration, concurrency mitigation, and a financial accuracy checklist.

Sidharth Verma Sidharth Verma · · 24 min read
NetSuite vs SAP for AI Agents: The 2026 ERP Integration Guide

If you are building a B2B SaaS product that requires AI agents to read, write, or reason over financial data inside your customers' ERPs, you are staring down a massive technical debt problem. LLMs are functionally useless without access to systems of record. ERP systems are the ultimate source of truth for enterprise data—invoices, expense reports, purchase orders, and ledger entries—but their legacy APIs are hostile environments for modern developers.

The search intent behind comparing NetSuite and SAP for AI agent integrations usually stems from a painful engineering reality. Your team is likely drowning in NetSuite SOAP quirks, SAP OData pagination limits, and legacy authentication models. You need to know which platform to prioritize and how to architect the connectivity layer so your agents can actually function.

The short answer: NetSuite is moving faster toward AI-native connectivity with its MCP-based AI Connector Service, while SAP's fragmented API surface and synchronous processing model require significantly more middleware to expose safely to LLMs. This guide breaks down the architectural realities, API quirks, and rate-limiting constraints of connecting AI agents to Oracle NetSuite and SAP in 2026 so you can make an informed build-or-buy decision.

The Agentic ERP Era: Why AI Agents Need Financial Context

AI agents that can draft purchase orders, reconcile bank transactions, or answer natural-language financial queries are the highest-value agentic workflows in enterprise SaaS right now. But an agent is only as useful as the data it can access. The financial data locked inside ERPs is precisely where autonomous agents deliver measurable business impact.

The problem is that ERPs were never designed for AI consumption. They were built for human operators clicking through forms, not for LLMs issuing API calls at machine speed. Both NetSuite and SAP enforce strict concurrency limits specifically because their architectures assume relatively low-frequency, human-initiated interactions. When you point an AI agent at these systems, you hit those limits hard.

This creates a core tension: the data your agent needs most is stored in the systems that are hardest to integrate with programmatically.

Market Context: NetSuite vs SAP in the Mid-Market

Before writing a single line of integration code, product managers must decide which ERP ecosystem to tackle first. The decision should be driven by your target customer demographic, not just API preference.

According to Gartner's 2025 Market Guide for Cloud ERP, Oracle NetSuite and SAP dominate the mid-market segment (companies with $10M to $500M in revenue). NetSuite holds approximately 34% of the cloud ERP market for mid-market companies, growing revenue 18% YoY to $1 billion per quarter. With over 43,000 customers across 219 countries, it dominates the North American mid-market, particularly in professional services, SaaS, and e-commerce.

SAP Business One maintains a 22% share globally, though that number rises to 38% in DACH (Germany, Austria, Switzerland) regions. More than 83,000 customers and 1.2 million users across more than 170 countries rely on SAP Business One, supported by a global network of 850 partners. SAP's footprint skews heavily toward manufacturing, distribution, and legacy enterprise subsidiaries.

Dimension Oracle NetSuite SAP (S/4HANA + Business One)
Primary Market Mid-market ($10M-$500M rev) SMB through large enterprise
Customer Count 43,000+ 83,000+ (B1) + enterprise S/4HANA
Strongest Verticals Professional services, SaaS, retail Manufacturing, distribution, DACH
Cloud Architecture Cloud-native (always has been) Cloud or on-premise (hybrid common)
AI Connector MCP-native AI Connector Service No first-party MCP equivalent

The practical implication for product managers: if your SaaS product targets North American mid-market companies, NetSuite is the unavoidable first target. If you are selling into European manufacturing, logistics, or large enterprises, SAP is mandatory. If you serve both segments, you need an architecture that abstracts both.

Decision Matrix: When to Prioritize NetSuite vs SAP

If you can only invest engineering time in one ERP first, use this matrix. Each row is a concrete signal from your pipeline or product strategy. Score each row, and the platform with more signals wins priority.

Signal Prioritize NetSuite Prioritize SAP
Customer geography >60% North America >40% DACH / EMEA
Customer size $10M-$500M revenue $500M+ or manufacturing SMBs
Industry vertical SaaS, professional services, e-commerce, retail Manufacturing, distribution, logistics, automotive
Deployment model Cloud-only acceptable Must support on-premise or hybrid
Read vs write split Reads dominate (reporting, reconciliation) Writes dominate (order creation, inventory updates)
Query complexity Multi-table JOINs, aggregations needed Single-entity CRUD, pre-built business process APIs sufficient
Auth preference OAuth 2.0 M2M (client credentials with JWT) OAuth 2.0 or Basic Auth with CSRF
AI connector maturity Want first-party MCP support Willing to build custom middleware
Custom field density Heavy customization (OneWorld, multi-currency) Standard S/4HANA with In-App extensions

If you genuinely split 50/50, start with NetSuite. SuiteQL's SQL-like query language produces faster time-to-value for read-heavy AI agent patterns, and the concurrency model is more predictable (a single shared pool you can reason about). SAP's rate limits are API-specific and often undocumented, which means more trial-and-error during development.

NetSuite API Architecture for AI Agents

Writing custom API connectors for NetSuite is an engineering nightmare. NetSuite is not a single API. It requires orchestrating across distinct API surfaces, each with its own capabilities and limitations.

To give an AI agent full context over an accounting environment, your integration must dynamically switch between these surfaces:

  1. SuiteTalk REST: The standard record API. It works for basic CRUD operations but fails completely when you need complex JOINs across multiple tables.
  2. SuiteQL: NetSuite's SQL-like query language accessible via REST. This is the primary data layer for reads. SuiteQL allows multi-table JOINs and complex filtering, which is exactly what an AI agent needs.
  3. RESTlets (SuiteScript): Custom server-side scripts. Capabilities like dynamic form field metadata (detecting mandatory flags) or generating Purchase Order PDFs are impossible through REST or SuiteQL alone. You have to deploy custom SuiteScript to the customer's instance.
  4. SOAP API: The legacy fallback. SuiteQL does not expose full tax rate configurations. To get sales tax item details, you must fall back to the legacy SOAP getList operation.

SuiteQL: The Primary Data Layer

SuiteQL is the most powerful tool for feeding context to AI agents because it supports JOINs, GROUP BY, aggregations, and complex filtering in a single request—capabilities the basic REST Record Service lacks.

-- Example: Fetch top 10 customers by revenue YTD
SELECT c.companyname, SUM(tl.netamount) as total_revenue
FROM transaction t
JOIN transactionline tl ON t.id = tl.transaction
JOIN customer c ON t.entity = c.id
WHERE t.type = 'CustInvc'
  AND t.trandate >= '2026-01-01'
GROUP BY c.companyname
ORDER BY total_revenue DESC
FETCH FIRST 10 ROWS ONLY

However, SuiteQL is subject to frequency limits and data caps, including a strict 100,000-row query limit. That ceiling is hard—you cannot paginate past it, which means your agent needs to design its queries carefully.

Concurrency: The Real Bottleneck

NetSuite enforces a default concurrency limit of 15 simultaneous requests per account, shared across REST and SOAP web services. This increases by 10 requests for each SuiteCloud Plus license, with higher service tiers offering more capacity.

This shared pool is the single biggest trap for AI agent architectures. SOAP, REST, RESTlets, and SuiteScript web service calls all compete for the same slots. A runaway scheduled script making HTTP calls eats slots that block your REST integration. If your agent fires off 15 parallel queries to build context for a financial analysis, it has consumed the customer's entire API capacity—blocking their Shopify sync, their payroll integration, and everything else.

The NetSuite AI Connector Service

Oracle NetSuite recently introduced the NetSuite AI Connector Service, a protocol-driven integration service supporting the Model Context Protocol (MCP). It gives customers a flexible and scalable way to connect their own AI to NetSuite with a "bring your own AI" model.

NetSuite provides the MCP Standard Tools SuiteApp with a set of tools that let you interact with your NetSuite data, alongside the option to build custom tools via SuiteScript. Every interaction goes through NetSuite's standard security layer, with Oracle providing pre-built tools covering record operations and saved searches.

But here is the honest assessment: Finance users who want to query data in plain English will find it's not ready out-of-the-box. The accuracy risk on financial data is real and showing up consistently in early reports. You need structured prompts, clean GL mapping, and a tolerance for validating every number before you act on it.

The AI Connector Service works well for single-tenant, internal use cases. However, if you are building a multi-tenant B2B SaaS product, you cannot rely entirely on first-party connectors. You need a managed platform to handle the punishing realities of NetSuite's fragmented API surfaces at scale.

SOAP Deprecation and TBA Sunset Timeline

A critical planning detail: SOAP is being deprecated. The 2025.2 SOAP endpoint is the last planned release. By 2028.2, SOAP web services will be fully removed and any remaining SOAP integrations will stop working. Build everything new on REST and OAuth 2.0.

The authentication story is shifting in parallel. As of the 2026.1 release, all newly built integrations should use REST web services with OAuth 2.0. Starting with the 2027.1 release, you will not be able to create new integrations using Token-Based Authentication (TBA). Existing TBA integrations will continue to work, but Oracle recommends migrating to OAuth 2.0 as soon as possible.

Managing these overlapping API surfaces during the transition is a massive hurdle. To see how deep this rabbit hole goes, read our guide on architecting a reliable NetSuite API integration.

graph TD
  Agent[AI Agent / LLM] -->|Tool Call| MCP[MCP Server]
  MCP -->|Unified Request| Router[Polymorphic Router]
  Router -->|Reads| SuiteQL[SuiteQL API]
  Router -->|Writes / Basic CRUD| REST[SuiteTalk REST]
  Router -->|PDFs / Metadata| RESTlet[SuiteScript RESTlet]
  Router -->|Tax Rates| SOAP[Legacy SOAP API]

SAP API Architecture: Navigating OData and SOAP

SAP's enterprise software ecosystem, particularly S/4HANA and its cloud variants, presents massive complexities for AI integration. While NetSuite fragments its API by operation type, SAP fragments its API by protocol and generation.

Connecting an AI agent to SAP S/4HANA or SAP Business One means navigating OData v2/v4 services, legacy BAPIs (Business Application Programming Interfaces), RFCs (Remote Function Calls), IDocs, and SOAP web services—each with distinct authentication models, error handling patterns, and behavioral quirks.

OData: The Primary (But Limited) API

SAP implements REST through OData (Open Data Protocol), specifically OData V2 for most services and V4 for newer ones. OData is SAP's recommended path forward, but it carries hard limitations that directly impact AI agent workflows.

The most severe technical hurdle is the strict pagination and concurrency limits. SAP APIs have a limit on the amount of records returned in a response (defaulting to 1000). When that limit is exceeded, you must consume the OData API using pagination parameters such as $top, $skip, and $count. For custom CDS views, developers hit a hard maximum of 5000 records per fetch using $top. SAP enforces these limits to prevent denial-of-service overloads on the underlying HANA database.

When an AI agent needs to execute a Retrieval-Augmented Generation (RAG) workflow, this 5000-record limit breaks the context gathering phase. You are forced to implement aggressive cursor-based pagination and exponential backoff strategies just to feed the LLM enough data.

The Synchronous Processing Bottleneck

This is where SAP gets truly painful for agentic workflows. SAP explicitly warns (e.g., Note 3542227) about mass operations via OData, citing long processing times due to the synchronous nature of OData services. Batch operations in OData are not processed in parallel, causing severe bottlenecks. If your AI agent attempts to reconcile 500 expenses in a single batch, the synchronous queue will likely time out before the operation completes.

Because OData is stateless and synchronous, SAP S/4HANA independently reprocessing an erroneous message does not make sense; reprocessing must be triggered from the sender system. This means your middleware—not SAP—owns the retry logic, error recovery, and idempotency guarantees.

CSRF Token Handling

Every write operation to SAP requires a valid CSRF token, obtained via a preflight request. Many OData servers require proper CSRF-token handling when creating, updating, or deleting entities for security reasons.

In multi-threaded agent environments, this creates race conditions. Since two requests (the pre-flight and the actual request) are executed for every modification, the pre-flight of one thread can overwrite the CSRF cookie of another. Managing this safely requires robust session handling at the integration layer.

sequenceDiagram
  participant Agent as AI Agent
  participant API as SAP OData API
  participant HANA as SAP HANA DB
  Agent->>API: GET /PurchaseOrders?$top=10000
  API-->>Agent: 400 Bad Request (Max $top is 5000)
  Agent->>API: GET /PurchaseOrders?$top=5000
  API->>HANA: Query First 5000
  HANA-->>API: Results + Skip Token
  API-->>Agent: 200 OK (5000 Records)
  Note over Agent,API: Agent must manually loop <br>using $skip tokens

SuiteQL vs OData: A Head-to-Head for AI Agent Queries

When an AI agent needs to build financial context—fetching data to reason over before taking action—the query layer determines everything about latency, accuracy, and token efficiency.

Capability NetSuite SuiteQL SAP S/4HANA OData
JOINs Full SQL-style JOINs across any tables Limited; $expand is slow and capped at 100 records
Aggregations GROUP BY, SUM, COUNT, AVG Not natively supported in most OData v2 services
Max result set 100,000 rows (hard ceiling) 1,000 per page default; 5,000 max per fetch
Write operations One record per REST POST Batch via changeset (synchronous, sequential)
Query language SQL-like (familiar to LLMs) URL-encoded query params ($filter, $select, $orderby)
Nested data Via JOINs in single query Via $expand (performance penalty)

SuiteQL is dramatically better for AI agent read patterns. A single SuiteQL query can return joined, aggregated financial data that would require 5-10 OData requests on SAP. This matters because every API call consumes concurrency slots and adds latency to the agent's reasoning chain. OData's URL-encoded query syntax is also less natural for LLMs to generate compared to SQL, creating higher error rates in function-calling scenarios.

Read-First Agent Patterns: Practical Query Examples

The fastest path to value with AI agents on ERP data is read-only workflows: querying, summarizing, and reasoning over financial records before you ever attempt writes. Here are concrete query patterns for the most common agent use cases on both platforms.

NetSuite: SuiteQL Patterns for Agents

1. Fetch open invoices for a specific vendor (accounts payable context)

SELECT t.id, t.tranid, t.trandate, t.duedate,
       t.foreigntotal as amount, BUILTIN.DF(t.status) as status,
       v.companyname as vendor_name
FROM transaction t
JOIN vendor v ON t.entity = v.id
WHERE t.type = 'VendBill'
  AND BUILTIN.DF(t.status) LIKE '%Open%'
  AND t.trandate >= '2026-01-01'
ORDER BY t.duedate ASC
FETCH FIRST 100 ROWS ONLY

This single query gives an agent everything it needs to answer "What bills are due this month?" - vendor name, amounts, due dates, and status in one round trip.

2. Cash position summary across accounts

SELECT a.acctnumber, a.fullname,
       SUM(tal.amount) as balance
FROM transactionaccountingline tal
JOIN account a ON tal.account = a.id
JOIN transaction t ON tal.transaction = t.id
WHERE a.accttype = 'Bank'
  AND t.trandate <= '2026-05-20'
GROUP BY a.acctnumber, a.fullname
ORDER BY balance DESC

3. Expense breakdown by category for a date range

SELECT a.fullname as account_name,
       COUNT(*) as transaction_count,
       SUM(ABS(tl.netamount)) as total_amount
FROM transaction t
JOIN transactionline tl ON t.id = tl.transaction
JOIN account a ON tl.account = a.id
WHERE t.type IN ('Check', 'CardChrg')
  AND t.trandate BETWEEN '2026-01-01' AND '2026-03-31'
  AND tl.mainline = 'F'
GROUP BY a.fullname
ORDER BY total_amount DESC
FETCH FIRST 20 ROWS ONLY

Notice the pattern: every query uses FETCH FIRST N ROWS ONLY to stay within the 100,000-row cap and to limit token consumption in the LLM's context window. Agent-generated queries should always include an explicit row limit.

SAP S/4HANA: OData Patterns for Agents

SAP OData queries are URL-encoded, which makes them harder for LLMs to generate correctly. Here are the equivalent patterns:

1. Fetch open supplier invoices

GET /API_SUPPLIERINVOICE_PROCESS_SRV/A_SupplierInvoice
  ?$filter=StatusCode eq '1' and PostingDate ge datetime'2026-01-01T00:00:00'
  &$select=SupplierInvoice,SupplierInvoiceIDByFiscalYear,PostingDate,
           InvoiceGrossAmount,DocumentCurrency,SupplierName
  &$orderby=PostingDate asc
  &$top=100

2. Fetch GL account balances

GET /API_JOURNALENTRYITEMBASIC_SRV/A_JournalEntryItemBasic
  ?$filter=GLAccount eq '100000' and FiscalYear eq '2026'
  &$select=GLAccount,AmountInCompanyCodeCurrency,CompanyCodeCurrency
  &$top=1000

3. Retrieve purchase orders with line items

GET /API_PURCHASEORDER_PROCESS_SRV/A_PurchaseOrder
  ?$filter=CreationDate ge datetime'2026-01-01T00:00:00'
  &$expand=to_PurchaseOrderItem
  &$select=PurchaseOrder,Supplier,PurchaseOrderDate,
           to_PurchaseOrderItem/Material,to_PurchaseOrderItem/NetPriceAmount
  &$top=50
Warning

SAP's $expand is the biggest performance trap for agents. Expanding line items on more than 50-100 parent records in a single request will either time out or get throttled. For agents, it is better to fetch parent records first, then issue targeted $expand calls for only the records the agent needs to reason about.

The key difference: a SuiteQL agent can build a complete financial picture in 1-3 queries. An SAP agent doing the same work typically needs 5-15 OData calls with careful pagination, making the orchestration layer far more complex.

Authentication: OAuth 2.0 Migration for AI Agent Integrations

Authentication is not a set-and-forget concern for ERP integrations. Both NetSuite and SAP are actively deprecating older auth methods, and AI agent architectures built on legacy flows will break.

NetSuite: From TBA to OAuth 2.0 Client Credentials

NetSuite's Token-Based Authentication (TBA) requires HMAC-SHA256 signature generation for every single request - computing a cryptographic signature from consumer key, consumer secret, token ID, and token secret. This works, but it is operationally painful for multi-tenant platforms managing thousands of customer connections.

OAuth 2.0 Client Credentials (M2M) is the replacement. Instead of signing every request, you obtain a short-lived bearer token by posting a signed JWT to NetSuite's token endpoint, then attach that token as a standard Authorization: Bearer header. No per-request signature computation.

Here is the migration timeline you need to plan for:

Release What Changes
2026.1 (now) All new integrations should use REST + OAuth 2.0. Certificate Rotation Endpoint available for programmatic cert management. Dynamic Client Registration (DCR) available.
2027.1 New integrations using TBA will be blocked. PKCE required for all new OAuth 2.0 authorization code grant flows.
2028.2 SOAP fully removed. All remaining SOAP/TBA-only integrations break.

For AI agent platforms, the Client Credentials flow is the right choice - it is designed for server-to-server communication with no user interaction. The access token is short-lived (typically 60 minutes), so your platform needs to handle token refresh automatically.

# Conceptual: NetSuite OAuth 2.0 Client Credentials token request
import jwt, time, requests
 
def get_netsuite_access_token(account_id, client_id, cert_id, private_key):
    now = int(time.time())
    payload = {
        "iss": client_id,
        "scope": "rest_webservices",
        "aud": f"https://{account_id}.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token",
        "iat": now,
        "exp": now + 3600
    }
    headers = {"kid": cert_id}
    assertion = jwt.encode(payload, private_key, algorithm="PS256", headers=headers)
 
    response = requests.post(
        f"https://{account_id}.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token",
        data={
            "grant_type": "client_credentials",
            "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
            "client_assertion": assertion
        }
    )
    return response.json()["access_token"]
Info

NetSuite's OAuth 2.0 Client Credentials flow requires the PS256 (RSASSA-PSS with SHA-256) signing algorithm for JWT assertions. Many standard JWT libraries default to RS256 - using the wrong algorithm will produce an invalid_grant error with no helpful message. Verify your library supports PS256 before writing any code.

SAP: OAuth 2.0 and CSRF Management

SAP S/4HANA Cloud supports OAuth 2.0 via SAP's XSUAA (Authorization & Trust Management) service, while on-premise deployments often still use Basic Auth or client certificates. The bigger headache for AI agents is CSRF - every write operation requires a two-step dance:

  1. GET request with X-CSRF-Token: Fetch header to obtain a token
  2. Actual POST/PATCH/DELETE with the token in X-CSRF-Token header and session cookies

In a multi-tenant integration platform, CSRF tokens must be scoped per customer connection, and the pre-flight request consumes one of your API calls against whatever rate limit applies.

MCP Tool Definitions for ERP Agents

The Model Context Protocol (MCP) standardizes how AI agents discover and invoke tools. If you are exposing ERP data to agents, defining clean MCP tool schemas is where agent accuracy starts - a poorly described tool produces garbage queries.

Here is what a well-structured MCP tool definition looks like for a unified accounting API:

{
  "name": "list_invoices",
  "description": "List invoices from the connected ERP (NetSuite or SAP). Returns invoice ID, vendor/customer name, amount, currency, status, issue date, and due date. Use invoice_type to filter by direction: 'bill' for accounts payable (vendor bills), 'invoice' for accounts receivable (customer invoices). Always specify a date range to avoid hitting row limits.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "invoice_type": {
        "type": "string",
        "enum": ["bill", "invoice"],
        "description": "'bill' for AP (money you owe), 'invoice' for AR (money owed to you)"
      },
      "issue_date_gte": {
        "type": "string",
        "format": "date",
        "description": "Filter invoices issued on or after this date (YYYY-MM-DD)"
      },
      "issue_date_lte": {
        "type": "string",
        "format": "date",
        "description": "Filter invoices issued on or before this date (YYYY-MM-DD)"
      },
      "status": {
        "type": "string",
        "enum": ["OPEN", "PAID", "CANCELLED", "SUBMITTED", "REJECTED"],
        "description": "Filter by invoice status"
      },
      "limit": {
        "type": "integer",
        "default": 50,
        "maximum": 200,
        "description": "Max records to return. Keep low to reduce token usage."
      }
    },
    "required": ["invoice_type"]
  }
}

A few design principles that matter for financial tools:

  • Enum constraints on invoice_type and status prevent LLM hallucination. Without enums, an agent might request type: "payable" or status: "unpaid", producing silent failures.
  • The description field does the heavy lifting. The agent has no other context about what "bill" vs "invoice" means in accounting terms. Write these descriptions for an LLM, not a human developer.
  • Default and maximum on limit protect against agents requesting unbounded result sets that blow up context windows or hit API row caps.
  • Date parameters are explicit, not implicit. Without date guidance in the tool schema, agents tend to omit date filters entirely - which on a large NetSuite instance returns 100,000 rows and exhausts the SuiteQL ceiling.

Here is a second tool for a common write pattern:

{
  "name": "create_expense",
  "description": "Create an expense record in the connected ERP. Requires an account ID (chart of accounts), vendor contact ID, amount, and transaction date. Returns the created expense ID. Use list_accounts with classification='EXPENSE' to find valid account IDs first.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "account_id": {
        "type": "string",
        "description": "The chart-of-accounts ID for the expense category. Get this from list_accounts."
      },
      "contact_id": {
        "type": "string",
        "description": "The vendor/payee contact ID. Get this from list_contacts."
      },
      "amount": {
        "type": "number",
        "description": "Expense amount in the account's base currency"
      },
      "currency": {
        "type": "string",
        "description": "ISO 4217 currency code (e.g., USD, EUR)"
      },
      "transaction_date": {
        "type": "string",
        "format": "date",
        "description": "Date of the expense (YYYY-MM-DD)"
      },
      "memo": {
        "type": "string",
        "description": "Description or memo for the expense line"
      }
    },
    "required": ["account_id", "contact_id", "amount", "transaction_date"]
  }
}

The cross-references in descriptions ("Get this from list_accounts") are intentional. They teach the agent to chain tools in the correct order rather than guessing at IDs.

Architectural Tradeoffs: Rate Limits, Custom Fields, and Security

When evaluating NetSuite vs SAP for AI agents, the architectural tradeoffs extend beyond basic connectivity. You must account for how your infrastructure handles rate limits, custom object mapping, and data security.

Handling API Rate Limits and Concurrency

AI agents are notoriously aggressive API consumers. When an LLM executes a loop of tool calls to find a specific transaction, it can easily trigger upstream rate limits.

For concurrency planning, NetSuite gives you a single, predictable constraint to engineer around (the 15-slot default pool). SAP S/4HANA Cloud manages rate limits via API Management policies (Quota, Spike Arrest, Concurrent Rate Limit), which vary by service and deployment type, often forcing developers to explore the SAP Business Accelerator Hub just to understand throttling thresholds.

Warning

A common misconception is that middleware should magically absorb and retry rate limit errors indefinitely. This is an anti-pattern. A robust platform takes a highly objective approach: do not retry, throttle, or apply backoff on rate limit errors in the proxy layer. When an upstream API like SAP or NetSuite returns an HTTP 429 (Too Many Requests), that error must pass directly to the caller.

Instead of masking the failure, modern integration infrastructure normalizes the upstream rate limit information into standardized headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset) following the IETF specification. The caller—your application or the AI agent's orchestration framework—is responsible for implementing intelligent retry and backoff logic. This ensures your agent is aware of the actual API constraints and can adjust its behavior, deciding whether to wait or switch tasks.

Concurrency Mitigation Patterns for AI Agents

Knowing the rate limits exist is not enough. Here are concrete patterns to keep your agents from burning through a customer's entire API budget.

Pattern 1: Request aggregation with SuiteQL

Instead of letting an agent issue individual record fetches, aggregate into a single SuiteQL query:

# Bad: 10 API calls to fetch 10 vendors by ID
for vendor_id in vendor_ids:
    result = netsuite_rest_get(f"/record/v1/vendor/{vendor_id}")
 
# Good: 1 SuiteQL call returning all 10 vendors
ids_clause = ",".join(vendor_ids)
query = f"""
    SELECT id, companyname, email, phone
    FROM vendor
    WHERE id IN ({ids_clause})
"""
result = netsuite_suiteql(query)

This turns 10 concurrency slot consumptions into 1. For a 15-slot account, that is the difference between blocking other integrations and leaving headroom.

Pattern 2: Semaphore-based concurrency control

Wrap all ERP API calls behind a per-account semaphore that respects the customer's concurrency limit:

import asyncio
 
class ERPConcurrencyGuard:
    def __init__(self, max_concurrent: int = 5):
        # Reserve slots for other integrations.
        # If account limit is 15, never use more than 5.
        self.semaphore = asyncio.Semaphore(max_concurrent)
 
    async def call(self, request_fn, *args, **kwargs):
        async with self.semaphore:
            return await request_fn(*args, **kwargs)
 
# Usage: cap your agent at 5 concurrent ERP calls,
# leaving 10 slots for the customer's other integrations
guard = ERPConcurrencyGuard(max_concurrent=5)
result = await guard.call(netsuite_suiteql, query)

Pattern 3: Caller-side backoff on 429s

Since the integration layer should pass 429 errors through transparently, the agent orchestration layer needs to handle retries:

import asyncio, random
 
async def call_with_backoff(request_fn, max_retries=4):
    for attempt in range(max_retries):
        response = await request_fn()
        if response.status_code != 429:
            return response
 
        # Use ratelimit-reset header if available
        retry_after = int(
            response.headers.get("ratelimit-reset",
            min(2 ** attempt + random.uniform(0, 1), 30))
        )
        await asyncio.sleep(retry_after)
 
    raise Exception("ERP rate limit exceeded after max retries")

The combination of aggregation + semaphore + caller-side backoff gives you a three-layer defense against concurrency exhaustion. This is not optional when building multi-tenant agent platforms - a single customer's runaway agent loop can degrade performance for every other tenant sharing that NetSuite account.

Custom Fields: The Silent Complexity Multiplier

Every NetSuite and SAP instance is customized. Custom fields, custom record types, and unique subsidiary structures are the norm. Your AI agent must be able to read and write to these custom fields dynamically.

NetSuite exposes custom fields through its metadata catalog and SuiteQL schema. Its multi-subsidiary setup (OneWorld) requires feature-adaptive queries that dynamically include or exclude JOINs based on the customer's specific NetSuite edition.

SAP supports custom fields through In-App Extensibility, allowing users to introduce additional fields to an existing S/4HANA service, consumable via .setCustomField and .getCustomField methods. Neither platform makes this easy. Custom field discovery, type mapping, and per-customer schema differences compound when generating dynamic tool schemas for AI agents.

Zero Data Retention for Financial Payloads

Passing financial payloads to LLMs introduces massive security and compliance risks. If your integration infrastructure caches or stores ERP data, you instantly inherit the customer's SOC 2, GDPR, and financial compliance burdens.

Pass-through architecture is a strict requirement. When building AI agents for financial data, the integration layer must act as a stateless proxy. Payloads must move from the ERP, through the normalized execution pipeline, directly to the AI agent's context window, without ever touching a persistent database. For a deeper dive into this security model, read our guide on building ERP integrations without storing customer data.

Abstracting the ERP Mess with Unified APIs

Building point-to-point connectors for legacy systems like NetSuite and SAP is a massive technical debt trap. Every hour your engineering team spends deciphering SAP OData pagination tokens or NetSuite HMAC signatures is an hour stolen from building actual AI features.

The architectural cure to this technical debt is a unified API layer built on a zero integration-specific code architecture. Instead of writing custom Node.js or Python scripts for every ERP, modern platforms abstract the differences between NetSuite's SuiteQL and SAP's OData APIs into a single execution pipeline.

flowchart LR
    A[AI Agent] --> B[Unified API Layer]
    B --> C{ERP Router}
    C -->|NetSuite| D[SuiteQL + REST<br>OAuth 1.0 TBA]
    C -->|SAP S/4HANA| E[OData v2/v4<br>CSRF + Basic Auth]
    C -->|SAP Business One| F[Service Layer API<br>Session Auth]
    D --> G[Normalized Response]
    E --> G
    F --> G
    G --> A

A unified API normalizes complex ERP data models—including multi-currency and multi-subsidiary setups—without requiring developers to write custom mapping logic. A single unified contacts resource dynamically routes to the vendor or customer NetSuite resource based on query parameters. An AI agent simply calls a standard REST endpoint or MCP tool, and the underlying platform handles the polymorphic routing, CSRF token pre-flights, authentication, and feature detection.

The honest caveat: unified APIs involve tradeoffs. You lose some platform-specific capabilities in exchange for standardization. For 80% of AI agent use cases, the normalized model covers it. For the remaining 20% (custom SuiteScripts, SAP BAPIs, highly specialized workflows), you need a proxy API that passes through raw requests to the underlying platform.

Primary Agent Use Cases for ERP Data

Once the API layer is abstracted, AI agents can execute complex workflows across both NetSuite and SAP:

  1. Automated Order-to-Cash (E-Commerce Sync): An AI agent monitors an external e-commerce platform. When an order is placed, it automatically queries or creates a Contact, generates an Invoice with the correct Items, and instantly logs the Payment upon checkout, keeping the ledger synced.
  2. Intelligent Expense Parsing: A Slackbot or automated email processor ingests a receipt, uses a vision model to extract the total and vendor, queries the API to find the matching Contact and Account, creates an Expense, and uploads the image via Attachments.
  3. Automated Bank Reconciliation: Fetch raw bank Transactions and use an LLM to heuristically match them against open Invoices or Expenses, proposing reconciliation pairs to the finance team.
  4. Natural Language Financial Reporting: An executive asks an agentic dashboard for current cash flow. The agent leverages the Reports and Accounts endpoints to fetch real-time Profit & Loss data and summarizes the health of the business without requiring the user to log into the ERP.

Testing and Validation Checklist for Financial Accuracy

Financial data has zero tolerance for approximation. An agent that misreads an invoice total or misclassifies an account type can cause real monetary damage. Before deploying any ERP-connected agent to production, run through this checklist.

Data Integrity Checks

  • Currency handling: Verify amounts use the correct currency code. Multi-currency NetSuite accounts return amounts in transaction currency, not base currency, unless your query explicitly converts. Confirm your agent never mixes currencies when summing.
  • Sign conventions: NetSuite credit memos and vendor credits use negative amounts. SAP refunds may use positive amounts with a reversal indicator. Validate that your normalization layer handles sign conventions consistently across both platforms.
  • Rounding: Compare agent-computed totals against ERP-reported totals. SuiteQL returns unrounded decimal values; ensure your agent does not introduce floating-point drift when summing line items.
  • Date boundaries: SuiteQL date filters use inclusive boundaries. OData datetime filters can behave differently between V2 and V4. Confirm that "transactions in Q1" returns exactly Jan 1 through Mar 31, not Jan 1 through Apr 1.

Agent Output Validation

  • Cross-reference totals: For any summarization task, have the agent independently query the summary and the underlying line items, then compare. If the sum of line item amounts does not match the header total, flag it.
  • Status mapping: Verify that NetSuite single-character status codes (A, B, C, D, E) map correctly to your unified statuses (OPEN, PAID, CANCELLED, SUBMITTED, REJECTED). A mismap between "Cancelled" and "Paid" is a catastrophic error.
  • Entity resolution: When the agent matches a vendor name from a receipt to a contact in the ERP, log the confidence score and require human confirmation below a threshold. Fuzzy matching on vendor names is where most expense-parsing agents fail.
  • Custom field presence: If your agent relies on custom fields (e.g., custbody42 in NetSuite), verify they exist in the target account before issuing writes. Custom fields vary per customer instance.

Concurrency and Performance Validation

  • Concurrency ceiling test: Simulate your maximum expected agent load against a sandbox account. Verify that at peak concurrency your agent never consumes more than 30-40% of the customer's total API slots.
  • 429 recovery: Deliberately trigger rate limits in testing. Confirm that 429 responses pass through to the agent, the retry logic kicks in with appropriate backoff, and the agent eventually succeeds or gracefully reports failure.
  • Query row limits: Test SuiteQL queries that could return more than 100,000 rows. Confirm your agent adds appropriate WHERE clauses and FETCH FIRST N ROWS ONLY to stay under the ceiling.
Tip

Run these checks in a NetSuite sandbox and SAP test tenant before touching production data. Both platforms offer sandbox environments specifically for integration testing - use them. The cost of a wrong write to a production general ledger is orders of magnitude higher than the time spent on sandbox validation.

What to Build First: A Decision Framework

If you are a PM or engineering lead deciding which ERP integration to prioritize for your AI agent product, here is a practical framework:

  1. Audit your customer base. Which ERP appears most in your pipeline? If you don't know, ask your sales team. If your customers are North American SaaS or e-commerce companies, build NetSuite first. If they are European manufacturers, SAP takes priority.
  2. Start with read-only. AI agents that can query and summarize financial data deliver value immediately with lower risk than write operations. Build reads first, writes second.
  3. Plan for both. Your enterprise customers will eventually need both NetSuite and SAP. If you build point-to-point connectors for each, you are signing up for permanent maintenance of two divergent codebases.
  4. Evaluate your concurrency budget. With NetSuite's 15-slot default, your agent cannot afford chatty API patterns. Design for minimal round trips—SuiteQL queries that return joined data, not dozens of individual record fetches.
  5. Choose your abstraction layer early. Whether you build custom middleware or adopt a unified API, the cost of refactoring later far exceeds the cost of choosing an abstraction up front.

The ERP integration landscape for AI agents is moving fast. NetSuite's MCP adoption signals that ERP vendors recognize the demand for AI-native connectivity. SAP will likely follow. But in 2026, the engineering work of making these legacy systems agent-friendly still falls squarely on the teams building the products.

Do not build this infrastructure in-house. Abstract the complexity, enforce zero data retention, and give your AI agents the standardized tools they need to actually do their jobs.

FAQ

What is the best way to connect AI agents to Oracle NetSuite?
Use SuiteQL as the primary read layer for multi-table JOINs and aggregations in a single query. Authenticate via OAuth 2.0 Client Credentials (M2M) with PS256-signed JWTs. Wrap all API calls behind a per-account concurrency semaphore (cap at 5 of the 15 default slots), and always add FETCH FIRST N ROWS ONLY to stay under the 100,000-row ceiling. For multi-tenant SaaS, abstract NetSuite behind a unified API that handles polymorphic routing and feature detection automatically.
How do AI agents handle SAP S/4HANA OData rate limits?
SAP does not publish universal rate limits - they vary by API and deployment. Use $top with a max of 5000, paginate with $skip tokens, avoid large $expand statements, and implement caller-side exponential backoff on 429 errors. For writes, pre-fetch CSRF tokens per session and scope them per customer connection to avoid race conditions in multi-threaded agent environments.
Should I build NetSuite or SAP integration first for my AI agent product?
If your customers are primarily North American mid-market companies in SaaS, professional services, or e-commerce, start with NetSuite. If they are European manufacturers or large enterprises, start with SAP. NetSuite's SuiteQL provides faster time-to-value for read-heavy agent workflows because a single query can return joined data that would require 5-10 OData requests on SAP.
What is the NetSuite SOAP deprecation timeline?
The 2025.2 SOAP endpoint is the last planned release. Starting with 2026.1, no new SOAP endpoints will be added. By 2027.1, you cannot create new integrations using TBA or SOAP. By 2027.2, only the 2025.2 endpoint will be supported. By 2028.2, SOAP is fully removed and all SOAP integrations stop working. Build all new integrations on REST with OAuth 2.0.
How do you validate financial accuracy when AI agents query ERP data?
Cross-reference agent-computed totals against ERP header totals, verify currency codes are not mixed in multi-currency accounts, confirm sign conventions for credits and refunds, test date boundary behavior between SuiteQL and OData, and validate status code mappings. Always test in sandbox environments before production, and require human confirmation for entity matching below a confidence threshold.

More from our Blog