Quota policy

This pageapplies toApigee andApigee hybrid.

View Apigee Edge documentation.

Aquota is an allotment of requests that an API proxy will accept over a time period, such as minute, hour, day, week, or month. The Quota policy maintains counters that tally the number of requests received by the API proxy. 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.

This policy is anExtensible policy and use of this policy might have cost or utilization implications, depending on your Apigee license. For information on policy types and usage implications, seePolicy types.

When an API proxy reaches its quota limit, Apigee rejects subsequent API calls and returns an error message until the Quota counter automatically resets at the end of the specified time interval, or until the Quota is explicitly reset using theResetQuota policy.

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 month.

With Apigee, each API call can be dynamically weighted. For example, with a Large Language Model (LLM) API, you can enforce a rate limit based on the number of tokens in the request or the response, or both. Also, the quota limits themselves can be dynamic, which means you can enforce more strict quotas when the system is busier, or relax quotas during non-peak hours.

A variation on the Quota policy,SpikeArrest policy, prevents traffic spikes (or bursts) that can be caused by a sudden increase in usage, buggy clients, or malicious attacks.

You can set the same quota for all apps accessing the API proxy, or you can set different quota limits, depending on:

  • The product that contains the API proxy
  • The app requesting the API
  • The app developer
  • The upstream service
  • Many other criteria
  • Combinations of any of the available criteria

Don't use the Quota policy to shield against overall traffic spikes. For that, use theSpikeArrest policy.

Tip: Need help deciding which rate limiting policy to use? SeeComparing Quota and SpikeArrest policies.

Videos

Note: The following videos were recorded with a previous version of the Apigee UI; however, the concepts are still valid.

These videos introduce quota management with the Quota policy:

Intro

Dynamic Quota

Distributed & Synchronous

Message Weight

Calendar

Rolling Window

Flexi

Conditional Quota

Flow Variables

Error Handling

Quota policy types

The Quota policy supports several different ways in which the quota counter starts and resets. You can define which to use with thetype attribute on the<Quota> element, as the following example shows:

<Quotaname="QuotaPolicy"type="calendar">...</Quota>

Valid values oftype include:

  • calendar: Configures a quota based on an explicit start time. The Quota counter for each app is refreshed based on the<StartTime>,<Interval>, and<TimeUnit> values that you set.
  • rollingwindow: Configures a quota that uses a "rolling window" to determine quota usage. Withrollingwindow, you determine the size of the window with the<Interval> and<TimeUnit> elements; for example, 1 day. When a request comes in, Apigee looks at the exact time of the request (say 5:01pm), counts the number of requests that came in between then and 5:01pm the previous day (1 day), and determines whether or not quota has been exceeded during that window.
  • flexi: Configures a quota that causes the counter to begin when the first request message is received from an app, and resets based on the<Interval> and<TimeUnit> values.

The following table describes when the quota resets for each type:

Time UnitType
default (or null)calendarflexi
minuteStart of next minuteOne minute after<StartTime>One minute after first request
hourTop of next hourOne hour after<StartTime>One hour after first request
dayMidnight GMT of the current day24 hours after<StartTime>24 hours after first request
weekMidnight GMT Sunday at the end of the weekOne week after<StartTime>One week after first request
monthMidnight GMT of the last day of the monthOne month (28 days) after<StartTime>One month (28 days) after first request
Note: If you need to limit spike in request traffic using a time interval measured in seconds, we recommend using theSpikeArrest policy instead of the Quota policy.

Fortype="calendar", you must specify the value of<StartTime>.

The table does not describe when the count resets for therollingwindow type. That's because rolling window quotas work a little differently, based on alookback window, such as a one hour or one day. For therollingwindow type, the counter never resets, but is recalculated on each request. When a new request comes in, the policy determines if the quota has been exceeded in the past window of time.

For example, you define a two hour window that allows 1000 requests. A new request comes in at 4:45 PM.The policy calculates the quota count for the past two hour window, meaning the number of requests since 2:45 PM. If the quota limit has not been exceeded in that two-hour window, then the request is allowed.

One minute later, at 4:46 PM, another request comes in. Now the policy calculates the quota count since 2:46 PM to determine if the limit has been exceeded.

Understanding quota counters

When a quota policy executes in an API proxy flow, a quota counter is incremented. When the counter reaches its limit, no further API calls associated with that counter are permitted. Depending on the configuration you use for your API Product, the quota policy may employ a single counter, or multiple independent counters. It's important to understand the scenarios under which multiple counters will be used, and how they behave.

Configuring quota settings for API products

An API product can specify quota settings at theproduct level or at theindividual operation level, or both. If your API proxy is included in an API product, you can configure the Quota policy to use the quota settings (allow count, time unit, and interval) that are defined in that product. The easiest way to do this is via theuseQuotaConfigInAPIProduct element. Alternatively, you can reference these settings in the Quota policy via individual variable references.

How quotas are counted

By default, Apigee maintains a separate quota counter for each operation defined in an API product, and the following rules are observed:

  • If an operation has a quota defined for it, then the operation's quota settings take precedence over the quota settings defined at the product level.
  • If an operation does not have a quota defined for it, then the product-level quota settings apply.
  • If the API product does not include any quota settings — neither at the product nor operation level — quota settings for allow count, time unit, and interval as specified in the Quota policy apply.

In all cases, Apigee maintains a separate quota counter for each operation defined in an API product. Any API calls that match an operation will increment its counter.

Configuring the quota policy to use API product quota settings

To configure your quota policy to use quota settings from an API product that the proxy belongs to:

  1. Create or update an API product and specify thequotaCounterScope attribute asPRODUCT to enforce quota at the API product level, or specifyPROXY to enforce quota at the API proxy level.
  2. For all API proxies in the API product, add aVerifyAPIKey policy or anOAuthv2 policy with a VerifyAccessToken operation in the request flowbefore the Quota policy. These policies identify the API product for each request.Note: If you don't add one of these operations to the request flow, the API proxy quota policy does not know which API product's quota configuration to apply to the request and the API product's quota counter is not updated for API calls.
  3. Configure the Quota policy to use the limits defined in the API Product, withUseQuotaConfigInAPIProduct.

