diff --git a/CHANGES.rst b/CHANGES.rst
index da741071..17cdef3b 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -65,6 +65,11 @@ Unreleased
 * :class:`.Reddit` has a new configurable parameter, ``timeout``. This defaults
   to 16 seconds. It controls how long PRAW will wait for a response before
   throwing an exception.
+* PRAW now handles ratelimit errors returned as instances of
+  :class:`.RedditAPIException`.
+* :class:`.Reddit` has one new parameter, ``ratelimit_seconds`` . The parameter
+  configures the maximum amount of seconds to catch ratelimits for.
+  It defaults to 5 seconds when not specified.
 
 **Changed**
 
diff --git a/praw/config.py b/praw/config.py
index 47508a08..6e0574c4 100644
--- a/praw/config.py
+++ b/praw/config.py
@@ -137,10 +137,18 @@ class Config:
         ):
             setattr(self, attribute, self._fetch_or_not_set(attribute))
 
-        for required_attribute in ("oauth_url", "reddit_url", "timeout"):
+        for required_attribute in (
+            "oauth_url",
+            "ratelimit_seconds",
+            "reddit_url",
+            "timeout",
+        ):
             setattr(self, required_attribute, self._fetch(required_attribute))
 
-        for attribute, conversion in {"timeout": int}.items():
+        for attribute, conversion in {
+            "ratelimit_seconds": int,
+            "timeout": int,
+        }.items():
             try:
                 setattr(self, attribute, conversion(getattr(self, attribute)))
             except ValueError:
diff --git a/praw/praw.ini b/praw/praw.ini
index f58b6406..fe29a1ba 100644
--- a/praw/praw.ini
+++ b/praw/praw.ini
@@ -13,6 +13,9 @@ trophy_kind=t6
 # The URL prefix for OAuth-related requests.
 oauth_url=https://oauth.reddit.com
 
+# The amount of seconds to ratelimit
+ratelimit_seconds=5
+
 # The URL prefix for regular requests.
 reddit_url=https://www.reddit.com
 
diff --git a/praw/reddit.py b/praw/reddit.py
index 79db34c4..54048285 100644
--- a/praw/reddit.py
+++ b/praw/reddit.py
@@ -1,7 +1,10 @@
 """Provide the Reddit class."""
 import configparser
 import os
+import re
+import time
 from itertools import islice
+from logging import getLogger
 from typing import IO, Any, Dict, Generator, Iterable, Optional, Type, Union
 from warnings import warn
 
@@ -41,6 +44,8 @@ Redditor = models.Redditor
 Submission = models.Submission
 Subreddit = models.Subreddit
 
+logger = getLogger("praw")
+
 
 class Reddit:
     """The Reddit class provides convenient access to Reddit's API.
@@ -59,6 +64,7 @@ class Reddit:
     """
 
     update_checked = False
+    _ratelimit_regex = re.compile(r"([0-9]{1,2}) (seconds?|minutes?)")
 
     @property
     def _next_unique(self):
@@ -481,8 +487,7 @@ class Reddit:
             None).
 
         """
-        data = self.request("GET", path, params=params)
-        return self._objector.objectify(data)
+        return self._objectify_request(method="GET", params=params, path=path)
 
     def info(
         self,
@@ -542,6 +547,50 @@ class Reddit:
 
         return generator(url)
 
+    def _objectify_request(
+        self,
+        data: Optional[
+            Union[Dict[str, Union[str, Any]], bytes, IO, str]
+        ] = None,
+        files: Optional[Dict[str, IO]] = None,
+        method: str = "",
+        params: Optional[Union[str, Dict[str, str]]] = None,
+        path: str = "",
+    ) -> Any:
+        """Run a request through the ``Objector``.
+
+        :param data: Dictionary, bytes, or file-like object to send in the body
+            of the request (default: None).
+        :param files: Dictionary, filename to file (like) object mapping
+            (default: None).
+        :param method: The HTTP method (e.g., GET, POST, PUT, DELETE).
+        :param params: The query parameters to add to the request (default:
+            None).
+        :param path: The path to fetch.
+
+        """
+        return self._objector.objectify(
+            self.request(
+                data=data, files=files, method=method, params=params, path=path
+            )
+        )
+
+    def _handle_rate_limit(
+        self, exception: RedditAPIException
+    ) -> Optional[Union[int]]:
+        for item in exception.items:
+            if item.error_type == "RATELIMIT":
+                amount_search = self._ratelimit_regex.search(item.message)
+                if not amount_search:
+                    break
+                seconds = int(amount_search.group(1))
+                if "minute" in amount_search.group(2):
+                    seconds *= 60
+                if seconds <= int(self.config.ratelimit_seconds):
+                    sleep_seconds = seconds + min(seconds / 10, 1)
+                    return sleep_seconds
+        return None
+
     def patch(
         self,
         path: str,
@@ -556,8 +605,7 @@ class Reddit:
             of the request (default: None).
 
         """
