Rate limits

Table of contents

Introduction

To keep the Ongoing WMS API fast and reliable for all integrations, calls to certain API methods are rate limited. This page describes how rate limiting works and how to handle it in your integration.

Rate limits are applied per API method and per calling client on each server. Each limited method has its own independent limit — being rate limited on one method does not affect calls to other methods.

There are two independent rate limit dimensions that may apply to a method:

  • Volume limit — the maximum number of calls allowed within a sliding time window (e.g. 100 calls per 60 minutes).
  • Consecutive failure limit — the maximum number of consecutive failed calls allowed within a sliding time window (e.g. 5 failed calls per 10 minutes). This resets to zero as soon as a call succeeds. It exists to protect against integrations that are stuck retrying a broken request (e.g. invalid credentials, malformed payload) in a tight loop.

Not every API method is rate limited — only methods where the volume of traffic warrants it. Methods without a documented limit are not currently rate limited, but this may change over time.

Limits are enforced per calling client (typically identified by source IP address, and in some cases by user account), so one integration exceeding its limit does not affect other integrations.

What happens when a limit is exceeded

When a limit is exceeded, the API responds with:

  • REST: HTTP status code 429 Too Many Requests, with a JSON RFC 7807 Problem Details body.
  • SOAP: a SOAP fault, with the same rate limit information included in the fault detail.

REST

Example response:


HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
Retry-After: 42
X-RateLimit-Reason: volume
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1717000000


{
  "type": "https://developer.ongoingwarehouse.com/rate-limits",
  "title": "Rate limit exceeded",
  "reason": "volume",
  "status": 429,
  "detail": "Rate limit exceeded: 100 calls per 60 minutes. Try again in 42 seconds.",
  "instance": "/api/v1/orders",
  "limit": 100,
  "windowSeconds": 3600,
  "remaining": 0,
  "retryAfterSeconds": 42
}

SOAP

Example fault:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <soap:Fault>
      <faultcode>soap:Server</faultcode>
      <faultstring>Rate limit exceeded: 100 calls per 60 minutes. Try again in 42 seconds.</faultstring>
      <detail>
        <RateLimitFault>
          <Reason>volume</Reason>
          <Limit>100</Limit>
          <WindowSeconds>3600</WindowSeconds>
          <Remaining>0</Remaining>
          <RetryAfterSeconds>42</RetryAfterSeconds>
        </RateLimitFault>
      </detail>
    </soap:Fault>
  </soap:Body>
</soap:Envelope>

Response headers

Every response from a rate-limited method includes headers describing the current status of the volume limit:

  • X-RateLimit-Limit — the maximum number of calls allowed in the current window.
  • X-RateLimit-Remaining — the number of calls remaining in the current window.
  • X-RateLimit-Reset — Unix timestamp (seconds) for when the current window resets.

If the method also has a consecutive-failure limit configured, the following headers are included as well, reporting the status of that separate dimension:

  • X-RateLimit-Failure-Limit — the maximum number of consecutive failed calls allowed.
  • X-RateLimit-Failure-Remaining — the number of consecutive failures remaining before being blocked.
  • X-RateLimit-Failure-Reset — Unix timestamp (seconds) for when the failure streak resets.

When a call is blocked (429 / SOAP fault), an additional header is included to identify which dimension caused the block:

  • X-RateLimit-Reason — volume if the call volume limit was exceeded, or consecutive-failures if too many failed calls occurred in a row.

A standard Retry-After header (in seconds) is also included on blocked responses, indicating how long to wait before retrying.

Note: In some cases a method may be running in report-only mode, meaning the limit is being monitored but not yet enforced. In that case, the headers above are instead named X-RateLimit-Report-Only-* (and X-RateLimit-Report-Only-Failure-*), and the call is not blocked even if the limit would otherwise have been exceeded.

Best practices for integrations

  • Respect the Retry-After header — wait at least that long before retrying a request that received a 429.
  • Monitor X-RateLimit-Remaining and proactively slow down before hitting the limit, rather than waiting for a 429.
  • Use exponential backoff when retrying after repeated 429 responses.
  • Avoid tight retry loops on failure — if a call keeps failing (e.g. due to bad input or invalid credentials), fix the underlying issue rather than retrying immediately, since repeated failures may trigger the consecutive-failure limit independently of the volume limit.
  • Check X-RateLimit-Reason to distinguish between the two limit types so you can react appropriately (e.g. back off vs. fix a bug).

If you believe your integration needs a higher limit than what's currently configured, please contact us so we can review your use case.