> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hub2.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Rate limits

> Those are the limits applied on our API.

export const method_0 = "Method"

export const route_0 = "Route"

export const limit_0 = "Actual limit"

export const rationalized_0 = "Rationalized limit"

export const notes_0 = "Notes"

<Note>
  This documentation was last updated on **23-11-21**.
</Note>

## Introduction

As the HUB2 API is their main project, a solid quality of service is required.

In order to keep an appropriate latency and a reliable service, rate limits must be enforced on the most cost-heavy endpoints.

This limit is applied per IP address, so it is relative to each of the API users and the usage of one won't impact the usage of the other.

That is why we enforce those limits.

## API limits

Here is a table of rate limits. The global limit is for all other endpoints.

| {method_0} | {route_0}                              | {limit_0}       | {rationalized_0} | {notes_0}    |
| :--------- | :------------------------------------- | :-------------- | :--------------- | :----------- |
| `GET`      | `/transfers`                           | 1 req / 30 sec  | 2 req / min      |              |
| `POST`     | `/transfers`                           | 75 req / 10 sec | 400 req / min    |              |
| `GET`      | `/transfers/:id`                       | 1 req / 5 sec   | 12 req / min     | *\*per :id*  |
| `GET`      | `/transfers/:id/balance`               | 1 req / 10 sec  | 6 req / min      |              |
| `GET`      | `/transfers/:id/status`                | 5 req / 5 sec   | 60 req / min     | *\*per :id*  |
| `GET`      | `/payments`                            | 1 req / 30 sec  | 2 req / min      |              |
| `GET`      | `/payments_intents`                    | 1 req / 30 sec  | 2 req / min      |              |
| `POST`     | `/payments_intents`                    | 75 req / 10 sec | 400 req / min    |              |
| `GET`      | `/payments_intents/:id`                | 1 req / 5 sec   | 12 req / min     | *\*per :id*  |
| `POST`     | `/payments_intents/:id/authentication` | 30 req / 5 sec  | 360 req / min    |              |
| `POST`     | `/payments_intents/:id/payments`       | 75 req / 10 sec | 400 req / min    |              |
| `POST`     | `/payments_intents/:id/payments/sync`  | 75 req / 10 sec | 400 req / min    |              |
| `GET`      | `/payments_intents/:id/payment-fees`   | 75 req / 10 sec | 450 req / min    |              |
| `GET`      | `/payments/:id/status`                 | 5 req / 5 sec   | 60 req / min     | *\*per :id*  |
| `GET`      | `/payments_intents/:id/status`         | 5 req / 5 sec   | 60 req / min     | *\*per :id*  |
| `POST`     | `/terminal/payments`                   | 5 req / 10 sec  | 30 req / min     |              |
| `GET`      | `/terminal/payments/:id`               | 5 req / 10 sec  | 30 req / min     |              |
| `GET`      | `/balance`                             | 75 req / 10 sec | 450 req / min    |              |
| `*`        | `*`                                    | 50 req / 5 sec  | 600 req / min    | Global limit |

<Note>
  **Actual limit** is how the code handles it in termes of requests / seconds.<br />**Rationalized limit** ease understanding and helps compare the different values on a same scale.
</Note>

<Warning>
  **This limit applies both to mode `sandbox` and mode `live`.<br />Remember to stop sandbox traffic if the transaction stream is getting heavy.**
</Warning>

## How to handle limits

Whenever a request is received by the API beyond the limit of the endpoint, an error `Too Many Requests` with HTTP status `429` will be returned.

<Note>
  Please checkout [MDN documentation](https://developer.mozilla.org/en/docs/Web/HTTP/Status/429) about this.
</Note>

The request failed and was not handled by the API because of the rate limit.

Headers are provided in the HTTP response for proper handling :

| Header name             | Description                                                                                                |
| :---------------------- | :--------------------------------------------------------------------------------------------------------- |
| `Retry-After`           | In case the limit is reached,<br />this header tells how long to wait before a new request will be allowed |
| `X-RateLimit-Limit`     | The current limit on the endpoint                                                                          |
| `X-RateLimit-Remaining` | Number of remaining requests before reaching the limit                                                     |
| `X-RateLimit-Reset`     | Time before a spot is free in the queue for a new request                                                  |

### Reactive solution (easier)

One way to handle rate limits from a client-side perspective is to retry requests if they fail for a 429 reason:

<CodeGroup>
  ```javascript hub2-api.js theme={null}
  const MAXIMUM_TRY_COUNT = 3;
  const URL = 'https://api.hub2.io/balance;
  const CONFIGURATION = {
    method: "GET",
    headers: {
      ApiKey: MY_API_KEY,
      MerchantId: MY_MERCHANT_ID,
    },
  };

  (function requestRetry(numberOfTries) {
    fetch(URL, CONFIGURATION)
      .then(() => {
        // code here
      })
      .catch((error) => {
        if (error?.response?.status === 429) {
          if (numberOfTries > MAXIMUM_TRY_COUNT) {
            throw error;
          }

          // Adding 1 second of grace delay
          const retryAfter: number = parseInt(response.headers['retry-after'], 10) + 1;
          await new Promise((resolve) => setTimeout(resolve, retryAfter));
          return requestRetry(numberOfTries + 1);
        }
      })
  })(0);
  ```

  ```typescript hub2.service.ts theme={null}
  // Using framework NestJS
  import { HttpService } from "@nestjs/axios";
  import { Injectable } from "@nestjs/common";
  import { lastValueFrom } from "rxjs";

  @Injectable()
  export class HUB2Service {
    public static MAXIMUM_TRY_COUNT: number = 3;

    constructor(
      private readonly http: HttpService,
    ) {}

    async requestRetry(numberOfTries: number = 0): Promise<any> {
      const url = 'https://api.hub2.io/balance;
      const config = {
        headers: {
          ApiKey: MY_API_KEY,
          MerchantId: MY_MERCHANT_ID,
        },
      };
      try {
        const response = await lastValueFrom(this.http.post(url, {}, config));
      } catch (error) {
        if (error?.response?.status === 429) {
          if (numberOfTries > HUB2Service.MAXIMUM_TRY_COUNT) {
            throw error;
          }

          // Adding 1 second of grace delay
          const retryAfter: number = parseInt(response.headers['retry-after'], 10) + 1;
          await new Promise((resolve) => setTimeout(resolve, retryAfter));
          return this.requestRetry(numberOfTries + 1);
        }
      }
    }
  }
  ```
</CodeGroup>

### Proactive solution (harder)

The proactive solution is a bit trickier, it consist of keeping a pool of requests ready to be started with the exact size of the destination endpoint rate limit. Whenever the pool is empty, the next request waits in line for a token to free up.

Check out [that interesting article](https://www.useanvil.com/blog/engineering/throttling-and-consuming-apis-with-429-rate-limits/) on how to implement rate limit from the client-side perspective, especially approaches 4 and 4.1.

## Conclusion

In a perfect world, no limit would be set on the API endpoints. However in the real world, it helps preventing abuse and keep a reliable service for everyone.

The team work on a daily basis to improve the stability and the performance of the API and this page will be updated as soon as upgrades allow to loosen the limits.
