This card covers the architecture pattern of placing an API gateway between API consumers and ERP backend systems. It is system-agnostic and applies to any ERP (Salesforce, SAP S/4HANA, Oracle ERP Cloud, Dynamics 365, NetSuite, Workday) with any gateway product (Kong, Apigee, AWS API Gateway, Azure APIM, SAP API Management). The card does NOT cover iPaaS-specific API management features (MuleSoft API Manager, Boomi API Management) — those are covered in the iPaaS comparison card.
| System | Role | API Surface | Direction |
|---|---|---|---|
| API Gateway (Kong / Apigee / AWS / Azure APIM / SAP) | Proxy, auth, rate limiting, monitoring | REST, OData passthrough | Inbound from consumers |
| ERP System(s) | Backend data source / target | REST, OData, SOAP, Bulk | Outbound to consumers via gateway |
| iPaaS (optional) | Data transformation, orchestration | N/A | Between gateway and ERP |
| API Consumers | Applications, partners, agents | REST (via gateway) | Inbound |
Comparison of what each gateway product offers for ERP API proxying.
| Gateway | Deployment | Rate Limiting | Request Transform | Auth Methods | Circuit Breaker | Pricing Model |
|---|---|---|---|---|---|---|
| Kong Gateway 3.x | Self-hosted, Konnect Cloud | Sliding window, fixed window | Headers, query, body (plugins) | OAuth 2.0, JWT, API key, mTLS | Yes (plugin) | OSS free; Enterprise ~$50K+/yr |
| Google Apigee X | Google Cloud managed | Spike arrest, quota, concurrent | AssignMessage, JavaScript, XSLT | OAuth 2.0, API key, SAML, JWT | Yes (target health) | Pay-per-use or committed |
| AWS API Gateway v2 | AWS managed | 10K RPS default, per-route | VTL mapping templates | IAM, Cognito, Lambda authorizer | No native | $1-3.50 per million requests |
| Azure API Management | Azure managed, self-hosted option | Per-key, per-IP, per-subscription | Liquid, XSLT policies | OAuth 2.0, certificates, managed identity | Yes (backend policy) | Dev free; Std ~$700/mo; Prem ~$2,800/mo |
| SAP API Management | SAP BTP managed (OEM Apigee Edge) | Spike arrest, quota | AssignMessage, JavaScript, KVM | OAuth 2.0, API key, principal propagation | Yes (target health) | Bundled with Integration Suite |
| MuleSoft API Manager | Anypoint Platform | Rate limit, spike control, SLA tiers | Full DataWeave (iPaaS-grade) | OAuth 2.0, client ID, JWT | Yes (built-in) | Bundled with Anypoint license |
Gateway rate limits and ERP-native rate limits operate independently. Configure gateway limits to be stricter than ERP limits, or consumers hit opaque ERP errors instead of clean gateway 429 responses.
| ERP System | Native Rate Limit | Window | Gateway Should Be Set To |
|---|---|---|---|
| Salesforce | 100,000 API calls (Enterprise) | 24h rolling | < 90,000/24h (10% margin) |
| SAP S/4HANA Cloud | Fair-use throttling | Per-request | Monitor and adapt |
| Oracle ERP Cloud | Throttled at service level | Per-request | Start at 60 req/min |
| Dynamics 365 (Dataverse) | 6,000 requests per 5 min per user | 5 min rolling | < 5,000/5min per user |
| NetSuite (SuiteTalk) | 10 concurrent, governance units | Per-execution | < 8 concurrent |
| Workday | No published hard limits | N/A | Start at 120 req/min |
| Limit Type | Kong | Apigee | AWS API Gateway | Azure APIM |
|---|---|---|---|---|
| Max request body size | Configurable (default 8MB) | 10 MB | 10 MB | 256 KB - 4 MB (by tier) |
| Request timeout | Configurable (default 60s) | 55s (configurable) | 29s (hard limit, REST API) | 240s (configurable) |
| Max header size | 64 KB | 25 headers / 7 KB each | 10,240 bytes | 32 KB |
| WebSocket support | Yes (Enterprise) | No | Yes (HTTP API) | Yes (Premium tier) |
An API gateway creates a two-layer authentication architecture: the gateway authenticates the consumer; the gateway itself authenticates to the ERP.
| Layer | Who Authenticates | Flow | Token Lifetime | Managed By |
|---|---|---|---|---|
| Consumer-to-Gateway | API consumer (app, partner) | API key, OAuth 2.0 client credentials, JWT | Minutes to hours | Gateway admin |
| Gateway-to-ERP | Gateway service account | ERP-native OAuth 2.0, TBA, certificate | Session-based (hours) | ERP admin |
| ERP | Recommended Auth | Gotcha |
|---|---|---|
| Salesforce | OAuth 2.0 JWT Bearer | Connected app digital certificate required; gateway must cache and refresh tokens |
| SAP S/4HANA | OAuth 2.0 client credentials via BTP | Principal propagation needed if ERP authorization is user-based |
| Oracle ERP Cloud | OAuth 2.0 client credentials | Token refresh endpoint differs from authorization endpoint |
| Dynamics 365 | Azure AD client credentials (managed identity if Azure APIM) | Azure APIM + managed identity = zero-secret setup |
| NetSuite | Token-Based Authentication (TBA) | TBA tokens don't expire; Kong/Apigee need custom plugin for HMAC-SHA256 |
START — Should I put an API gateway in front of my ERP APIs?
├── How many applications/teams consume ERP APIs?
│ ├── 1 (single integration)
│ │ ├── Using iPaaS? YES → SKIP GATEWAY (iPaaS handles concerns)
│ │ ├── Using iPaaS? NO → SKIP GATEWAY (direct API simpler)
│ │ └── External partner access? YES → ADD GATEWAY (security boundary)
│ ├── 2-5 consumers
│ │ ├── All internal? YES → MAYBE (unified monitoring/auth)
│ │ ├── External partners? → ADD GATEWAY (security + per-partner rate limiting)
│ │ └── iPaaS already managing? → CHECK iPaaS API management first
│ └── 6+ consumers or external API program
│ └── ADD GATEWAY — this is the sweet spot
├── Which ERP?
│ ├── Salesforce → Gateway for auth consolidation; rate limiting secondary
│ ├── SAP S/4HANA on BTP → USE SAP API MANAGEMENT (native, principal propagation)
│ ├── SAP on-premise → ADD GATEWAY (reverse proxy)
│ ├── Dynamics 365 → USE AZURE APIM (managed identity, zero-secret)
│ ├── Oracle ERP Cloud → ADD GATEWAY (no built-in API management)
│ └── NetSuite → ADD GATEWAY only if >5 consumers
└── What does the gateway need to do?
├── Rate limiting only → CHECK if ERP native limits sufficient
├── Auth consolidation → ADD GATEWAY
├── Simple transform (header/query) → Gateway OK
├── Complex transform (object mapping) → USE iPaaS instead
├── Monitoring/analytics → ADD GATEWAY
├── API versioning → ADD GATEWAY
└── Caching → ADD GATEWAY (reference data only)
| Criterion | Kong | Apigee X | AWS API Gateway | Azure APIM | SAP API Mgmt |
|---|---|---|---|---|---|
| Best for ERP | Multi-cloud, on-prem SAP | Multi-ERP, analytics | AWS-native workloads | Dynamics 365 | SAP S/4HANA on BTP |
| Rate limiting | Sliding/fixed, cluster-wide | Spike arrest + quota | Per-route, 10K RPS default | Per-key, per-IP, per-sub | Spike arrest + quota |
| Circuit breaker | Yes (plugin) | Via target health | No native | Via backend policy | Via target health |
| Developer portal | Yes (Enterprise) | Yes (built-in) | No | Yes (built-in) | Yes (API Business Hub) |
| Multi-region | Manual per region | Global (Anthos) | Per-region, via CloudFront | Premium tier | Single BTP region |
| OSS option | Yes | No | No | No | No |
| ERP connectors | No (generic proxy) | No (generic proxy) | No (generic proxy) | D365 via Logic Apps | SAP prebuilt adapters |
| Typical cost | OSS free; Ent $50K+/yr | $25K-$100K+/yr | $1-3.50/M requests | $700-$2,800/mo | Bundled w/ IS |
Audit your ERP API landscape: count consumers, map auth flows, check if your iPaaS already provides API management. [src6]
# Audit checklist
# 1. How many applications call ERP APIs? If < 5 internal, gateway may be overkill
# 2. Do external partners need ERP data? If yes, gateway is mandatory
# 3. Does your iPaaS have API management? (MuleSoft API Manager, Boomi, SAP API Mgmt)
# 4. Which ERP systems? D365 = Azure APIM; SAP BTP = SAP API Mgmt
# 5. Timeout requirement? AWS API GW hard limit 29s (REST API type)
Verify: If < 5 internal consumers and iPaaS handles auth/rate limiting → skip the gateway.
The gateway must authenticate to each ERP using ERP-native credentials. This is the most error-prone step. [src3]
# Kong declarative config — Salesforce OAuth 2.0 JWT Bearer
services:
- name: salesforce-api
url: https://your-instance.salesforce.com
routes:
- name: salesforce-query
paths:
- /erp/salesforce
plugins:
- name: request-transformer
config:
add:
headers:
- "Authorization: Bearer $(cached_sf_token)"
Verify: curl -H "apikey: KEY" https://gateway.example.com/erp/salesforce/services/data/v62.0/limits → returns Salesforce API limits JSON.
Configure gateway rate limiting with 10-15% safety margin below ERP native limits. [src7]
# Kong rate-limiting plugin — Salesforce example
plugins:
- name: rate-limiting
service: salesforce-api
config:
minute: 60
hour: 3500
day: 85000 # 85K vs Salesforce 100K = 15% margin
policy: cluster # Cluster-wide counter, not per-node
hide_client_headers: false
Verify: Send 65 requests in 1 minute → requests 61-65 return HTTP 429 with Retry-After header.
ERP systems have maintenance windows. A circuit breaker at the gateway prevents cascading failures. [src2]
# Kong upstream health checks (circuit breaker)
upstreams:
- name: salesforce-upstream
healthchecks:
active:
healthy: { interval: 10, successes: 3 }
unhealthy: { interval: 5, tcp_failures: 3, timeouts: 3, http_failures: 3 }
passive:
unhealthy: { tcp_failures: 3, timeouts: 3, http_failures: 3 }
Verify: Simulate ERP downtime → gateway returns 503, stops sending requests, auto-recovers.
# Input: ERP rate limit config, gateway rate limit config
# Output: Validation — are gateway limits safely below ERP limits
def validate_rate_limits(erp_limits: dict, gateway_limits: dict, margin: float = 0.15):
"""Ensure gateway rate limits are below ERP native limits with safety margin."""
issues = []
for window, erp_limit in erp_limits.items():
gw_limit = gateway_limits.get(window)
if gw_limit is None:
issues.append(f"WARNING: No gateway {window} limit — ERP enforces at {erp_limit}")
continue
max_safe = int(erp_limit * (1 - margin))
if gw_limit > max_safe:
issues.append(f"DANGER: Gateway {window} ({gw_limit}) exceeds safe ({max_safe})")
else:
issues.append(f"OK: Gateway {window} ({gw_limit}) safely below ERP ({erp_limit})")
return issues
sf_limits = {"daily": 100_000, "hourly": 5_000}
gw_limits = {"daily": 85_000, "hourly": 4_250}
for line in validate_rate_limits(sf_limits, gw_limits):
print(line)
<!-- Azure APIM inbound policy — Dynamics 365 Dataverse proxy -->
<policies>
<inbound>
<rate-limit-by-key calls="5000" renewal-period="300"
counter-key="@(context.Subscription.Id)" />
<authentication-managed-identity
resource="https://your-org.crm.dynamics.com" />
<rewrite-uri template="/api/data/v9.2/{remaining}" />
<set-header name="OData-MaxVersion" exists-action="override">
<value>4.0</value>
</set-header>
</inbound>
<backend>
<forward-request timeout="120" />
</backend>
<on-error>
<choose>
<when condition="@(context.Response.StatusCode == 429)">
<return-response>
<set-status code="429" reason="Rate limit exceeded" />
<set-header name="Retry-After" exists-action="override">
<value>60</value>
</set-header>
</return-response>
</when>
</choose>
</on-error>
</policies>
# Test Salesforce query through Kong gateway
curl -s -w "\nHTTP Status: %{http_code}\nTime: %{time_total}s\n" \
-H "apikey: YOUR_GATEWAY_KEY" \
"https://gateway.example.com/erp/salesforce/services/data/v62.0/query?q=SELECT+Id,Name+FROM+Account+LIMIT+5"
# Check rate limit headers
curl -s -D - -o /dev/null \
-H "apikey: YOUR_GATEWAY_KEY" \
"https://gateway.example.com/erp/salesforce/limits" \
| grep -i "x-ratelimit"
| Concern | Gateway Can Handle | iPaaS Should Handle | Notes |
|---|---|---|---|
| Header injection (auth tokens) | Yes | Yes | Gateway is simpler |
| Query parameter rewriting | Yes | Yes | Gateway is simpler |
| URL path transformation | Yes | Yes | Gateway is simpler |
| JSON field renaming (flat) | Possible (with plugins) | Yes | Gateway is fragile |
| Object nesting/flattening | No | Yes | Beyond gateway scope |
| Multi-object JOIN across ERPs | No | Yes | iPaaS core capability |
| Error response normalization | Yes | Yes | Gateway is ideal |
| Response caching | Yes | Possible | Gateway is ideal |
Cache-Control: max-age based on data volatility (product catalog: 3600s, order status: 0s). [src1]$batch requests are multipart MIME — some gateways parse these incorrectly, corrupting changeset boundaries. [src5]| Code | Source | Meaning | Cause | Resolution |
|---|---|---|---|---|
| 429 (gateway) | Gateway | Consumer exceeded gateway rate limit | Too many requests | Wait for Retry-After header |
| 429 (ERP) | ERP (passed through) | Exceeded ERP native limit | Gateway limit set too high | Reduce gateway rate limit |
| 502 | Gateway | ERP returned invalid response | ERP downtime, TLS mismatch | Check ERP health, verify TLS cert |
| 503 | Gateway | Circuit breaker open | Repeated ERP failures | Wait for half-open; check ERP |
| 504 | Gateway | ERP response exceeded timeout | ERP slow or maintenance | Increase gateway timeout |
| 401 (gateway) | Gateway | Invalid consumer API key | Credential issue | Rotate consumer key |
| 401 (ERP via 502) | ERP | Gateway ERP token expired | Token cache stale | Refresh ERP OAuth token |
Set gateway timeout = ERP timeout + 5s; use idempotency keys for writes. [src2]Always configure active health checks alongside passive; set recovery interval to match maintenance window. [src2]Use CA-bundle trust, not certificate pinning; 30-day cert expiry alerts. [src3]Implement token refresh on 401; don't cache tokens > 1 hour. [src3]Disable session affinity unless ERP requires it (e.g., SAP stateful RFC). [src5]# BAD — treating the gateway like an ESB/iPaaS
# 200 lines of Lua/JavaScript doing: query SF, query SAP, join data,
# transform schema, apply business rules
# Result: unmaintainable, untestable, no error recovery
# GOOD — gateway handles proxy, auth, rate limiting only
services:
- name: order-integration-api
url: https://mulesoft.example.com/api/v1/orders # Points to iPaaS
plugins:
- name: rate-limiting
config: { minute: 60 }
- name: key-auth
config: { key_names: ["apikey"] }
# BAD — gateway AND iPaaS AND ERP all enforce separate rate limits
# Consumer gets inconsistent 429 errors from different layers
# with different Retry-After values
# GOOD — gateway is the ONLY consumer-facing rate limiter
# iPaaS rate limiting disabled; gateway limits set 15% below ERP
plugins:
- name: rate-limiting
config:
day: 85000 # 15% below Salesforce 100K/24h
policy: cluster
hide_client_headers: false
# BAD — single gateway instance, no failover
# If this node dies, ALL ERP traffic stops
# GOOD — multi-node cluster behind LB with direct-to-ERP fallback
upstreams:
- name: erp-backend
targets:
- target: erp-node-1:443
- target: erp-node-2:443
healthchecks:
active:
healthy: { interval: 5, successes: 2 }
unhealthy: { interval: 2, tcp_failures: 2 }
Use async patterns (202 Accepted + polling) for long-running operations. [src8]Use iPaaS built-in API management first. [src4]NEVER cache POST/PUT/PATCH/DELETE; only cache GET for reference data. [src1]Redact Authorization headers and token fields; use log masking policies. [src7]Pick one: SAP for SAP-centric landscapes, or third-party for multi-ERP. [src5]Preserve ERP pagination URLs in response rewriting rules. [src3]# Check gateway health and upstream ERP status (Kong)
curl -s http://localhost:8001/upstreams/salesforce-upstream/health | jq '.data[].health'
# Check current rate limit counters (Kong)
curl -s http://localhost:8001/plugins | jq '.data[] | select(.name=="rate-limiting") | .config'
# Test gateway-to-ERP latency (difference = gateway overhead, should be < 50ms)
time curl -s -o /dev/null https://your-instance.salesforce.com/services/data/v62.0/limits
time curl -s -o /dev/null -H "apikey: KEY" https://gateway.example.com/erp/salesforce/limits
# Check Azure APIM metrics for D365 backend
az apim api show --resource-group RG --service-name APIM --api-id dynamics365
# Verify gateway TLS cert not expired
echo | openssl s_client -connect gateway.example.com:443 2>/dev/null | openssl x509 -noout -dates
| Gateway | Latest Version | Release | Notable Changes | ERP Impact |
|---|---|---|---|---|
| Kong 3.9 | 2025-12 | Current | Improved WebSocket, new rate-limiting algo | Better event-driven ERP integrations |
| Apigee X | 2025-Q4 | Current | Advanced security analytics | Better ERP API abuse visibility |
| AWS API Gateway v2 | 2024-11 | Current | HTTP API matured (30min timeout) | Higher timeout than REST API (29s) |
| Azure APIM | 2024-05-01 | Current | Self-hosted v2, managed identity improvements | Better D365 zero-secret auth |
| SAP API Mgmt | IS 2024 | Current | Updated Apigee Edge, improved adapters | Tighter BTP + principal propagation |
| Use API Gateway When | Don't Use When | Use Instead |
|---|---|---|
| 6+ apps consume ERP APIs, need unified auth/monitoring | Single iPaaS integration handles auth, rate limiting, monitoring | iPaaS built-in API management |
| External partners need ERP data access | All consumers are internal with direct network | Direct API calls with retry logic |
| Multiple ERPs, need unified consumer experience | Single ERP with well-documented native API | ERP native API directly |
| Need API versioning (proxy old paths to new versions) | ERP API is stable with backward compatibility | ERP native versioning |
| Azure APIM + Dynamics 365 (managed identity, natural fit) | Adding Azure APIM just for non-Azure ERP | Kong or Apigee (cloud-agnostic) |
| SAP BTP landscape needing S/4HANA API management | Non-SAP landscape with no BTP investment | Third-party gateway |
| Need circuit breaker / retry at the edge | iPaaS already has circuit breaker and retry | iPaaS error handling |
| Capability | Standalone Gateway (Kong/Apigee/AWS) | iPaaS API Mgmt (MuleSoft/Boomi/SAP IS) | Notes |
|---|---|---|---|
| Rate limiting | Full (sliding window, quota, spike arrest) | Basic to full (varies by platform) | Standalone more configurable |
| Auth consolidation | Full (OAuth, JWT, API key, mTLS) | Full | Feature parity |
| Request transformation | Simple (headers, query, URL rewrite) | Full (complex object mapping) | iPaaS wins for complex transforms |
| Response caching | Full | Limited | Gateway purpose-built |
| Circuit breaker | Full | Varies | Gateway more configurable |
| Developer portal | Full | Varies | Standalone gateways better |
| API analytics | Full | Basic to full | Apigee excels |
| Multi-ERP orchestration | No (single hop proxy) | Full (multi-step flows) | iPaaS core capability |
| Error recovery | Retry + circuit breaker | Full (DLQ, compensation) | iPaaS wins complex recovery |
| Deployment flexibility | Self-hosted, cloud, hybrid | Cloud-first | Kong wins on-premise |
| Cost (mid-scale) | $0-$50K/yr | $50K-$200K+/yr | Gateway cheaper standalone |