Was this helpful?

A Quota is an allotment of request messages that an app is allowed to submit to an API over the course of an hour, a day, a week, or a month. To support Quota enforcement, Apigee Edge maintains counters that tally the number of requests received from individual apps. This capability enables API providers to enforce limits on the number of API calls made by apps over an interval of time. Using Quota policies you can, for example, limit apps to 1 request per minute, or to 10,000 requests per month.

When an app reaches its Quota limit, subsequent API calls are rejected; Apigee Edge returns an error message for every request that exceeds the Quota. The Quota policy provides the ability to reset Quotas on-the-fly, after an app has exceeded its limit.

For example, if a Quota is defined as 10,000 messages per month, rate-limiting begins after the 10,000th message. It doesn't matter whether 10,000 messages were counted on the first day or the last day of that period; the app is blocked from making additional requests until the Quota counter automatically resets at the end of the specified time interval, or until the Quota is explicitly reset using Reset quota counter using ResetQuota.

A variation on Quota called SpikeArrest prevents traffic spikes (or bursts) that can be caused by a sudden increase in usage, buggy clients, or malicious attacks. For more information on SpikeArrest, see Shield APIs using SpikeArrest.

The name attribute for this policy is restricted to these characters: A-Z0-9._\-$ %. However, the Management UI enforces additional restrictions, such as automatically removing characters that are not alphanumeric.

Quota types

Three types of Quota are supported. You define the Quota type as an attribute of the Quota policy. For example:

<Quota name="MyQuota" type="calendar">

The following Quota types are supported:

  • calendar: In the calendar Quota, you define an explicit start time. The Quota counter for each app is refreshed based on the Interval and TimeUnit that you set.

    For example, the following Quota of type calendar begins counting at 10 am on February 18, 2014, and will refresh every 5 hours.

    <Quota name="QuotaPolicy" type="calendar">
      <Identifier ref="request.header.clientId"/> 
      <StartTime>2014-02-18 10:00:00</StartTime>
      <Interval>5</Interval>
      <TimeUnit>hour</TimeUnit>
      <Allow count="99"/>
      <MessageWeight ref="request.header.weight"/>
      <Distributed>true</Distributed>
      <Synchronous>true</Synchronous>
    </Quota>
  • rollingwindow: A "rolling window" counter advances by the time interval that you specify. You don't specify a StartTime; instead, the StartTime for the counter is the time when the first message is received from the client plus the interval that you define. A counter is kept for each client ID (consumer key). Thus, the counter will reset to zero when the Interval you define has passed. This enables you to configure a Quota in which an app is indefinitely allowed 1000 requests every 24 hours.
  • flexi: Flexible Quota enforcement causes the counter to begin when the first request message is received from an app. Under flexible Quota enforcement, StartTime is dynamic; every app has its own StartTime based on the the time when the first request is received. This enables you to provide Quotas that support one week, one month, or 6 months access to your API, customized for each app.
  • Default: A Quota policy that does not explicitly define a type is a default Quota configuration. In the default configuration, quota enforcement type is calendar without a StartTime configured. The following is an example of a default Quota policy. 
    <Quota name="MyQuota">
      <Identifier ref="request.header.clientId"/> 
      <Interval>1</Interval>
      <TimeUnit>hour</TimeUnit>
      <Allow count="10000"/>
    </Quota>

    When you use a default, Quota enforcement takes place based on calendar time intervals--always based on the timestamp when the first request message is received by the API proxy. In the above example, imagine that the first message is received at 2013-07-08 07:35:28. The StartTime for the Quota count will be 2013-07-08 07:00:00 and the EndTime will be 2013-07-08 08:00:00 (1 hour from the StartTime). The StartTime will always be the calendar or clock StartTime of the corresponding interval, such as hour, day, week, or month.

Identifying apps

Quotas are counted for individual apps. For this to work, each app requires a unique identifier that it presents with each request. The identifier can be customized. It can be any HTTP header, query parameter, form parameter, or message content that is unique to each consumer app.