Configuring API proxy-level counters

It is possible to configure an API product to maintain a quota count at the API proxy scope. In this case, the quota configuration specified at the API product level is shared by all operations that do not have their own quota specified. The effect of this configuration is to create a counter at the API proxy level for this API product.

To achieve this configuration, you must use the/apiproducts Apigee APIto create or update the product and set thequotaCounterScope attribute toPROXY in the create or update request. With thePROXY configuration, requests matching any of the operations defined for the API product that are associated with the same proxy, and do not have their own quota settings, will share a common quota counter for that proxy.

In Figure 1, Operation 1 and 2 are associated with Proxy1 and Operation 4 and 5 are associated with Proxy3. BecausequotaCounterScope=PROXY is set in the API product, each of these operations uses the API product-level quota setting. Operation 1 and 2, associated with Proxy1, use a shared counter, and Operation 4 and 5, associated with Proxy3, use a separate shared counter. Operation 3 has its own quota configuration setting, and because of that uses its own counter, irrespective of the value of thequotaCounterScope attribute.

Figure 1: Use of the quotaCounterScope flag

How quotas are counted if no API products are in use

If there is no API product associated with an API proxy, a quota policy maintains a single counter, regardless of how many times you reference it in an API proxy. The name of the quota counter is based on thename attribute of the policy.

For example, you create a Quota policy namedMyQuotaPolicy with a limit of 5 requests and place it on multiple flows (Flow A, B, and C) in the API proxy. Even though it is used in multiple flows, it maintains a single counter that is updated by all instances of the policy:

  • Flow A is executed -> MyQuotaPolicy is executed and its counter = 1
  • Flow B is executed -> MyQuotaPolicy is executed and its counter = 2
  • Flow A is executed -> MyQuotaPolicy is executed and its counter = 3
  • Flow C is executed -> MyQuotaPolicy is executed and its counter = 4
  • Flow A is executed -> MyQuotaPolicy is executed and its counter = 5

The next request to any of the three flows is rejected because the quota counter has reached its limit.

Using the same Quota policy in more than one place in an API proxy flow, which can unintentionally cause Quota to run out faster than you expected, is an anti-pattern described inIntroduction to antipatterns.

Alternatively, you can define multiple Quota policies in your API proxy and use a different policy in each flow. Each Quota policy maintains its own counter, based on thename attribute of the policy.

Creating multiple counters through policy configuration

You can use the<Class> or<Identifier> elements in the Quota policy to define multiple, unique counters in a single policy. By using these elements, a single policy can maintain different counters based on the app making the request, the app developer making the request, a client ID or other client identifier, and more. See the examples above for more information on using the<Class> or<Identifier> elements.

Note: Quota counters are scoped to the API proxy that contains the Quota policy. If multiple API proxies contain Quota policies with the same name, the counters are maintained separately.

Time notation

All Quota times are set to theCoordinated Universal Time (UTC) time zone.

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

Dates are defined as year, month, and day, in the following format:YYYY-MM-DD. For example,2021-02-04 represents February 4, 2021.

Time of day is defined as hours, minutes, and seconds 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:00 and24:00:00, are available to distinguish the two midnights that can be associated with one date. Therefore2021-02-04 24:00:00 is the same date and time as2021-02-05 00:00:00. The latter is usually the preferred notation.

Getting quota settings from the API product configuration

You can set quota limits in API product configurations. Those limits don't automatically enforce quota. Instead, you can reference product quota settings in a quota policy. Here are some advantages of setting a quota on the product for quota policies to reference:

  • Quota policies can use a uniform setting across all API proxies in the API product.
  • You can make runtime changes to the quota setting on an API product, and quota policies that reference the value automatically have updated quota values.

For more information on using quota settings from an API product, see the "Dynamic Quota" example above.

For info on configuring API products with quota limits, seeManaging API products.

Configuring shared quota counters

In the simple case, the Quota policy increments its counter once for each request sent to an API proxy, during initial request processing. In some cases, you may want to check if the quota is exceeded on initial handling of the incoming request, but increment the counter only during response handling. This makes sense when the cost or weight of the API call can be known only after the upstream or target system responds. In the case of an LLM API, the size of the response in tokens might determine the cost. In the case of a BigQuery API, thetotal_slot_ms in the response might determine the cost.

Three Quota policy elements—<SharedName>,<CountOnly>, and<EnforceOnly>—when used together, allow you to customize the Quota policy to enforce the quota on the incoming request, and accrue counts against the quota based on information derived from target responses.

For example, suppose you have an API proxy that uses an LLM as a target, and you wish to enforce a quota of 100,000 tokens per hour. The LLM responses provide atotalTokenCount value. To achieve this, do the following:

  • Attach a Quota policy to the ProxyEndpoint Request flow with the<SharedName> element set with a name value and the<EnforceOnly> element set totrue.
  • To the ProxyEndpoint Response flow, attach an ExtractVariables policy to extract thetotalTokenCount value from the response received from the LLM target.
  • Attach a second Quota policy to the ProxyEndpoint Response flow with the<SharedName> element set to the same name value as the first Quota policy and the<CountOnly> element set totrue. Set the<MessageWeight> element to use the extractedtotalTokenCount value.

For an example showing how to use shared counters, seeShared counters in theSamples section.

Samples

These policy code samples illustrate how to start and end quota periods by:

More Dynamic Quota

<Quota name="CheckQuota">  <Interval ref="verifyapikey.verify-api-key.apiproduct.developer.quota.interval">1</Interval>  <TimeUnit ref="verifyapikey.verify-api-key.apiproduct.developer.quota.timeunit">hour</TimeUnit>  <Allow count="200" countRef="verifyapikey.verify-api-key.apiproduct.developer.quota.limit"/></Quota>

