The beehiiv API has a rate limit of 180 requests per minute on a per-organization basis. This is to prevent abuse and ensure the stability of the API.
If you are making requests to the beehiiv API at a rate that exceeds the rate limit, you will receive a 429 (Too Many Requests) error.
To prevent this, we recommend implementing rate limiting and methods like exponential backoff to retry requests that fail due to rate limiting.
Each response from the beehiiv API will include the following headers to assist you in your rate limiting implementation:
RateLimit-Limit: The maximum number of requests that are allowed in the current period.RateLimit-Remaining: The number of requests remaining in the current period.RateLimit-Reset: The time (in seconds since the Unix epoch) at which the current period will reset.To effectively implement rate limiting, we recommend instituting a queue system and leveraging exponential backoff.
Many programming languages and frameworks offer built-in support for queue systems. Some common examples include:
Many no-code platforms such as Zapier and Make automatically adhere to our rate limit.
This is a basic example of how to implement rate limiting in your JavaScript code. More complex implementations can be implemented using one of the queue systems mentioned above or by using a library like Bottleneck.
Configuration:
MAX_REQUESTS_PER_MINUTE: Set to 180, matching the beehiiv API limit.MAX_CONCURRENT: Limits how many requests can be active simultaneously (e.g., 5). This prevents overwhelming the network or the server with too many connections at once, even if within the overall rate limit.MIN_TIME_BETWEEN_REQUESTS_MS: Ensures a minimum delay between the start of each request (e.g., 350ms). This helps distribute requests more evenly and provides an additional safeguard against hitting the rate limit due to bursts.State Management:
requestQueue: An array that holds API calls waiting to be made. Each item in the queue is an object containing the function to call (fnToCall), its arguments (args), and the resolve and reject functions of the Promise returned by throttledApiCall.activeRequestsCount: Tracks the number of currently in-flight API requests.requestTimestamps: Stores the timestamps of when each request was dispatched. This array is used to ensure that no more than MAX_REQUESTS_PER_MINUTE are made within any rolling 60-second window.makeApiCall(endpoint, params):
fetch request to the beehiiv API. You’ll need to replace 'Bearer YOUR_API_KEY' with your API key and customize the request as needed.throttledApiCall(endpoint, params):
makeApiCall. When you want to make an API request in a rate-limited fashion, you call throttledApiCall instead of makeApiCall directly.requestQueue and then triggers processRequestQueue (asynchronously via setTimeout) to attempt to process it.processRequestQueue():
requestQueue is empty, it does nothing.requestTimestamps to only keep those within the last 60 seconds.activeRequestsCount is already at MAX_CONCURRENT, it returns, waiting for an active request to complete.requestTimestamps indicates that MAX_REQUESTS_PER_MINUTE have been made in the last 60 seconds, it calculates the time needed to wait until the oldest request in the window expires and schedules processRequestQueue to run after that delay.MIN_TIME_BETWEEN_REQUESTS_MS. If so, it schedules processRequestQueue to run after the necessary delay.requestQueue, increments activeRequestsCount, records the dispatch timestamp, and executes the API call (fnToCall).finally block decrements activeRequestsCount and calls setTimeout(processRequestQueue, 0) to ensure the queue processing continues for any subsequent requests.Example Usage (fetchAllPosts):
throttledApiCall. The rate limiter manages the queue and dispatches these calls according to the defined limits, preventing 429 errors.This vanilla JavaScript approach helps prevent 429 errors by managing request flow. Remember to adjust YOUR_API_KEY and the API endpoints in the makeApiCall function.
This vanilla JavaScript example focuses on managing request rates within a single Node.js process, like running a script locally on your machine.
It does not cover persistent storage of rate limit states (which would be needed if the application restarts) or distributed rate limiting across multiple instances. For those scenarios, or for handling very large queues robustly, you would typically integrate server-side queuing systems (like Amazon SQS or others mentioned above) often backed by stores like Redis or Valkey.