You specify the token that will identify each app by defining a reference to a variable in the Identifier element. The Identifier most commonly used to uniquely identify apps is the client_id. The client_id is another name for the API key, or consumer key, that is generated for an app when it is registered in an organization on Apigee Edge. You can use this identifier if you have enabled API key or OAuth authorization policies for your API.

<Identifier ref="request.header.client_id"/>

In some circumstances, Quota settings must be retrieved where no client_id is available, such as when no security policy is in place. In those situations, you can use the AccessEntity policy type to retrieve the appropriate API product settings. For more information, see Retrieve API product settings using GetAPIProduct.

Dynamic Quota settings

Quota settings can be static or dynamic. The following examples demonstrate static and dynamic Quota configurations.

Sample static Quota configuration:

In a simple, static Quota, you set a count, a time interval, and a time unit. The following static Quota configuration limits requesting apps to 10,000 requests per month:

<Quota name="QuotaPolicy">
    <Allow count="10000"/>
    <Interval>1</Interval>
    <TimeUnit>month</TimeUnit>
</Quota>

In the example above the count is 10,000 client requests, over the course of 1 month.

API product-based dynamic Quota configuration:

Dynamic Quota configurations are more useful than static Quotas. Dynamic Quotas enable you to configure a single Quota policy that enforces different Quota settings for different apps, based on the identity of the requesting app. (Another term for Quota settings in this context is "Service Plan". The dynamic Quota checks the apps' "Service Plan" and then enforces those settings.)

Dynamic Quota settings are populated at runtime by resolving an app identifier to an API product. The Identifier can be a field in the request that is unique to each app. For API proxies where OAuth is enforced, you can use client_id as the Identifier, as demonstrated in the sample policy below.

<Quota name="CheckQuota"> 
  <Interval ref="apiproduct.developer.quota.interval"/>
  <TimeUnit ref="apiproduct.developer.quota.timeunit"/>
  <Allow countRef="apiproduct.developer.quota.limit"/>
  <Identifier ref="client_id"/>
</Quota>

If an API Key is used to validate an inbound request, then, assuming that the policy is named "VerifyApiKey", then the dynamic Quota policy should be configured as follows:

<Quota name="ratelimiting.developer.quotas"> 
  <Identifier ref="request.queryparam.apikey" /> 
  <Interval ref="verifyapikey.VerifyApiKey.apiproduct.developer.quota.interval" /> 
  <TimeUnit ref="verifyapikey.VerifyApiKey.apiproduct.developer.quota.timeunit" /> 
  <Allow countRef="verifyapikey.VerifyApiKey.apiproduct.developer.quota.limit" /> 
</Quota>

The example above uses the variable client_id to identify the requesting app. This works as long as the request message contains a client_id (associated with an OAuth-enabled request).

Note that the value for verifyapikey.VerifyApiKey will vary based on the name of the OAuthV2 policy of type VerifyApiKey that is used to check the API key. If your policy is called, for example, KeyValidationPolicy, then the variable name will be verifyapikey.KeyValidationPolicy.

Class-based dynamic Quota

You can also set Quota limits dynamically by using a class-based Quota count. In the example below, a quota class i created from a custom attribute in the access token profile. (To make this work, you would need to add a custom attribute called developer_segment to your access token profiles.) If the value of the attribute developer_segment is platinum, the app presenting the access token is permitted 10000 requests per day, while silver is permitted 1000 requests per day.)

<Quota name="QuotaPolicy">
  <Interval>1</Interval>
  <TimeUnit>day</TimeUnit>
  <Allow count="100">
    <Class ref="accesstoken.developer_segment">
      <Allow class="platinum" count="10000"/>
      <Allow class="silver" count="1000" />
    </Class>
  </Allow>
</Quota>

Time notation

All Quotas are set to the Coordinated Universal Time (UTC) time zone.

Quota time notation follows the international standard date notation defined in International Standard ISO 8601.

Dates are defined as year, month, and day, in the following format: YYYY-MM-DD.