Dynamic quotas enable you to configure a single Quota policy that enforces different quota settings based on information passed to the Quota policy. Another term for Quota settings in this context isservice plan. The dynamic Quota checks the apps' service plan and then enforces those settings.

Note: If you specify both a value and a reference for an element, then reference gets the priority. If reference does not resolve at runtime, then the value is used.

For example, when you create an API product, you can optionally set the allowed quota limit, time unit, and interval. However, setting these value on the API product does not enforce their use in an API proxy. You must also add a Quota policy to the API proxy that reads these values. SeeCreate API products for more.

In the example above, the API proxy containing the Quota policy uses aVerifyAPIKey policy, namedverify-api-key, to validate the API key passed in a request. The Quota policy then accesses the flow variables from the VerifyAPIKey policy to read the quota values set on the API product.

Another option is to set custom attributes on individual developers or apps, and then read those values in the Quota policy. For example, to set different quota values per developer. you set custom attributes on the developer containing the limit, time unit, and interval. You then reference these values in the Quota policy as shown below:

<Quota name="DeveloperQuota">  <Identifier ref="verifyapikey.verify-api-key.client_id"/>  <Interval ref="verifyapikey.verify-api-key.developer.timeInterval"/>  <TimeUnit ref="verifyapikey.verify-api-key.developer.timeUnit"/>  <Allow countRef="verifyapikey.verify-api-key.developer.limit"/></Quota>

This example also uses the VerifyAPIKey flow variables to reference the custom attributes set on the developer.

You can use any variable to set the parameters of the Quota policy. Those variables can come from:

  • Flow variables
  • Properties on the API product, app, or developer
  • A key value map (KVM)
  • A header, query parameter, form parameter, and others

For each API proxy, you can add a Quota policy that either references the same variable as all the other Quota policies in all the other proxies, or the Quota policy can reference variables unique for that policy and proxy.

Start time

<Quotaname="QuotaPolicy"type="calendar"><StartTime>2021-02-1810:30:00</StartTime><Interval>5</Interval><TimeUnit>hour</TimeUnit><Allowcount="99"/></Quota>

For a Quota withtype set tocalendar, you must define an explicit<StartTime> value. The time value is the GMT time, not local time. If you do not provide a<StartTime> value for a policy of typecalendar, Apigee issues an error.

The Quota counter for each app is refreshed based on the<StartTime>,<Interval>, and<TimeUnit> values. For this example, the Quota begins counting at 10:30 am GMT on February 18, 2021, and refreshes every 5 hours. Therefore, the next refresh is at 3:30 pm GMT on February 18, 2021.

Access Counter

<Quota name="QuotaPolicy">  <Interval>5</Interval>  <TimeUnit>hour</TimeUnit>  <Allow count="99"/></Quota>

An API proxy has access to the flow variables set by the Quota policy. You can access these flow variables in the API proxy to perform conditional processing, monitor the policy as it gets close to the quota limit, return the current quota counter to an app, or for other reasons.

Because access the flow variables for the policy is based on the policiesname attribute, for the policy above named<Quota> you access its flow variables in the form:

  • ratelimit.QuotaPolicy.allowed.count: Allowed count.
  • ratelimit.QuotaPolicy.used.count: Current counter value.
  • ratelimit.QuotaPolicy.expiry.time: UTC time when the counter resets.

There are many other flow variables that you can access, as described below.

For example, you can use the followingAssignMessage policy to return the values of Quota flow variables as response headers:

<AssignMessagecontinueOnError="false"enabled="true"name="ReturnQuotaVars"><AssignTocreateNew="false"type="response"/><Set><Headers><Headername="QuotaLimit">{ratelimit.QuotaPolicy.allowed.count}</Header><Headername="QuotaUsed">{ratelimit.QuotaPolicy.used.count}</Header><Headername="QuotaResetUTC">{ratelimit.QuotaPolicy.expiry.time}</Header></Headers></Set><IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables></AssignMessage>

Shared counters

The following example illustrates how to configure a shared counter for an API proxy, where the quota counter is also incremented when the target response is HTTP status200. Because both the Quota policies use the same<SharedName> value, both of the Quota policies will share the same quota counter. For more information, seeConfiguring shared quota counters.

ProxyEndpoint configuration example:

<ProxyEndpoint name="default">  <PreFlow name="PreFlow">    <Request>      <Step>        <Name>Quota-Enforce-Only</Name>      </Step>    </Request>    <Response>      <Step>        <Name>EV-Token-Count</Name>      </Step>      <Step>        <Name>Quota-Count-Only</Name>      </Step>    </Response>    <Response/>  </PreFlow>  <Flows/>  <PostFlow name="PostFlow">    <Request/>    <Response/>  </PostFlow>  <HTTPProxyConnection>    <BasePath>/quota-shared-name</BasePath>  </HTTPProxyConnection>  <RouteRule name="noroute"/></ProxyEndpoint>

First quota policy example:

<Quotaname="Quota-Enforce-Only"type="rollingwindow"><SharedName>common-counter</SharedName><EnforceOnly>true</EnforceOnly><Allowcount="15000"/><Interval>30</Interval><TimeUnit>minute</TimeUnit><Distributed>true</Distributed></Quota>

ExtractVariable policy example:

<ExtractVariablesname='EV-Token-Count'><Source>response</Source><VariablePrefix>extracted</VariablePrefix><JSONPayload><Variablename='tokenCount'><JSONPath>$[1].usageMetadata.totalTokenCount</JSONPath></Variable></JSONPayload></ExtractVariables>

Second Quota policy example:

<Quotaname="Quota-Count-Only"type="rollingwindow"><SharedName>common-counter</SharedName><!--SamenameasthefirstQuotapolicy--><CountOnly>true</CountOnly><Allowcount="15000"/><Interval>30</Interval><TimeUnit>minute</TimeUnit><Distributed>true</Distributed><MessageWeightref="extracted.tokenCount"/></Quota>

