Schedule a demo

API rate limiting and firewall

API rate limiting controls how many requests a client can make to your APIs within a given time window. In Zato, the same mechanism also works as an IP-based firewall - you can silently drop connections from unwanted addresses, exactly like a network firewall would.

A few real-world examples of how you can use it:

  • Cap each API partner at 1,000 requests per hour across all endpoints they authenticate to (identity-aware rate limiting), no matter how many individual REST endpoints they invoke

  • Apply stricter limits during maintenance windows and relax them during business hours - or the other way around, allow only a few req/s throughout the day but allow 10x more between 01:00 and 02:00 when you know batch loading processes run - with each time range tracked by its own independent counters

  • Set both a per-second burst limit and a per-day or per-month hard cap on the same rule, so short traffic spikes are absorbed while the total daily or monthly budget is still enforced

  • Allow only your internal address ranges to reach an endpoint and silently drop everything else, turning a REST channel into a private API without a separate network-level firewall

  • Block entire IP ranges with a silent TCP drop that reveals nothing about the server behind the address - scanners and automated tools see only a connection reset, identical to a network firewall

Identity-level and channel-level limits

Rate limiting can be configured on two levels, either in combination or independently.

  • Security definitions - limits apply to all channels that use a given Basic Auth or API key definition, regardless of which channel is called. This is identity-aware rate limiting - the limit follows the credential, not the IP address or the channel endpoint. A single partner authenticating to ten different channels still has one shared limit.
  • REST channels - limits apply to a specific channel endpoint

When both are configured, security definition limits are checked first. If the security definition allows the request through, the channel limits are checked next. This two-level design means you can set a global cap per partner (via security definitions) and a separate, tighter cap on individual endpoints (via channels), without the two interfering.

Concepts

Rules and address lists

Each rate limiting configuration consists of one or more rules. Each rule has an address list - a set of IP addresses or ranges that it matches against - and one or more time ranges with their own limits. There is no hard cap on the number of addresses per rule or on the number of rules per channel.

Addresses can be single IPs (e.g. 192.168.1.10) or ranges in subnet notation (e.g. 10.0.0.0/8 meaning all addresses from 10.0.0.0 to 10.255.255.255). Both IPv4 and IPv6 are supported.

If a rule's address list is empty, it matches all client IP addresses. If addresses are specified, only requests from matching addresses are subject to that rule. Rules are evaluated top to bottom - the first rule whose address list matches the client IP is used.

Allow lists and deny lists

You can combine allow and deny rules to build precise IP access policies. For example, a rule allowing 10.0.0.0/8 followed by a catch-all disallow rule creates a classic allowlist.

A rule disallowing 203.0.113.0/24 followed by a permissive catch-all creates a denylist. More specific addresses in earlier rules naturally take precedence over broader ranges in later rules, because rules are evaluated in the order you define.

Time ranges

Each rule has at least one time range - the all-day default. You can add additional time ranges for specific hours of the day (e.g. 09:00-17:00). When a request arrives, Zato checks time ranges in order:

  • If a specific time range covers the current time and is not disabled, it is used
  • Otherwise, the all-day default is used

Each time range has its own independent set of limits and counters.

Burst control and hard caps

Each time range gives you two controls that work together:

  • Rate and Burst - how many requests per second are allowed, and how large a short spike can be before throttling kicks in. For example, rate=100 and burst=200 means a client can send 200 requests in a quick burst, but sustained traffic cannot exceed 100 per second.

  • Limit and Time unit - a hard ceiling on the total number of requests over a longer period. The time unit is a fixed calendar interval - when it ends, the counter resets to zero and the client gets a fresh allowance. For example, a limit of 1,000 per minute means the counter resets at the top of every minute (10:00:00, 10:01:00, 10:02:00, ...). A limit of 20,000 per day means the counter resets at midnight. A limit of 500 per hour means a client that exhausts its quota at 14:37 can send again at 15:00. Note that monthly limits respect actual calendar days, e.g. 30 days in June, 31 in July, 28 or 29 in February, and so on.

What happens when a request is denied?

When a request is denied, Zato always returns HTTP 429 Too Many Requests with a Retry-After header containing an HTTP-date timestamp indicating when the client can retry.

$ curl -v http://user:password@localhost:17010/api/customer

< HTTP/1.1 429 Too Many Requests
< Retry-After: Mon, 01 Jun 2026 00:00:00 GMT
{
    "result": "Error",
    "cid": "20260504-113121-2314-57a1b3646a55499ea",
    "details": "Too many requests"
}

Disallowed traffic (firewall mode)

If a time range is marked as disallowed, Zato does not return an HTTP error at all. Instead, it silently drops the TCP connection, exactly as a network firewall would, without any response headers, response bodies, or HTTP status codes - the connection is simply closed, and the client sees a connection reset or timeout.

This is useful for blocking entire IP ranges, denying access outside business hours, or implementing geographic restrictions at the application level of Zato.

$ curl -v http://user:password@localhost:17010/api/customer

curl: (56) Recv failure: Connection reset by peer

Disabled rules

A time range can be disabled, which means it is skipped during evaluation. If the all-day default is disabled and no other time range matches, rate limiting is effectively turned off for that rule (meaning all traffic is always allowed). This lets you temporarily suspend rate limiting without deleting the configuration.

Disabling a rule takes effect immediately and does not reset counters. When you re-enable the rule, the existing counters resume from where they were. If you need a clean slate, use the Clear counters link separately.

What happens on server restarts?

All counters are reset to zero when the server restarts. Rate limiting rules and configuration are loaded automatically on startup, but, since the counters themselves are held in memory and are not permanent, they all start from zero again after a restart.

Configuring rate limiting on REST channels