For example, 2013-02-04 represents February 4, 2013.

Time of day is defined as hours, minutes, and second, in the following format: hours:minutes:seconds.

For example, 23:59:59 represents the time one second before midnight.

Note that two notations, 00:00 and 24:00, are available to distinguish the two midnights that can be associated with one date. Therefore:

2013-02-04 24:00:00 is the same date and time as 2013-02-05 00:00:00

00:00 is usually the preferred notation.

Configuring a Quota policy

Configure Quota policy using the following elements.

XML Field Name Description
StartTime (Optional)
Use only for Quota policies of type calendar. Indicates the ISO 8601 date and time when the Quota counter begins counting (regardless of whether or not any requests have been received from any apps.)
Valid value: ISO 8601 formatted date and time, for example 2013-02-05 00:00:00.
Interval (Required)
Specifies the interval of time (in hours, minutes, or days as defined by TimeUnit) applicable to the Quota. For example, a value of 24 for the Interval with a TimeUnit of hours means that the Quota is calculated over one day (24 hours).
Valid value: integer
TimeUnit (Required)

Valid values: second, minute, hour, day, or month

Note: Distributed Quota does not support seconds for the TimeUnit.

Allow count (Required)
Specifies a message count for the quota.
For example, a value of 100 for the Allow count with a duration of 1 month means that the quota is set to be 100 messages per month.
Valid value: integer
Note: If a count reference is specified, it takes precedence over the Allow count value.
For example, the element <Allow count="2000" countRef="request.header.allowed_quota"/> has a count header (countRef="request.header.allowed_quota") along with the count value of 2000.
Identifier (Optional) Variable used for uniquely identifying the client app.
MessageWeight (Optional)
Specifies the weighting defined for each message.
Message weight is used to increase impact of request messages that, for example, consume more computational resources than others. For example, you may want calculate POST messages as being twice as expensive as GET messages. A value representing MessageWeight can be extracted from HTTP headers, query parameters, or an XML or JSON request payload. For example, if the Quota is 10 messages per minute and the MessageWeight for POST requests is 2, then only 5 POST requests are permitted in any 10 minute interval. The Quota is violated (that is, messages rejected) starting with the sixth message.
Distributed
When set to true, a central counter is maintained that is continuously updated by all Apigee Edge management servers. For example, if the limit is 10 messages/hour and number of servers assigned is 2, then the Quota count total is maintained for both servers. Note: This setting does not apply to Apigee Edge free trial accounts, since all Quota counts in the Cloud are, by default, distributed.
Valid values: true or false
PreciseAtSecondsLevel
The default precision for Quotas intervals is one minute. When set to true, Quota precision is set to record at intervals of one second. Use this setting when you have a Quota that uses minutes as the TimeUnit, and you need to ensure that Quotas are counted and enforced by seconds.
Valid values: true or false
Synchronous
This setting determines how the distributed Quota counter is updated. If set to true, the quota counter is updated in the central repository synchronously. This means that the update is made at the same time the API call is quota-checked. When synchronous is set to true, you are guaranteed that no API calls over the quota will be allowed.
 
If set to false, the quota counter is updated asynchronously, and it is possible that some API calls will go through over the quota, depending on when the repository was asynchronously updated. The default asynchronous update interval is 10 seconds. Use AsynchronousConfiguration field, described below, to configure the asynchronous behavior. 

The primary reason to choose asynchronous updating (false) is that it is slightly less efficient to enforce synchronous updates. If you can accept the potential performance impact, or expect lower throughput, so that performance will not be an issue, you may wish to set synchronous to be true. If it is essential to avoid going over the quota, then set this field to true
Valid values: true or false (default)
AsynchronousConfiguration (Optional)
This configuration element is only required when Synchronous is set to false. This element enables you to configure the synchronization interval among distributed Quota counters. The default asynchronous update interval is 10 seconds. You can modify this by adding the child element SyncIntervalInSeconds. For example:
<Synchronous>false</Synchronous>
<AsynchronousConfiguration>
  <SyncIntervalInSeconds>20</SyncIntervalInSeconds>