First Request

<Quota name="MyQuota">  <Interval>1</Interval>  <TimeUnit>hour</TimeUnit>  <Allow count="10000"/></Quota>

Use this sample code to enforce a quota of 10,000 calls per one hour. The policy resets the quota counter at the top of each hour. If the counter reaches the 10,000-call quota before the end of the hour, calls beyond 10,000 are rejected.

For example, if the counter starts at2021-07-08 07:00:00, then it resets to 0 at2021-07-08 08:00:00 (1 hour from the start time). If the first message is received at2021-07-08 07:35:28 and the message count reaches 10,000 before2021-07-08 08:00:00, calls beyond that count are rejected until the count resets at the top of the hour.

The counter reset time is based on the combination of<Interval> and<TimeUnit>. For example, if you set<Interval> to 12 for a<TimeUnit> of hour, then the counter resets every twelve hours. You can set<TimeUnit> to minute, hour, day, week, or month.

You can reference this policy in multiple places in your API proxy. For example, you could place it on the Proxy PreFlow so it is executed on on every request. Or, you could place it on multiple flows in the API proxy. If you use this policy in multiple places in the proxy, it maintains a single counter that is updated by all instances of the policy.

Alternatively, you can define multiple Quota policies in your API proxy. Each Quota policy maintains its own counter, based on thename attribute of the policy.

Set identifier

<Quotaname="QuotaPolicy"type="calendar"><Identifierref="request.header.clientId"/><StartTime>2021-02-1810:00:00</StartTime><Interval>5</Interval><TimeUnit>hour</TimeUnit><Allowcount="99"/></Quota>

By default, a Quota policy defines a single counter for the API proxy, regardless of the origin of a request. Alternatively, you can use the<Identifier> attribute with a Quota policy to maintain separate counters based on the value of the<Identifier> attribute.

For example, use the<Identifier> tag to define separate counters for every client ID. On a request to your proxy, the client app then passes a header containing theclientID, as shown in the example above.

You can specify any flow variable to the<Identifier> attribute. For example, you could specify that a query param namedid contains the unique identifier:

<Identifier ref="request.queryparam.id"/>

If you use theVerifyAPIKey policy to validate the API key, or the OAuthV2 policies with OAuth tokens, you can use information in the API key or token to define individual counters for the same Quota policy. For example, the following<Identifier> element uses theclient_id flow variable of a VerifyAPIKey policy namedverify-api-key:

<Identifier ref="verifyapikey.verify-api-key.client_id"></Identifier>

Each uniqueclient_id value now defines its own counter in the Quota policy.

Class

<Quota name="QuotaPolicy">  <Interval>1</Interval>  <TimeUnit>day</TimeUnit>  <Allow>    <Class ref="request.header.developer_segment">      <Allow count="10000"/>      <Allow count="1000" />    </Class>  </Allow></Quota>

You can set Quota limits dynamically by using a class-based Quota count. In this example, the quota limit is determined by the value of thedeveloper_segment header passed with each request. That variable can have a value ofplatinum orsilver. If the header has an invalid value, the policy returns a quota violation error.

Note: You cannot use both the<Class> and<Identifier> elements in the same Quota policy.

Note: To access a tutorial featuring a complete functional example proxy that integrates a Quota policy afterVerifyAPIKey policy, refer to the Apigee samples repository.

<Quota> element

Following are attributes and child elements of<Quota>. Note that some element combinations are mutually exclusive or not required. See the samples for specific usage.

Theverifyapikey.my-verify-key-policy.apiproduct.* variables below are available by default when aVerifyAPIKey policy calledmy-verify-key-policy is used to check the app's API key in the request. The variable values come from the quota settings on the API product that the key is associated with, as described inGetting quota settings from the API product configuration.

<QuotacontinueOnError="false"enabled="true"name="Quota-3"type="calendar"><DisplayName>Quota3</DisplayName><Allowcount="UPPER_REQUEST_LIMIT"countRef="verifyapikey.my-verify-key-policy.apiproduct.developer.quota.limit"/><Allow><Classref="request.queryparam.time_variable"><Allowclass="peak_time"count="UPPER_LIMIT_DURING_PEAK"/><Allowclass="off_peak_time"count="UPPER_LIMIT_DURING_OFFPEAK"/></Class></Allow><Intervalref="verifyapikey.my-verify-key-policy.apiproduct.developer.quota.interval">1</Interval><TimeUnitref="verifyapikey.my-verify-key-policy.apiproduct.developer.quota.timeunit">month</TimeUnit><StartTime>2021-7-1612:00:00</StartTime><Distributed>false</Distributed><Synchronous>false</Synchronous><AsynchronousConfiguration><SyncIntervalInSeconds>20</SyncIntervalInSeconds><SyncMessageCount>5</SyncMessageCount></AsynchronousConfiguration><Identifier/><MessageWeight/><UseQuotaConfigInAPIProduct><DefaultConfig><Allow><Classref="request.queryparam.time_variable"><Allowclass="peak_time"count="5000"/><Allowclass="off_peak_time"count="1000"/></Class></Allow><Intervalref="verifyapikey.my-verify-key-policy.apiproduct.developer.quota.interval">1</Interval><TimeUnitref="verifyapikey.my-verify-key-policy.apiproduct.developer.quota.timeunit">month</TimeUnit></DefaultConfig></UseQuotaConfigInAPIProduct></SharedName></CountOnly></EnforceOnly></Quota>

The following attributes are specific to this policy:

AttributeDescriptionDefaultPresence
type

Sets theQuota policy type, which determines when and how the quota counter checks quota usage as well as how it resets.

If you don't settype, the counter begins at the beginning of the minute/hour/day/week/month.

Valid values include:

  • calendar
  • rollingwindow
  • flexi