In Dashboard, navigate to the REST channel list via Connections -> Channels -> REST. Each channel row has a Rate limiting link.

Click it to open the rate limiting editor for that channel.

From here you can:

  • Add IP addresses or ranges to restrict which clients the rule applies to
  • Add time ranges with specific hours
  • Set rate, burst, limit, and time unit for each time range
  • Enable or disable individual time ranges
  • Mark time ranges as disallowed (firewall mode)
  • Reorder rules by dragging
  • Clear counters for a specific rule
  • Save to apply changes immediately without restarting

Configuring rate limiting on security definitions (identity-aware)

Navigate to Security -> Basic Auth or Security -> API Keys. Each definition row has a Rate limiting link, the same as for channels.

Rules configured here apply to every channel that uses this security definition. The limit follows the credential, not the endpoint. For example, if a Basic Auth user "api-partner-1" has a limit of 100 requests per minute, that limit is enforced across all channels that "api-partner-1" authenticates to - whether the partner calls /orders, /invoices, or any other endpoint protected by the same definition.

This is identity-keyed rate limiting: the counter is tracked per security definition, so a single partner cannot bypass the limit by distributing requests across multiple channels. Each security definition has its own independent counters - "partner-a" and "partner-b" never share a bucket, even if they call the same endpoints. There is no account-wide shared bucket where one misbehaving client can exhaust limits for everyone else.

Client IP resolution

Zato determines the client IP address using the following headers, checked in this order:

  1. X-Zato-Forwarded-For
  2. X-Forwarded-For
  3. REMOTE_ADDR

The first non-empty value is used. If your deployment is behind a load balancer or reverse proxy, make sure one of these headers carries the real client address.

When IP resolution is not enough - for example, when many users share one address through mobile carriers, corporate NATs, or iCloud Private Relay and similar - use identity-aware rate limiting via security definitions instead, so the limit follows each credential rather than the shared IP.

Live updates

Changes saved through the Dashboard take effect immediately, there is no need to restart the server, no propagation delay, no estimation window, and no grace period during which old rules still apply, which means you can respond to an ongoing incident by changing limits in real time.

When you click "Save", existing counters are preserved across configuration updates, so changing a limit doesn't reset the counters - if a client has used 80 of 100 allowed requests and you raise the limit to 200, they immediately have 120 remaining.

FAQ and examples

How do I limit a partner to 100 requests per minute?

  1. Create a Basic Auth or API key definition for the partner
  2. Open its rate limiting editor
  3. Set the all-day rule to Limit: 100, Time unit: minute
  4. Set Rate and Burst high enough (e.g. 100 and 200) so the per-second limit does not interfere
  5. Save

Every channel this partner authenticates to now enforces the 100/minute cap - the limit follows the credential across all endpoints.

How do I block a specific IP range?

  1. Open the rate limiting editor for the channel or security definition
  2. Add a rule with the address range you want to block (e.g. 172.16.0.0/12)
  3. Set the all-day time range to disallowed
  4. Save

Requests from that range will be silently dropped at the TCP level. You can add as many addresses per rule as needed - there is no limit on list size.

How do I allow only internal IPs?

  1. Create a rule with your internal address ranges (e.g. 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
  2. Set generous limits on that rule
  3. Create a second rule with an empty address list (matches everything)
  4. Mark the second rule as disallowed
  5. Save

Since rules are evaluated top to bottom, internal IPs match the first rule and get through, while all other IPs hit the catch-all disallow rule and are silently dropped.

How do I apply different limits during business hours?

  1. Open the rate limiting editor
  2. Add a time range for business hours (e.g. 09:00-17:00) with a higher limit
  3. Configure the all-day default with a lower limit for off-peak hours
  4. Save

Each time range has its own independent counters. You can define as many time ranges as needed - for example, one for peak hours with generous limits, one for maintenance windows with tight limits, and the all-day range as a baseline.

How do I temporarily disable rate limiting?

  1. Open the rate limiting editor
  2. Click the toggle to disable the all-day rule (and any specific time ranges)
  3. Save

Disabled rules are skipped during evaluation. You can re-enable them later without losing the configuration, and the change takes effect immediately - no need to restart anything.

How do I clear a channel's or client's counters?

  1. Open the rate limiting editor
  2. Click the Clear counters link on the rule row whose counters you want to reset

This clears all counters for that rule immediately - both the per-second burst counter and the hard cap counter. The client can resume sending requests right away without waiting for a time unit to expire.

Can I automate the creation of rules and conditions?

Yes. Zato's enmasse tool lets you define rate limiting rules in YAML and import them from the command line or CI/CD pipelines, without using the Dashboard at all.

Rate limiting is configured as a rate_limiting key on channel_rest and security entries. For example:

channel_rest:
  - name: my.api.channel
    service: my.service
    url_path: /api/v1/data
    rate_limiting:
      - cidr_list:
          - 10.0.0.0/8
        time_range:
          - is_all_day: false
            time_from: '09:00'
            time_to: '17:00'
            disabled: false
            disallowed: false
            rate: 100
            burst: 200
            limit: 5000
            limit_unit: hour
      - cidr_list:
          - 0.0.0.0/0
        time_range:
          - is_all_day: true
            disabled: false
            disallowed: false
            rate: 10
            burst: 20
            limit: 500
            limit_unit: hour

security:
  - name: partner.credentials
    type: basic_auth
    username: partner1
    rate_limiting:
      - cidr_list:
          - 0.0.0.0/0
        time_range:
          - is_all_day: true
            disabled: false
            disallowed: false
            rate: 200
            burst: 400
            limit: 10000
            limit_unit: day

The full YAML reference, including all supported fields and their meanings, is in the enmasse reference - point your AI assistant at that page to have it generate or modify rules for you automatically.