-        data = self.request("PATCH", path, data=data)
-        return self._objector.objectify(data)
+        return self._objectify_request(data=data, method="PATCH", path=path)
 
     def post(
         self,
@@ -579,10 +627,32 @@ class Reddit:
             None).
 
         """
-        data = self.request(
-            "POST", path, data=data or {}, files=files, params=params
-        )
-        return self._objector.objectify(data)
+        data = data or {}
+        try:
+            return self._objectify_request(
+                data=data,
+                files=files,
+                method="POST",
+                params=params,
+                path=path,
+            )
+        except RedditAPIException as exception:
+            seconds = self._handle_rate_limit(exception=exception)
+            if seconds is not None:
+                logger.debug(
+                    "Rate limit hit, sleeping for {:.2f} seconds".format(
+                        seconds
+                    )
+                )
+                time.sleep(seconds)
+                return self._objectify_request(
+                    data=data,
+                    files=files,
+                    method="POST",
+                    params=params,
+                    path=path,
+                )
+            raise
 
     def put(
         self,
@@ -598,8 +668,7 @@ class Reddit:
             of the request (default: None).
 
         """
-        data = self.request("PUT", path, data=data)
-        return self._objector.objectify(data)
+        return self._objectify_request(data=data, method="PUT", path=path,)
 
     def random_subreddit(self, nsfw: bool = False) -> Subreddit:
         """Return a random lazy instance of :class:`~.Subreddit`.

API ratelimit hit with chat
**Describe the bug**
<!-- A clear and concise description of what the bug is. -->
Live chat comments have a ratelimit of 5 seconds per message, but this message is returned as any other APIException. 

**To Reproduce**
Steps to reproduce the behavior:
1. Obtain a submission instance that is a live chat
2.Just reply twice to the same submission in succession

**Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->
The program should wait for the ratelimit.

**Code/Logs**
<!-- include your code, without the Reddit() initialization, so as to not leak private credentials. -->
```
---------------------------------------------------------------------------
APIException                              Traceback (most recent call last)
<ipython-input-14-5b88e4f8d60d> in <module>
      1 while True:
----> 2     print(repr(s[1].reply("F")))
      3 

/usr/local/lib/python3.7/site-packages/praw/models/reddit/mixins/replyable.py in reply(self, body)
     31         """
     32         data = {"text": body, "thing_id": self.fullname}
---> 33         comments = self._reddit.post(API_PATH["comment"], data=data)
     34         try:
     35             return comments[0]

/usr/local/lib/python3.7/site-packages/praw/reddit.py in post(self, path, data, files, params)
    553             "POST", path, data=data or {}, files=files, params=params
    554         )