For a complete description of each type, seeQuota policy types.

N/AOptional

The following table describes attributes that are common to all policy parent elements:

AttributeDescriptionDefaultPresence
name

The internal name of the policy. The value of thename attribute can contain letters, numbers, spaces, hyphens, underscores, and periods. This value cannot exceed 255 characters.

Optionally, use the<DisplayName> element to label the policy in the management UI proxy editor with a different, natural-language name.

N/ARequired
continueOnError

Set tofalse to return an error when a policy fails. This is expected behavior for most policies.

Set totrue to have flow execution continue even after a policy fails. See also:

falseOptional
enabled

Set totrue to enforce the policy.

Set tofalse toturn off the policy. The policy will not be enforced even if it remains attached to a flow.

trueOptional
async

This attribute is deprecated.

falseDeprecated

<DisplayName> element

Use in addition to thename attribute to label the policy in the management UI proxy editor with a different, natural-language name.

<DisplayName>Policy Display Name</DisplayName>
Default

N/A

If you omit this element, the value of the policy'sname attribute is used.

PresenceOptional
TypeString

<Allow>

Specifies the count limit for the quota. If the counter for the policy reaches this limit value, subsequent calls are rejected until the counter resets.

Can also contain a<Class> element that conditionalizes the<Allow> element based on a flow variable.

Default Valuen/a
Required?Optional
TypeInteger or Complex type
Parent Element<Quota>
Child Elements<Class>

Shown below are three ways to set the<Allow> element:

<Allow count="2000"/>
<Allow countRef="verifyapikey.VerifyAPIKey.apiproduct.developer.quota.limit"/>
<Allow count="2000" countRef="verifyapikey.VerifyAPIKey.apiproduct.developer.quota.limit"/>

If you specify bothcount andcountRef, thencountRef gets the priority. IfcountRef does not resolve at runtime, then the value ofcount is used.

You can also specify a<Class> element as a child of<Allow> to determine the allowed count of the policy based on a flow variable. Apigee matches the value of the flow variable to theclass attribute of the<Allow> element, as shown below:

<Allow><Classref="request.queryparam.time_variable"><Allowclass="peak_time"count="5000"/><Allowclass="off_peak_time"count="1000"/></Class></Allow>

The following table lists attributes of<Allow>:

AttributeDescriptionDefaultPresence
count

Use to specify a message count for the quota.

For example, acount attribute value of 100,Interval of 1, and aTimeUnit of month specify a quota of 100 messages per month.

2000Optional
countRef

Use to specify a flow variable containing the message count for a quota.countRef takes precedence over thecount attribute.

noneOptional

<Class>

Lets you conditionalize the value of the<Allow> element based on the value of a flow variable. For each different<Allow> child tag of<Class>, the policy maintains a different counter.

Default Valuen/a
Required?Optional
TypeComplex type
Parent Element<Allow>
Child Elements<Allow> (child of<Class>)

To use the<Class> element, specify a flow variable using theref attribute to the<Class> element. Apigee then uses the value of the flow variable to select one of the<Allow> child elements to determine the allowed count of the policy. Apigee matches the value of the flow variable to theclass attribute of the<Allow> element, as shown below:

<Allow><Classref="request.queryparam.time_variable"><Allowclass="peak_time"count="5000"/><Allowclass="off_peak_time"count="1000"/></Class></Allow>

In this example, the current quota counter is determined by the value of thetime_variable query param passed with each request. That variable can have a value ofpeak_time oroff_peak_time. If the query param contains an invalid value, the policy returns a quota violation error.

Note: You cannot use both the<Class> and<Identifier> elements in the same Quota policy.

The following table lists attributes of<Class>:

AttributeDescriptionDefaultPresence
refUse to specify a flow variable containing the quota class for a quota.noneRequired

<Allow> (child of<Class>)

Specifies the limit for a quota counter defined by the<Class> element. For each different<Allow> child tag of<Class>, the policy maintains a different counter.

Default Valuen/a
Required?Optional
TypeComplex type
Parent Element<Class>
Child Elements None

For example:

<Allow><Classref="request.queryparam.time_variable"><Allowcount="5000"/><Allowcount="1000"/></Class></Allow>

In this example, the Quota policy maintains two quota counters namedpeak_time andoff_peak_time. Which of these is used depends on the query parameter passed in, as shown in<Class> example.

The following table lists attributes of<Allow>:

AttributeDescriptionDefaultPresence
classDefines the name of the quota counter.noneRequired
countSpecifies the quota limit for the counter.noneRequired

<Interval>

Specifies the number of time periods in which quotas are calculated.

Default Valuen/a
Required?Required
TypeInteger
Parent Element<Quota>
Child Elements None

Use to specify an integer (for example, 1, 2, 5, 60, and so on) that will be paired with the<TimeUnit> element you specify (minute, hour, day, week, or month) to determine a time period during which Apigee calculates quota use.

For example, an interval of24 with a<TimeUnit> ofhour means that the quota will be calculated over the course of 24 hours.

<Interval ref="verifyapikey.VerifyAPIKey.apiproduct.developer.quota.interval">1</Interval>

The following table lists attributes of<Interval>:

AttributeDescriptionDefaultPresence
ref

Use to specify a flow variable containing the interval for a quota.ref takes precedence over an explicit interval value. If both reference and value are specified, then reference gets the priority. Ifref does not resolve at runtime, then the value is used.

noneOptional

<TimeUnit>

Specifies the unit of time applicable to the quota.

Default Valuen/a
Required?Required
TypeString
Parent Element<Quota>
Child Elements None

Select fromminute,hour,day,week,month, oryear.

Note: The Quota policy also supportssecond as the time unit. However,second is only supported for non-distributed counters (when<Distributed> is set tofalse). Google recommends that you use theSpikeArrest policy to limit spikes in request traffic at the second level rather than use thesecond value here.

For example, anInterval of24 with aTimeUnit ofhour means that the quota will be calculated over the course of 24 hours.

