2.23API Call Quota Limits

Created on Aug 17, 2026~11 min read

When integrating with third-party APIs (such as WeChat, payment gateways, etc.), you usually need to comply with their daily/monthly call limits. To avoid business interruptions or bans caused by exceeding the limit, the framework provides a flexible API call quota limit feature that supports daily, weekly, monthly, and permanent total-count strategies, and also allows custom strategies.

After the quota limit is enabled, each request checks the current count according to the configured strategy. If the limit is reached, the request is interrupted directly and an InvalidOperationException is thrown (no HTTP request is actually sent). Use HttpRequestBuilder.SetQuotaKey(key) to assign a quota key to each request and associate it with the quota configuration in HttpClientOptions.

Configuration

1. Register the default quota strategies

Register the default quota strategies in the Startup.cs or Program.cs file:

cs
services.AddHttpRemote(builder =>{    builder.AddDefaultQuotaStrategies();   // Register the four strategies: daily, weekly, monthly, lifetime});

2. Configuring Quota Limits for a Specific HttpClient Client

When registering an HttpClient, use ConfigureOptions to set the QuotaLimits dictionary, associating quota keys with their corresponding limit strategies:

cs
// Configure the default clientservices.AddHttpClient(string.Empty)    .ConfigureOptions(options =>    // Or use the overload: .ConfigureOptions((options, serviceProvider) =>    {        options.QuotaLimits = new Dictionary<string, HttpQuotaLimit>        {            ["wechat/accesstoken"] = new HttpQuotaLimit("daily", 2000), // Daily limit            ["wechat/menu_create"]  = new HttpQuotaLimit("weekly", 1000),   // Weekly limit            ["wechat/upload_media"] = new HttpQuotaLimit("monthly", 50000), // Monthly limit            ["wechat/lifetime_stat"] = new HttpQuotaLimit("lifetime", 10000)    // Lifetime total        };    });// Configure a specific clientservices.AddHttpClient("weixin")    .ConfigureOptions(options =>    // Or use the overload: .ConfigureOptions((options, serviceProvider) =>    {        options.QuotaLimits = new Dictionary<string, HttpQuotaLimit>        {            ["wechat/accesstoken"] = new HttpQuotaLimit("daily", 2000), // Daily limit            ["wechat/menu_create"]  = new HttpQuotaLimit("weekly", 1000),   // Weekly limit            ["wechat/upload_media"] = new HttpQuotaLimit("monthly", 50000), // Monthly limit            ["wechat/lifetime_stat"] = new HttpQuotaLimit("lifetime", 10000)    // Lifetime total        };    });

3. Specifying a Quota Key for a Request

When sending a request, use SetQuotaKey to associate it with the corresponding quota configuration, so that the request is constrained by the matching rule:

cs
var response = await httpRemoteService.SendAsync(    HttpRequestBuilder.Get("https://api.weixin.qq.com/cgi-bin/token")        .SetHttpClientName("weixin")        .SetQuotaKey("wechat/accesstoken"));    // This key is limited to 2000 times per day

Built-in Quota Strategies

The framework provides four common built-in strategies, specified through the Strategy property (case-insensitive):

Strategy nameDescriptionWindow reset rule (based on UTC time)
dailyDaily limitResets at 00:00:00 each day
weeklyWeekly limitResets at 00:00:00 each Monday
monthlyMonthly limitResets at 00:00:00 on the first day of each month
lifetimeLifetime total (not reset by time)Never resets; permanently rejected once the limit is reached

For example, configuring Strategy = "daily" and MaxCount = 2000 means at most 2000 calls per day. Configuring Strategy = "lifetime" and MaxCount = 10000 means the quota key can be called at most 10000 times over the entire application lifetime, without being reset over time.

Custom Quota Strategies

You can implement the IHttpQuotaStrategy interface to create a strategy with any reset rule (for example, hourly, custom time windows, sliding windows, etc.).

1. Define the strategy class

cs
public sealed class HourlyQuotaStrategy : IHttpQuotaStrategy{    /// <inheritdoc />    public string Name => "hourly"; // Unique name of the strategy    /// <inheritdoc />    public bool TryAcquire(HttpQuotaCounter quotaCounter, int maxCount, out int current)    {        // Use the current UTC hour as the window identifier (format: yyyy-MM-dd HH)        var hourKey = DateTime.UtcNow.ToString("yyyy-MM-dd HH");        // If the window identifier changes, a new hour has begun, so reset the counter        if (quotaCounter.WindowKey != hourKey)        {            quotaCounter.Count = 0;            quotaCounter.WindowKey = hourKey;        }        // Increment the counter        quotaCounter.Count++;        current = quotaCounter.Count;        return current <= maxCount;    }}

2. Register the custom quota strategy

Register the custom quota strategy in the Startup.cs or Program.cs file:

cs
services.AddHttpRemote(builder =>{    builder.AddQuotaStrategy<HourlyQuotaStrategy>();});

After registration, you can use Strategy = "hourly" in QuotaLimits:

cs
options.QuotaLimits = new Dictionary<string, HttpQuotaLimit>{    ["some/high_freq_api"] = new HttpQuotaLimit("hourly", 100)  // At most 100 calls per hour};

Multi-Node Cluster Deployment

By default, the quota manager HttpQuotaManager maintains counters based on an in-memory cache, which is suitable for single-node or single-instance deployments. In a multi-node cluster environment, each node maintains its own independent counting state, causing the overall quota limit to become ineffective (for example, an endpoint with a global limit of 2000 calls/day could be called 2000 times on each node without mutual awareness). To accurately share quotas across all nodes, you can migrate the counter storage to a distributed cache (such as Redis).

Simply implement the IHttpQuotaManager interface, basing the counting and window-checking logic on distributed atomic operations, and then replace the default service:

cs
public class RedisHttpQuotaManager : IHttpQuotaManager{    // Implement the interface methods, based on Redis for atomic increment, window reset, and over-limit checks}

Replace the default implementation during service registration:

cs
services.Replace(ServiceDescriptor.Singleton<IHttpQuotaManager, RedisHttpQuotaManager>());

After replacement, all nodes share the same quota counter, ensuring that the cluster-wide call count always stays within the configured limits. When implementing a custom manager, make sure the window reset and counter increment operations are atomic to avoid exceeding the limit under concurrency.


With the mechanisms above, you can easily configure differentiated call limits for different endpoints, effectively preventing third-party API limits or cost overruns caused by excessive calls.