--> 555         return self._objector.objectify(data)
    556 
    557     def put(

/usr/local/lib/python3.7/site-packages/praw/objector.py in objectify(self, data)
    168             errors = data["json"]["errors"]
    169             if len(errors) == 1:
--> 170                 raise APIException(*errors[0])
    171             assert not errors
    172         elif isinstance(data, dict):

APIException: RATELIMIT: 'you are doing that too much. try again in 5 seconds.' on field 'ratelimit'
```

**System Info**
 - OS: MacOS 12.14.6
 - Python: 3.7.7
 - PRAW Version: 6.5.1

diff --git a/tests/unit/test_reddit.py b/tests/unit/test_reddit.py
index 0a664c5a..966fef5a 100644
--- a/tests/unit/test_reddit.py
+++ b/tests/unit/test_reddit.py
@@ -8,7 +8,7 @@ from prawcore.exceptions import BadRequest
 
 from praw import Reddit, __version__
 from praw.config import Config
-from praw.exceptions import ClientException
+from praw.exceptions import ClientException, RedditAPIException
 
 from . import UnitTest
 
@@ -61,6 +61,14 @@ class TestReddit(UnitTest):
             == "An incorrect config type was given for option timeout. The "
             "expected type is int, but the given value is test."
         )
+        with pytest.raises(ValueError) as excinfo:
+            Reddit(ratelimit_seconds="test", **self.REQUIRED_DUMMY_SETTINGS)
+        assert (
+            excinfo.value.args[0]
+            == "An incorrect config type was given for option "
+            "ratelimit_seconds. The expected type is int, but the given value "
+            "is test."
+        )
 
     def test_info__not_list(self):
         with pytest.raises(TypeError) as excinfo:
@@ -80,6 +88,78 @@ class TestReddit(UnitTest):
     def test_multireddit(self):
         assert self.reddit.multireddit("bboe", "aa").path == "/user/bboe/m/aa"
 
+    @mock.patch(
+        "praw.Reddit.request",
+        side_effect=[
+            {
+                "json": {
+                    "errors": [
+                        [
+                            "RATELIMIT",
+                            "You are doing that too much. Try again in 5 "
+                            "seconds.",
+                            "ratelimit",
+                        ]
+                    ]
+                }
+            },
+            {
+                "json": {
+                    "errors": [
+                        [
+                            "RATELIMIT",
+                            "You are doing that too much. Try again in 5 "
+                            "seconds.",
+                            "ratelimit",
+                        ]
+                    ]
+                }
+            },
+            {
+                "json": {
+                    "errors": [
+                        [
+                            "RATELIMIT",
+                            "You are doing that too much. Try again in 10 "
+                            "minutes.",
+                            "ratelimit",
+                        ]
+                    ]
+                }
+            },
+            {
+                "json": {
+                    "errors": [
+                        [
+                            "RATELIMIT",
+                            "APRIL FOOLS FROM REDDIT, TRY AGAIN",
+                            "ratelimit",
+                        ]
+                    ]
+                }
+            },
+            {},
+        ],
+    )
+    @mock.patch("time.sleep", return_value=None)
+    def test_post_ratelimit(self, __, _):
+        with pytest.raises(RedditAPIException) as exc:
+            self.reddit.post("test")
+        assert (
+            exc.value.message
+            == "You are doing that too much. Try again in 5 seconds."
+        )
+        with pytest.raises(RedditAPIException) as exc2:
+            self.reddit.post("test")
+        assert (
+            exc2.value.message
+            == "You are doing that too much. Try again in 10 minutes."
+        )
+        with pytest.raises(RedditAPIException) as exc3:
+            self.reddit.post("test")
+        assert exc3.value.message == "APRIL FOOLS FROM REDDIT, TRY AGAIN"
+        assert self.reddit.post("test") == {}
+
     def test_read_only__with_authenticated_core(self):
         with Reddit(
             password=None,

pip install -e .[dev]
parse_log_pytest
requirements.txt
3.7
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.13
Babel==2.14.0
betamax==0.8.1
betamax-matchers==0.4.0
black==23.3.0
certifi @ file:///croot/certifi_1671487769961/work/certifi
cfgv==3.3.1
charset-normalizer==3.4.1
click==8.1.8
distlib==0.3.9
docutils==0.17.1
exceptiongroup==1.2.2
filelock==3.12.2
flake8==5.0.4
identify==2.5.24
idna==3.10
imagesize==1.4.1
importlib-metadata==4.2.0
iniconfig==2.0.0
Jinja2==3.1.6
MarkupSafe==2.1.5
mccabe==0.7.0
mypy-extensions==1.0.0
nodeenv==1.9.1
packaging==24.0
pathspec==0.11.2
platformdirs==2.6.2
pluggy==1.2.0
-e git+https://github.com/praw-dev/praw.git@5533c045b0195e0538bd1676ddba1983f51ccf84#egg=praw
prawcore==1.5.0
pre-commit==2.21.0
pycodestyle==2.9.1
pydocstyle==6.3.0
pyflakes==2.5.0
Pygments==2.17.2
pytest==7.4.4
pytz==2025.2
PyYAML==6.0.1
requests==2.31.0
requests-toolbelt==1.0.0
snowballstemmer==2.2.0
Sphinx==2.4.5
sphinx-rtd-theme==1.3.0
sphinxcontrib-applehelp==1.0.2
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp==2.0.0
sphinxcontrib-jquery==4.1
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.5
tomli==2.0.1
typed-ast==1.5.5
typing_extensions==4.7.1
update-checker==0.18.0
urllib3==2.0.7
virtualenv==20.16.2
websocket-client==1.6.1
zipp==3.15.0

name: praw
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=22.3.1=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.13
      - babel==2.14.0
      - betamax==0.8.1
      - betamax-matchers==0.4.0
      - black==23.3.0
      - cfgv==3.3.1
      - charset-normalizer==3.4.1
      - click==8.1.8
      - distlib==0.3.9
      - docutils==0.17.1
      - exceptiongroup==1.2.2
      - filelock==3.12.2
      - flake8==5.0.4
      - identify==2.5.24
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==4.2.0
      - iniconfig==2.0.0
      - jinja2==3.1.6
      - markupsafe==2.1.5
      - mccabe==0.7.0
      - mypy-extensions==1.0.0
      - nodeenv==1.9.1
      - packaging==24.0
      - pathspec==0.11.2
      - platformdirs==2.6.2
      - pluggy==1.2.0
      - praw==7.0.0.dev0
      - prawcore==1.5.0
      - pre-commit==2.21.0
      - pycodestyle==2.9.1
      - pydocstyle==6.3.0
      - pyflakes==2.5.0
      - pygments==2.17.2
      - pytest==7.4.4
      - pytz==2025.2
      - pyyaml==6.0.1
      - requests==2.31.0
      - requests-toolbelt==1.0.0
      - snowballstemmer==2.2.0
      - sphinx==2.4.5
      - sphinx-rtd-theme==1.3.0
      - sphinxcontrib-applehelp==1.0.2
      - sphinxcontrib-devhelp==1.0.2
      - sphinxcontrib-htmlhelp==2.0.0
      - sphinxcontrib-jquery==4.1
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==1.0.3
      - sphinxcontrib-serializinghtml==1.1.5
      - tomli==2.0.1
      - typed-ast==1.5.5
      - typing-extensions==4.7.1
      - update-checker==0.18.0
      - urllib3==2.0.7
      - virtualenv==20.16.2
      - websocket-client==1.6.1
      - zipp==3.15.0
prefix: /opt/conda/envs/praw

tests/unit/test_reddit.py::TestReddit::test_invalid_config tests/unit/test_reddit.py::TestReddit::test_post_ratelimit
tests/unit/test_reddit.py::TestReddit::test_check_for_updates tests/unit/test_reddit.py::TestReddit::test_check_for_updates_update_checker_missing tests/unit/test_reddit.py::TestReddit::test_comment tests/unit/test_reddit.py::TestReddit::test_context_manager tests/unit/test_reddit.py::TestReddit::test_info__invalid_param tests/unit/test_reddit.py::TestReddit::test_info__not_list tests/unit/test_reddit.py::TestReddit::test_live_info__valid_param tests/unit/test_reddit.py::TestReddit::test_live_info__invalid_param tests/unit/test_reddit.py::TestReddit::test_multireddit tests/unit/test_reddit.py::TestReddit::test_read_only__with_authenticated_core tests/unit/test_reddit.py::TestReddit::test_read_only__with_authenticated_core__non_confidential tests/unit/test_reddit.py::TestReddit::test_read_only__with_script_authenticated_core tests/unit/test_reddit.py::TestReddit::test_read_only__without_trusted_authenticated_core tests/unit/test_reddit.py::TestReddit::test_read_only__without_untrusted_authenticated_core tests/unit/test_reddit.py::TestReddit::test_reddit__missing_required_settings tests/unit/test_reddit.py::TestReddit::test_reddit__required_settings_set_to_none tests/unit/test_reddit.py::TestReddit::test_reddit__site_name_no_section tests/unit/test_reddit.py::TestReddit::test_request__badrequest_with_no_json_body tests/unit/test_reddit.py::TestReddit::test_submission tests/unit/test_reddit.py::TestReddit::test_subreddit tests/unit/test_reddit.py::TestRedditCustomRequestor::test_requestor_class tests/unit/test_reddit.py::TestRedditCustomRequestor::test_requestor_kwargs
praw/config.py praw/reddit.py praw/praw.ini CHANGES.rst
praw/config.py praw/reddit.py praw/praw.ini CHANGES.rst