<TimeUnit ref="verifyapikey.VerifyAPIKey.apiproduct.developer.quota.timeunit">month</TimeUnit>
Default:none
Presence:Required
Type:String

The following table lists attributes of<TimeUnit>:

AttributeDescriptionDefaultPresence
refSpecifies a flow variable containing the time unit for a quota.ref takes precedence over an explicit interval value. Ifref does not resolve at runtime, then the interval value is used.noneOptional

<StartTime>

Whentype is set tocalendar, specifies the date and time when the quota counter begins counting, regardless of whether any requests have been received from any apps.

Default Valuen/a
Required?Optional (Required whentype is set tocalendar)
TypeString inISO 8601 date and time format
Parent Element<Quota>
Child Elements None

Important: If you omit the<StartTime> element from your Quota policy configuration, the quota period will start on the first day of the current month, by default.

For example:

<StartTime>2021-7-16 12:00:00</StartTime>

<Distributed>

Determines whether Apigee uses one or more nodes to process requests.

Default Valuefalse
Required?Optional
TypeBoolean
Parent Element<Quota>
Child Elements None

Set totrue to specify that the policy should maintain a central counter and continuously synchronize it across all nodes. The nodes can be across availability zones and/or regions.

Note: If you have a paid Apigee account, you typically have multiple Message Processors in your installation, and that number can vary based on your traffic load. Evaluation accounts typically have two Message Processors.

If you use the default value offalse, then you might exceed your quota because the count for each node is not shared:

<Distributed>false</Distributed>

To guarantee that the counters are synchronized, and updated on every request, set<Distributed> and<Synchronous> totrue:

<Distributed>true</Distributed><Synchronous>true</Synchronous>

<Synchronous>

Determines whether to update a distributed quota counter synchronously.

Default Valuefalse
Required?Optional
TypeBoolean
Parent Element<Quota>
Child Elements None

Set totrue to update a distributed quota counter synchronously. This means that the updates to the counters are made at the same time the quota is checked on a request to the API. Set totrue if it is essential that you not allow any API calls over the quota.

Note: By implementing synchronous updates to the counter, there is the potential for performance impacts and lower throughputs. In some cases, use of<Synchronous>true</Synchronous> could cause the quota policy to fail to process some transactions.

Set tofalse to update the quota counter asynchronously. This means that it is possible that some API calls exceeding the quota will go through, depending on when the quota counter in the central repository is asynchronously updated. However, you will not face the potential performance impacts associated with synchronous updates.

The default asynchronous update interval is 10 seconds. Use the<AsynchronousConfiguration> element to configure this asynchronous behavior.

<Synchronous>false</Synchronous>

<AsynchronousConfiguration>

Configures the synchronization interval among distributed quota counters when the policy configuration element<Synchronous> is either not present or present and set tofalse. Apigee ignores this element when<Synchronous> is set totrue.

Default Valuen/a
Required?Optional
TypeComplex type
Parent Element<Quota>
Child Elements<SyncIntervalInSeconds>
<SyncMessageCount>

You can specify the synchronization behavior using the<SyncIntervalInSeconds> or<SyncMessageCount> child elements. Use either or both elements. For example,

<AsynchronousConfiguration>   <SyncIntervalInSeconds>20</SyncIntervalInSeconds></AsynchronousConfiguration>

or

<AsynchronousConfiguration>   <SyncIntervalInSeconds>20</SyncIntervalInSeconds>   <SyncMessageCount>5</SyncMessageCount></AsynchronousConfiguration>
  • When only<SyncIntervalInSeconds> is present, the quota synchronizes every N seconds, where N is the value specified in the element, irrespective of how many messages have been handled.
  • When only<SyncMessageCount> is present, the quota synchronizes every M messages, where M is the value specified in the element, or every 10 seconds, whichever comes first.
  • When both elements are present, the quota synchronizes every M messages or every N seconds, whichever comes first.
  • When<AsynchronousConfiguration> is not present or neither child element is present, the quota synchronizes every 10 seconds, irrespective of how many messages have been handled.

<SyncIntervalInSeconds>

Overrides the default behavior in which asynchronous updates are performed after an interval of 10 seconds.

Default Value10 seconds
Required?Optional
TypeInteger
Parent Element<AsynchronousConfiguration>
Child Elements None
<AsynchronousConfiguration>   <SyncIntervalInSeconds>20</SyncIntervalInSeconds></AsynchronousConfiguration>

The sync interval must be >= 10 seconds, as described inLimits.

<SyncMessageCount>

Specifies the number of requests to process before synchronizing the quota counter.

Default Valuen/a
Required?Optional
TypeInteger
Parent Element<AsynchronousConfiguration>
Child Elements None
<AsynchronousConfiguration>   <SyncMessageCount>5</SyncMessageCount></AsynchronousConfiguration>

Using the configuration in this example, on each node, the quota count will synchronize after every 5 requests, or every 10 seconds, whichever comes first.

<Identifier>

Configures the policy to create unique counters based on a flow variable.

Default Valuen/a
Required?Optional
TypeString
Parent Element<Quota>
Child Elements None

Via the Identifier element, you can allot call counts to distinct buckets defined by the value in a flow variable. For example, you can use thedeveloper.id variable, which is populated after aVerifyAPIKey policy, to enforce one quota limit to all instances of all apps created by each specific developer, or you can use theclient_id to enforce a quota limit for each particular app. The configuration for the latter looks like this:

<Identifier ref="client_id"/>

You can refer to either a custom variable that you might set with theAssignMessage policy or theJavaScript policy, or a variable that is implicitly set, such as those set by theVerifyAPIKey policy or theVerifyJWT policy. For more on variables, seeUsing Flow Variables, and for a list of well-known variables defined by Apigee, see theFlow variables reference.

If you don't use this element, the policy allots all call counts into a single counter for the particular Quota policy.

