Limits and Quotas
To prevent abuse, avoid slowdowns, and ensure that all users use our APIs responsibly, we enforce quota limits. If you make too many requests, you may exceed your quota. In this case, the API returns an error until requests are available again.
We enforce two types of request limits, each applying to a different time window: long-term usage limits and short-term rate limits. A third type of limit depends on your Fatture in Cloud plan, rather than the number of API requests. See Plan Limits for details.
πΒ Long-term usage limitsβ
Long-term usage limits help prevent improper API usage by limiting the number of requests you can make within a given period.
- Public apps: quotas apply to each company-app pair. Two public apps accessing the same company have separate quotas.
- Private apps: quotas apply to the company and are shared by all its private apps, regardless of which private app makes the request. Creating another private app does not increase the available quotas.
This distinction applies to both hourly and monthly quotas.
The quota limits are as follows:
| API limit type | Limit |
|---|---|
| Requests per hour | 1,000 requests per hour per company-app pair for public apps |
| Requests per hour | 1,000 requests per hour per company, shared by all private apps |
| Requests per month | 40,000 requests per month per company-app pair for public apps |
| Requests per month | 40,000 requests per month per company, shared by all private apps |
Long-term limits use fixed time windows: these quotas are reset at the beginning of a new hour or month.
If a limit is exceeded, the API returns a 403 Forbidden HTTP status code. The response also includes a Retry-After header indicating how many seconds to wait before retrying the request.
β±Β Short-term rate limitsβ
Short-term rate limits help prevent usage spikes that could affect system availability by limiting the number of requests applications can send within a short time interval.
All apps and users accessing the same company share and consume the same short-term quota.
The quota limit is as follows:
| API limit type | Limit |
|---|---|
| Requests every 5 minutes | 300 requests every 5 minutes |
Short-term rate limits use a sliding-window algorithm. See the additional resources below for more information.
If the limit is exceeded, the API returns a 429 Too Many Requests HTTP status code. The response also includes a Retry-After header indicating how many seconds to wait before retrying the request.
πΒ Check your current usageβ
You can check your current usage against the long-term usage limits using the following methods.
πΒ HTTP Headers and response codesβ
Every API response includes HTTP headers with information about your long-term usage limits.
| Header | Description |
|---|---|
| RateLimit-HourlyRemaining | The number of requests remaining for the current hour. |
| RateLimit-HourlyLimit | The maximum number of requests you are permitted to make per hour. |
| RateLimit-MonthlyRemaining | The number of requests remaining for the current month. |
| RateLimit-MonthlyLimit | The maximum number of requests you are permitted to make per month. |
Here is an example of an HTTP response:
HTTP/1.1 200 OK
Date: Tue, 05 May 2020 17:27:06 GMT
Status: 200 OK
RateLimit-HourlyRemaining: 840
RateLimit-HourlyLimit: 1000
RateLimit-MonthlyRemaining: 1430
RateLimit-MonthlyLimit: 20000
When a limit is exceeded, the API returns the corresponding HTTP status code and a Retry-After header specifying how many seconds to wait before making further requests.
Here is an example of an API response when the short-term rate limit is exceeded:
HTTP/1.1 429 Too Many Requests
Date: Tue, 05 May 2020 18:00:00 GMT
Status: 429 Too Many Requests
Retry-After: 3600
π»Β From the Fatture in Cloud web appβ
-
Log in to Fatture in Cloud.
-
Access the Settings -> Connected Applications (Impostazioni -> Applicazioni collegate) page.
-
Select the app you want to check. Its API status (Stato attuale delle API) shows whether the APIs are active (ATTIVO):

If the status shows DISATTIVO (inactive), the limits have been reached and the APIs are deactivated:

-
Click View details (Vedi dettagli) next to the API status to open the Quotas and request limits (Quote e limiti di richiesta) dialog. It shows two counters side by side: Hourly requests for the current hour and Monthly requests for the current month.

Each counter shows:
- Above the bar: the requests used out of the limit, for example 990 / 1000.
- Below the bar: the requests still available.
- The bar: the proportion of the quota already used. Its colour is blue when plenty of requests remain, orange when only a few remain, and red when none remain.
If the APIs are deactivated, the dialog shows red bars with no requests left:

When no requests are left, the remaining count shows 0, and requests over a long-term limit are rejected with a 403 Forbidden response (see long-term usage limits).
As explained above, private app quotas apply to the company. Every private app belonging to the same company therefore shows the same counters.
βΒ Using the APIβ
The Get Api Usage method returns the current usage for the company-app pair making the request.
Every call to Get Api Usage consumes one API request from your quotas, just like any other API call. The returned usage already includes this request.
For this reason, we do not recommend using this method for routine quota monitoring, especially before each API call. Instead, read the HTTP headers included in the responses to your regular API requests: they provide quota information without requiring an additional request. Reserve Get Api Usage for occasional checks when you need the detailed usage data.
Here is how to call it:
GET https://api-v2.fattureincloud.it/c/{company_id}/info/api_usage
Authorization: Bearer YOUR_ACCESS_TOKEN
Here is an example response:
{
"data": {
"app_id": 123,
"hourly": {
"default_limit": 1000,
"limit": 1000,
"custom_limit": null,
"usage": 160,
"remaining": 840,
"date": "2026-10-13 15:00:00"
},
"monthly": {
"default_limit": 40000,
"limit": 40000,
"custom_limit": null,
"usage": 12570,
"remaining": 27430,
"date": "2026-10-01"
}
}
}
| Field | Description |
|---|---|
app_id | The ID of the app the quotas apply to; it is null for private apps, since they share quotas. |
default_limit | The standard limit of the window. |
limit | The limit applied to the window: the custom limit if one was granted, the default limit otherwise. |
custom_limit | The custom limit granted for the window, null if no custom limit is set. |
usage | The number of requests already consumed in the current window. |
remaining | The number of requests still available in the current window. |
date | The start of the current window: the current hour for hourly, the current month for monthly. |
πΒ Is it still not enough?β
Our default quotas are designed to meet the needs of most use cases. However, some use cases may require a higher quota.
If you need a higher quota, you can request an increase from our team. Approval is not automatic: you must explain your use case in detail and demonstrate why the default quotas are insufficient.
We can only increase long-term usage limits.
If you receive a 429 Too Many Requests response, your requests are exceeding the short-term rate limit. You need to adjust how your integration sends requests. Requests to increase this limit will be rejected. Instead, read the next section for guidance on handling rate limits.
πββοΈΒ Keep calm and deal with quotas!β
If you exceed the short-term rate limit, the API returns a 429 Too Many Requests response. This is not a fatal error: wait before retrying the request. If requests continue to arrive too quickly, the API will keep rejecting them.
To handle this, gradually increase the delay between retries. This is commonly done using exponential backoff.
The following examples show how to add exponential backoff to your code:
- C#
- Go
- Java
- JavaScript
- PHP
- Python
- Ruby
- TypeScript
// We apply exponential backoff to our C# SDK
// https://github.com/fattureincloud/fattureincloud-csharp-sdk/
// We suppose to use the http://www.thepollyproject.org
// and the https://github.com/Polly-Contrib/Polly.Contrib.WaitAndRetry libraries
// to implement the exponential back-off
// to install them using the .Net cli:
// dotnet add package Polly
// dotnet add package Polly.Contrib.WaitAndRetry
using System;
using Polly;
using It.FattureInCloud.Sdk.Api;
using It.FattureInCloud.Sdk.Model;
using It.FattureInCloud.Sdk.Client;
using Polly.Contrib.WaitAndRetry;
namespace Backoff
{
class Program
{
static void Main(string[] args)
{
Configuration config = new Configuration();
config.AccessToken = "YOUR_ACCESS_TOKEN";
var apiInstance = new ProductsApi(config);
var companyId = 11;
var maxRetryAttempts = 5;
var pauseBetweenFailures = Backoff.ExponentialBackoff(TimeSpan.FromSeconds(2), retryCount: maxRetryAttempts);
var retryPolicy = Policy
.Handle<ApiException>()
.WaitAndRetry(pauseBetweenFailures);
retryPolicy.Execute(() =>
{
ListProductsResponse result = apiInstance.ListProducts(companyId);
Console.Write("\n successful");
Console.Write(result);
});
}
}
}
// We apply exponential backoff to our Go SDK
// https://github.com/fattureincloud/fattureincloud-go-sdk/
// We suppose to use the https://pkg.go.dev/github.com/cenkalti/backoff/v4 library
// to implement the exponential back-off
// to install it:
// go get github.com/cenkalti/backoff/v4
package main
import (
"context"
"encoding/json"
"fmt"
"os"
backoff "github.com/cenkalti/backoff/v4"
fattureincloudapi "github.com/fattureincloud/fattureincloud-go-sdk/v2/api"
)
var (
companyId = int32(2)
auth = context.WithValue(context.Background(), fattureincloudapi.ContextAccessToken, "YOUR_ACCESS_TOKEN")
configuration = fattureincloudapi.NewConfiguration()
apiClient = fattureincloudapi.NewAPIClient(configuration)
)
func main() {
operation := func() error {
resp, _, err := apiClient.ProductsAPI.ListProducts(auth, companyId).Execute()
if resp != nil {
json.NewEncoder(os.Stdout).Encode(resp)
} else {
fmt.Println(err)
}
return err
}
err := backoff.Retry(operation, backoff.NewExponentialBackOff())
if err != nil {
fmt.Fprintf(os.Stderr, "Error %v\n", err)
return
}
}
// We apply exponential backoff to our Java SDK
// https://github.com/fattureincloud/fattureincloud-java-sdk/
// We suppose to use the https://resilience4j.readme.io library to implement the exponential back-off
// to install it see: https://search.maven.org/artifact/io.github.resilience4j/resilience4j-retry/1.7.1/jar
import io.github.resilience4j.core.IntervalFunction;
import io.github.resilience4j.retry.Retry;
import io.github.resilience4j.retry.RetryConfig;
import io.github.resilience4j.retry.RetryRegistry;
import io.vavr.CheckedFunction0;
import it.fattureincloud.sdk.ApiClient;
import it.fattureincloud.sdk.ApiException;
import it.fattureincloud.sdk.Configuration;
import it.fattureincloud.sdk.api.ProductsApi;
import it.fattureincloud.sdk.auth.OAuth;
import it.fattureincloud.sdk.model.ListProductsResponse;
public class Application {
public static void main(String[] args) throws Throwable {
ApiClient defaultClient = Configuration.getDefaultApiClient();
OAuth OAuth2AuthenticationCodeFlow = (OAuth) defaultClient.getAuthentication("OAuth2AuthenticationCodeFlow");
OAuth2AuthenticationCodeFlow.setAccessToken("ACCESS_TOKEN");
RetryConfig config = RetryConfig.custom()
.maxAttempts(10)
.retryExceptions(ApiException.class)
.intervalFunction(IntervalFunction.ofExponentialBackoff(1000, 2))
.build();
RetryRegistry registry = RetryRegistry.of(config);
Retry retry = registry.retry("listProducts", config);
Retry.EventPublisher publisher = retry.getEventPublisher();
publisher.onRetry(event -> System.out.println(event.toString()));
ProductsApi apiInstance = new ProductsApi(defaultClient);
CheckedFunction0<ListProductsResponse> retryingListSuppliers =
Retry.decorateCheckedSupplier(retry,
() -> apiInstance.listProducts(2, null, null, null, null, null));
System.out.println(retryingListSuppliers.apply().getData());
}
}
// We apply exponential backoff to our JavaScript SDK
// https://github.com/fattureincloud/fattureincloud-js-sdk/
let defaultClient = fattureInCloudSdk.ApiClient.instance;
let OAuth2AuthenticationCodeFlow =
defaultClient.authentications["OAuth2AuthenticationCodeFlow"];
OAuth2AuthenticationCodeFlow.accessToken = "YOUR_ACCESS_TOKEN";
let productsApiInstance = new fattureInCloudSdk.ProductsApi();
var companyId = 16;
var opts = {};
const delay = (retryCount) =>
new Promise((resolve) => setTimeout(resolve, 2 ** retryCount * 1000));
const getProd = async (retryCount = 0, lastError = null) => {
if (retryCount > 20) throw new Error(lastError);
try {
return await productsApiInstance.listProducts(companyId, opts);
} catch (e) {
await delay(retryCount);
return getProd(retryCount + 1, e);
}
};
console.log(await getProd());
// We apply exponential backoff to our PHP SDK
// https://github.com/fattureincloud/fattureincloud-php-sdk/
// We suppose to use the https://github.com/stechstudio/backoff library
// to implement the exponential back-off
// to install: composer require stechstudio/backoff
$backoff = new Backoff(10, 'exponential', 10000, true);
$accessToken = "YOUR_ACCESS_TOKEN";
$config = Configuration::getDefaultConfiguration()->setAccessToken($accessToken);
$service = new UserApi(new Client(), $config);
$result = $backoff->run(function() {
return $this->service->listUserCompanies();
});
return $result; // it contains the result of the closure
# We apply exponential backoff to our Python SDK
# https://github.com/fattureincloud/fattureincloud-python-sdk/
# We suppose to use the https://github.com/litl/backoff library to implement the exponential back-off
# to install: pip install backoff
import fattureincloud_python_sdk
from fattureincloud_python_sdk.api import products_api
from fattureincloud_python_sdk.exceptions import ApiException
import backoff
import collections
collections.Callable = collections.abc.Callable # needed if you are using python > 3.10
@backoff.on_exception(backoff.expo, ApiException, max_tries=10)
def get_products(configuration, company_id):
with fattureincloud_python_sdk.ApiClient(configuration) as api_client:
products_api_instance = products_api.ProductsApi(api_client)
products_api_instance.list_products(company_id)
return
configuration = fattureincloud_python_sdk.Configuration()
configuration.access_token = "YOUR_ACCESS_TOKEN"
configuration.retries = 0 # needed to implement custom backoff
company_id = 11
get_products(configuration, company_id)
# We apply exponential backoff to our Ruby SDK
# https://github.com/fattureincloud/fattureincloud-ruby-sdk/
require 'fattureincloud_ruby_sdk'
FattureInCloud_Ruby_Sdk.configure do |config|
# Configure OAuth2 access token for authorization: OAuth2AuthenticationCodeFlow
config.access_token = "YOUR_TOKEN"
end
suppliers_api_instance = FattureInCloud_Ruby_Sdk::SuppliersApi.new
retries = 0
max_retries = 20
company_id = 2
begin
company_suppliers = suppliers_api_instance.list_suppliers(company_id)
puts company_suppliers
rescue FattureInCloud_Ruby_Sdk::ApiError => e
if retries <= max_retries
retries += 1
sleep 2 ** retries
retry
else
raise "Giving up on the server after #{retries} retries. Got error: #{e.message}"
end
end
// We apply exponential backoff to our TypeScript SDK
// https://github.com/fattureincloud/fattureincloud-ts-sdk/
import {
Configuration,
ProductsApi,
} from "@fattureincloud/fattureincloud-ts-sdk";
const apiConfig = new Configuration({
accessToken: "YOUR_ACCESS_TOKEN",
});
let productsApiInstance = new ProductsApi(apiConfig);
var companyId = 2;
var opts = {};
const delay = (retryCount: number) =>
new Promise((resolve) => setTimeout(resolve, 2 ** retryCount * 1000));
const getProd: any = async (retryCount = 0, lastError?: string) => {
if (retryCount > 20) throw new Error(lastError);
try {
return await productsApiInstance.listProducts(companyId);
} catch (e: any) {
await delay(retryCount);
return getProd(++retryCount, e.message);
}
};
console.log(await getProd());
You can set your access token in the dedicated section. See the authentication documentation for more information.
You can also use the Retry-After header to determine how long to wait before retrying a request.
βοΈΒ Plan Limitsβ
Our APIs also enforce limits based on the Fatture in Cloud plan associated with your company. Each plan limits the number of resources you can create. The API returns an error if an operation would exceed one of these limits. See Plan Management for more information.
πΒ Additional Resourcesβ
- Rate limiting using the Fixed Window algorithm
- Rate limiting using the Sliding Window algorithm
- Exponential Backoff
- Exponential Backoff And Jitter
- Better Retries with Exponential Backoff and Jitter for Java
- Retry-After Header
- 403 Forbidden
- 429 Too Many Requests
- Windowing examples in the Apache Beam documentation
- Retry with resilience4j