{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-tutorials/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["admonition"]},"type":"markdown"},"seo":{"title":"Handling Rate Limits (429)","llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"handling-rate-limits-429","__idx":0},"children":["Handling Rate Limits (429)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Rhythm APIs may return a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["429 Too Many Requests"]}," response when a client sends requests at a high rate. This is standard behavior for REST APIs and is not specific to your account or credentials."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When you receive a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["429"]},", your client should pause and retry the request after a delay rather than immediately retrying — which would likely trigger another ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["429"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"exponential-backoff","__idx":1},"children":["Exponential backoff"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The recommended approach is ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["exponential backoff with jitter"]},": each successive retry waits longer than the last, with a small random offset to avoid synchronized retries from multiple clients."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A basic pattern:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Receive a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["429"]}," response"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Wait ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["base * 2^attempt + jitter"]}," milliseconds"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Retry the request"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["If the retry also returns ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["429"]},", increase the attempt count and repeat"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Stop after a maximum number of attempts and surface an error"]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info","name":"Retry-After header"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If the response includes a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Retry-After"]}," header, use that value as your wait time instead of calculating your own."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"open-source-libraries","__idx":2},"children":["Open source libraries"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Rather than implementing backoff from scratch, use a well-tested library for your language:"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"javascript--nodejs","__idx":3},"children":["JavaScript / Node.js"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://github.com/sindresorhus/p-retry"},"children":["p-retry"]}]}," — Promise-based retry with full backoff control (ESM only; requires a bundler or dynamic ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["import()"]}," in CommonJS projects)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://github.com/softonic/axios-retry"},"children":["axios-retry"]}]}," — drop-in retry plugin for Axios (ensure your ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["axios"]}," dependency is kept up to date independently)"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"python","__idx":4},"children":["Python"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://github.com/jd/tenacity"},"children":["tenacity"]}]}," — full-featured retry library with exponential, fibonacci, and custom wait strategies"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"java","__idx":5},"children":["Java"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://resilience4j.readme.io/docs/retry"},"children":["Resilience4j Retry"]}]}," — production-grade retry with exponential backoff and jitter; the recommended choice for Java 17+ projects"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"c--net","__idx":6},"children":["C# / .NET"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://github.com/App-vNext/Polly"},"children":["Polly"]}]}," — comprehensive resilience library with retry, circuit breaker, and backoff policies"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"go","__idx":7},"children":["Go"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://github.com/avast/retry-go"},"children":["retry-go"]}]}," — simple retry with configurable backoff strategies including exponential and fibonacci"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"php","__idx":8},"children":["PHP"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://github.com/caseyamcl/guzzle_retry_middleware"},"children":["GuzzleRetryMiddleware"]}]}," — retry middleware for Guzzle with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Retry-After"]}," header support"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://github.com/stechstudio/backoff"},"children":["PHP Backoff"]}]}," — standalone backoff library with exponential, linear, and polynomial strategies"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"summary","__idx":9},"children":["Summary"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["A ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["429"]}," response means your client is sending too many requests — it is not an auth error"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Always implement retry logic with exponential backoff in any integration that calls Rhythm APIs under load"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Honor the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Retry-After"]}," header when present"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Use an established library rather than rolling your own implementation"]}]}]},"headings":[{"value":"Handling Rate Limits (429)","id":"handling-rate-limits-429","depth":1},{"value":"Exponential backoff","id":"exponential-backoff","depth":2},{"value":"Open source libraries","id":"open-source-libraries","depth":2},{"value":"JavaScript / Node.js","id":"javascript--nodejs","depth":3},{"value":"Python","id":"python","depth":3},{"value":"Java","id":"java","depth":3},{"value":"C# / .NET","id":"c--net","depth":3},{"value":"Go","id":"go","depth":3},{"value":"PHP","id":"php","depth":3},{"value":"Summary","id":"summary","depth":2}],"frontmatter":{"seo":{"title":"Handling Rate Limits (429)"}},"lastModified":"2026-06-10T21:18:21.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/tutorials/rate-limiting","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}