If you refer todeveloper.id ordeveloper.app.id for the quota<Identifier>, or use those variables as one element in a custom variable used as the<Identifier>, be aware that the values of these variables may change, during some future maintenance period. This would be rare, not a regular occurrence. But if it were to occur, and if you had a Quota policy using one of those variables as the<Identifier>, then the quota wouldn't be strictly enforced during the time window in which the change occurred.

This element is also discussed inHow does the Quota policy work when no Identifier is specified?

Note: You cannot use both the<Class> and<Identifier> elements in the same Quota policy.

The following table describes the attributes of<Identifier>:

AttributeDescriptionDefaultPresence
ref

Specifies a flow variable that identifies the counter to use for the request. The variable can refer to an HTTP header, a query parameter, a form parameter, or an element of the message content, or, some other value to identify how to allot call counts.

Theclient_id is commonly used as the variable. Theclient_id is also known as the API key or consumer key, and is generated for an app when it is registered in an organization on Apigee. You can use this identifier if you have enabled API key or OAuth authorization policies for your API.

N/AOptional

<MessageWeight>

Specifies the cost assigned to each message for quota purposes. Use this element to assign different impact to API requests based on their content or the value of the call.

Default Valuen/a
Required?Optional
TypeInteger
Parent Element<Quota>
Child Elements None

For example, when Apigee is managing a Large Language Model (LLM) API, you can use the number of tokens in the request or the response, or both, as the<MessageWeight>.

Or, if you want to countPOST messages as being twice as expensive asGET messages, you would set the<MessageWeight> to 2 for aPOST and 1 for aGET. Suppose the quota is 10 messages per minute and the proxy processes 5POST requests in the first 35 seconds. The proxy will reject any additional request,POST orGET, until the counter resets.

A value representing<MessageWeight> must be specified using a flow variable, and can be extracted from HTTP headers, query parameters, an XML or JSON request payload, or any other flow variable. For example, you can extract the value from a response payload into a variable namedextracted.message_weight, and then use this for<MessageWeight>:

<MessageWeight ref="extracted.message_weight"/>

If the flow variable resolves to 0, the request will not affect the counter.

<UseQuotaConfigInAPIProduct>

Defines quota settings for an API product, such as the time units, interval, and allowed maximum.

Default Valuen/a
Required?Optional
TypeComplex type
Parent Element<Quota>
Child Elements<DefaultConfig>

If you add the<UseQuotaConfigInAPIProduct> element to the Quota policy, then Apigee ignores any<Allow>,<Interval>, and<TimeUnit> child elements of<Quota>.

The<UseQuotaConfigInAPIProduct> element is simply a container for the default settings that you define using the<DefaultConfig> element, as the following example shows:

<UseQuotaConfigInAPIProduct stepName="POLICY_NAME">  <DefaultConfig>...</DefaultConfig></UseQuotaConfigInAPIProduct>

You can use thestepName attribute to reference either aVerifyAPIKey policy or aValidateToken policy operation of theOAuthv2 policy in the flow.

The following table describes the attributes of<UseQuotaConfigInAPIProduct>:

AttributeDescriptionDefaultPresence
stepNameIdentifies the name of the authentication policy in the flow. The target can be either aVerifyAPIKey policy or anOAuthv2 policy.N/ARequired

For more information, see the following:

<DefaultConfig>

Contains default values for an API product's quota. When you define a<DefaultConfig>, all three child elements are required.

Default Valuen/a
Required?Optional
TypeComplex type
Parent Element<UseQuotaConfigInAPIProduct>
Child Elements<Allow>
<Interval>
<TimeUnit>