</AsynchronousConfiguration>

Alternatively, you can use the SyncMessageCount option instead, but you cannot use both. SyncMessageCount specifies the number of requests across all Apigee message processors between quota updates. The following example specifies that the quota count is updated every 5 requests across all Apigee message processors:

<Synchronous>false</Synchronous>
<AsynchronousConfiguration>
   <SyncMessageCount>5</SyncMessageCount>
</AsynchronousConfiguration>

Policy-specific variables

The following predefined Flow variables are automatically populated when a Quota policy executes. For more information about Flow variables, see Variables reference.

Variables Type Permissions Description
ratelimit.{policy_name}.allowed.count Long Read-Only Returns the allowed quota count
ratelimit.{policy_name}.used.count Long Read-Only Returns the current quota used within a quota interval
ratelimit.{policy_name}.available.count Long Read-Only Returns the available quota count in the counter
ratelimit.{policy_name}.exceed.count Long Read-Only Returns the count that exceeds the limit in the current counter
ratelimit.{policy_name}.total.exceed.count Long Read-Only Returns the total count that exceeds the limit, because the quota policy is attached
ratelimit.{policy_name}.expiry.time Long Read-Only Returns the time in milliseconds, which determines when the quota expires and new quota counter starts
ratelimit.{policy_name}.identifier String Read-Only Returns the (client) identifier reference attached to the policy
ratelimit.{policy_name}.class String Read-Only Returns the class associated with the client identifier
ratelimit.{policy_name}.class.allowed.count Long Read-Only Returns the allowed quota count defined in the class
ratelimit.{policy_name}.class.used.count Long Read-Only Returns the used quota within a class
ratelimit.{policy_name}.class.available.count Long Read-Only Returns the available quota count in the class
ratelimit.{policy_name}.class.exceed.count Long Read-Only Returns the count that exceeds the limit in the class
ratelimit.{policy_name}.class.total.exceed.count Long Read-Only Returns the total count that exceeds the limit in the class, because the Quota policy is attached

Policy-specific error codes

The default format for error codes returned by Policies is:

{
  "code" : " {ErrorCode} ",
  "message" : " {Error message} ",
  "contexts" : [ ]
}
Error Code Message
QuotaViolation Rate limit quota violation. Quota limit : {0} exceeded by {1}. Total violation count : {2}. {3}
InvalidMessageWeight Invalid message weight value {0}
ErrorLoadingProperties Error loading rate limit properties from {0}
FailedToResolveQuotaIntervalReference Failed to resolve quota interval reference {0} in quota policy {1}
InvalidQuotaInterval Invalid quota interval {0} in quota policy {1}
FailedToResolveQuotaIntervalTimeUnitReference Failed to resolve quota time unit reference {0} in quota policy {1}
InvalidQuotaTimeUnit Invalid quota time unit {0} in quota policy {1}
InvalidTimeUnitForDistributedQuota Invalid timeunit {0} for distributed quota
InvalidSynchronizeIntervalForAsyncConfiguration 'SyncIntervalInSeconds' should be a value greater than zero
InvalidSynchronizeMessageCountForAsyncConfiguration 'SyncMessageCount' should be a value greater than zero
InvalidAsynchronizeConfigurationForSynchronousQuota AsynchronousConfiguration is not valid for synchronous quota
InvalidQuotaType Invalid Quotatype:{0};Valid Types are calendar,rollingwindow,flexi
InvalidStartTime Invalid Starttime:{0}; Start Time should be of the format 'yyyy-MM-dd HH:mm:ss
StartTimeNotSupported Starttime is not supported for quotatype {0}. Starttime is supported only for 'calendar' based type

Policy schema

Each policy type is defined by an XML schema (.xsd). For reference, policy schemas are available on GitHub.

Help or comments?

  • Something's not working: See Apigee Support
  • Something's wrong with the docs: Click Send Feedback in the lower right.
    (Incorrect? Unclear? Broken link? Typo?)