It's possible to define these values on both the API product's operation (either with the UI or theAPI products API and in the Quota policy. If you do that, however, the settings on the API product take precedence and the settings on the Quota policy are ignored.

The syntax for this element is as follows:

<UseQuotaConfigInAPIProduct stepName="POLICY_NAME"><DefaultConfig>    <Allow>allow_count</Allow>    <Interval>interval</Interval>    <TimeUnit>[minute|hour|day|week|month]</TimeUnit>  </DefaultConfig></UseQuotaConfigInAPIProduct>

The following example specifies a quota of 10,000 every week:

<DefaultConfig>  <Allow>10000</Allow>  <Interval>1</Interval>  <TimeUnit>week</TimeUnit></DefaultConfig>

For more information, see the following:

<SharedName>

Identifies this Quota policy asshared. All Quota policies in an API proxy with the same<SharedName> value share the same underlying quota counter.

For more information and examples,seeConfiguring shared quota counters.

Default Valuen/a
Required?Optional
TypeString
Parent Element<Quota>
Child Elements None

<CountOnly>

Place a Quota policy with this element set totrue in a step in the ProxyEndpoint response flow to increment the underlying quota counter without sending an error back to the client when the quota limit is exceeded. If this element is present, the<SharedName> element must also be present and the<EnforceOnly> element must not be present.

For more information and examples, seeConfiguring shared quota counters.

Default Valuefalse
Required?Optional
TypeBoolean
Parent Element<Quota>
Child Elements None

<EnforceOnly>

Place a Quota policy with this element set totrue in the request flow of an API proxy to enforce a quota without incrementing the quota counter. This configuration allows deferred enforcement of rate limits based on message weights that can be known only in the response flow. If this element is present, the<SharedName> must also be present and the<CountOnly> element must not be present.

For more information and examples, seeConfiguring shared quota counters.

Default Valuefalse
Required?Optional
TypeBoolean
Parent Element<Quota>
Child Elements None

Flow variables

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

VariablesTypePermissionsDescription
ratelimit.{policy_name}.allowed.countLongRead-OnlyReturns the allowed quota count.
ratelimit.{policy_name}.used.countLongRead-OnlyReturns the current quota used within a quota interval.
ratelimit.{policy_name}.available.countLongRead-OnlyReturns the available quota count in the quota interval.
ratelimit.{policy_name}.exceed.countLongRead-OnlyReturns 1 after the quota is exceeded.
ratelimit.{policy_name}.total.exceed.countLongRead-OnlyReturns 1 after the quota is exceeded.
ratelimit.{policy_name}.expiry.timeLongRead-Only

Returns the UTC time (in milliseconds), which determines when the quota expires and when the new quota interval starts.

When the Quota policy's type isrollingwindow, this value is not valid because the quota interval never expires.

ratelimit.{policy_name}.identifierStringRead-OnlyReturns the (client) identifier reference attached to the policy
ratelimit.{policy_name}.classStringRead-OnlyReturns the class associated with the client identifier
ratelimit.{policy_name}.class.allowed.countLongRead-OnlyReturns the allowed quota count defined in the class
ratelimit.{policy_name}.class.used.countLongRead-OnlyReturns the used quota within a class
ratelimit.{policy_name}.class.available.countLongRead-OnlyReturns the available quota count in the class
ratelimit.{policy_name}.class.exceed.countLongRead-OnlyReturns the count of requests that exceeds the limit in the class in the current quota interval
ratelimit.{policy_name}.class.total.exceed.countLongRead-OnlyReturns the total count of requests that exceeds the limit in the class across all quota intervals, so it is the sum ofclass.exceed.count for all quota intervals.
ratelimit.{policy_name}.failedBooleanRead-Only

Indicates whether or not the policy failed (true or false).

Error reference

This section describes the fault codes and error messages that are returned and fault variables that are set by Apigee when this policy triggers an error. This information is important to know if you are developing fault rules to handle faults. To learn more, seeWhat you need to know about policy errors andHandling faults.

Runtime errors

These errors can occur when the policy executes.

Tip: Need help resolving an error? Clickin the Fix column for detailed troubleshooting information.
Fault codeHTTP statusCauseFix
policies.ratelimit.FailedToResolveQuotaIntervalReference500Occurs if the<Interval> element is not defined within theQuota policy. This element is mandatory and used to specify the interval of time applicable to the quota. The time interval can be minutes, hours, days, weeks, or months as defined with the<TimeUnit> element.
policies.ratelimit.FailedToResolveQuotaIntervalTimeUnitReference500Occurs if the<TimeUnit> element is not defined within theQuota policy. This element is mandatory and used to specify the unit of time applicable to the quota. The time interval can be in minutes, hours, days, weeks, or months.
policies.ratelimit.InvalidMessageWeight500Occurs if the value of the<MessageWeight> element specified through a flow variable is invalid (a non-integer value).
policies.ratelimit.QuotaViolation500The quota limit was exceeded.N/A

Deployment errors

Tip: Need help resolving an error? Click in the Fix column for detailed troubleshooting information.
Error nameCauseFix
InvalidQuotaIntervalIf the quota interval specified in the<Interval> element is not an integer, then the deployment of the API proxy fails. For example, if the quota interval specified is 0.1 in the<Interval> element, then the deployment of the API proxy fails.
InvalidQuotaTimeUnitIf the time unit specified in the<TimeUnit> element is unsupported, then the deployment of the API proxy fails. The supported time units areminute,hour,day,week, andmonth.
InvalidQuotaTypeIf the type of the quota specified by thetype attribute in the<Quota> element is invalid, then the deployment of the API proxy fails. The supported quota types aredefault,calendar,flexi, androllingwindow.
InvalidStartTimeIf the format of the time specified in the<StartTime> element is invalid, then the deployment of the API proxy fails. The valid format isyyyy-MM-dd HH:mm:ss, which is theISO 8601 date and time format. For example, if the time specified in the<StartTime> element is7-16-2017 12:00:00 then the deployment of the API proxy fails.
StartTimeNotSupportedIf the<StartTime> element is specified whose quota type is notcalendar type, then the deployment of the API proxy fails. The<StartTime> element is supported only for thecalendar quota type. For example, if thetype attribute is set toflexi orrolling window in the<Quota> element, then the deployment of the API proxy fails.
InvalidSynchronizeIntervalForAsyncConfigurationIf the value specified for the<SyncIntervalInSeconds> element within the<AsynchronousConfiguration> element in aQuota policy is less than zero, then the deployment of the API proxy fails.
InvalidAsynchronizeConfigurationForSynchronousQuotaIf the value of the<AsynchronousConfiguration> element is set totrue in aQuota policy, which also has asynchronous configuration defined using the<AsynchronousConfiguration> element, then the deployment of the API proxy fails.

Fault variables

These variables are set when this policy triggers an error. For more information, seeWhat you need to know about policy errors.

VariablesWhereExample
fault.name="fault_name"fault_name is the name of the fault, as listed in theRuntime errors table above. The fault name is the last part of the fault code.fault.name Matches "QuotaViolation"
ratelimit.policy_name.failedpolicy_name is the user-specified name of the policy that threw the fault.ratelimit.QT-QuotaPolicy.failed = true

Example error response

Note: For error handling, the best practice is to trap theerrorcode part of the error response. Do not rely on the text in thefaultstring, because it could change.
{"fault":{"detail":{"errorcode":"policies.ratelimit.QuotaViolation"},"faultstring":"Rate limit quota violation. Quota limit  exceeded. Identifier : _default"}}

Example fault rule

<FaultRules>    <FaultRule name="Quota Errors">        <Step>            <Name>JavaScript-1</Name>            <Condition>(fault.name Matches "QuotaViolation") </Condition>        </Step>        <Condition>ratelimit.Quota-1.failed=true</Condition>    </FaultRule></FaultRules>
Note: When the rate of incoming requests exceeds the thresholds set by Quota or SpikeArrest policy, the system returns an HTTP status code 429 Too Many Requests.

Schemas

Sample: See ourGitHub repository samples for the most recent schemas.

Related topics

ResetQuota policy

SpikeArrest policy

Comparing Quota and Spike Arrest policies

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2025-12-17 UTC.