Repository: auth0/auth0-python

Issue:
Retries implementation of rest.py missing for POST/PATCH/PUT/DELETE
### Checklist

- [X] I have looked into the [Readme](https://github.com/auth0/auth0-python#readme) and [Examples](https://github.com/auth0/auth0-python/blob/master/EXAMPLES.md), and have not found a suitable solution or answer.
- [X] I have looked into the [API documentation](https://auth0-python.readthedocs.io/en/latest/) and have not found a suitable solution or answer.
- [X] I have searched the [issues](https://github.com/auth0/auth0-python/issues) and have not found a suitable solution or answer.
- [X] I have searched the [Auth0 Community](https://community.auth0.com) forums and have not found a suitable solution or answer.
- [X] I agree to the terms within the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md).

### Description

If you make a lot of API calls after each other, you will run into Error Code 429 of GlobalRateLimit.

Only **GET** implements retries, as you can see here: https://github.com/auth0/auth0-python/blob/8e1bf4a0ff07db16a768acf2b8b4310b523f03f1/auth0/rest.py#L139-L178

The retry implementation for **POST/FILE_POST/PATCH/PUT/DELETE** is missing, as you can see here:
https://github.com/auth0/auth0-python/blob/8e1bf4a0ff07db16a768acf2b8b4310b523f03f1/auth0/rest.py#L180-L239


### Reproduction

Try the following script to do a lot of POST call. (I used adding a member to an Organization)


```
# =========================================================
# Step 1: Install Auth0 Phyton SDK
# =========================================================
"""
pip install auth0-python
"""

# =========================================================
# Step 2: Create M2M Application
# =========================================================
"""
1. Go to "Applications" -> "Applications" and click on "+ Create Application".
2. Enter as "Name": "SaaS Management M2M", select "Machine to Machine Applications" and click on "Create".
3. Select "Auth0 Management API" and select "All" Permissions (for production, select only the scopes that are required).
4. Click on "Authorize"
5. Switch to the tab "Settings" and copy the values of "Domain", "Client ID" and "Client Secret".
"""

# =========================================================
# Step 3: Run Deployment
# =========================================================
from auth0.authentication import GetToken
from auth0.management import Auth0
from auth0.rest import RestClientOptions
from auth0.rest import RateLimitError
import time

# Step 1: Get Access Token for Management API
auth0_domain = "domain.eu.auth0.com"
auth0_client_id = "XXXX"
auth0_client_secret = "XXXX"

get_token = GetToken(auth0_domain, auth0_client_id, client_secret=auth0_client_secret)
token = get_token.client_credentials('https://{}/api/v2/'.format(auth0_domain))
mgmt_api_token = token['access_token']

# Step 2: Create Auth0
rest_client_option = RestClientOptions(retries=10) # set max retries to maximum of 10
auth0 =  Auth0(auth0_domain, mgmt_api_token, rest_client_option)

# Step 3: Loop on any API that is doing a put/post/delete call for about 30 tries,
# for me - it usually happens on try 16 or 17
for i in range(1, 30):
    start_time = time.perf_counter()
    print("===== Iteration "+ str(i) + " =====")
    try:
        organization_id = "org_V6RnNQ9x3vKcGcB9"
        user_id = "auth0|64db3cf0cf71fa8ca0ae9226"
        auth0.organizations.create_organization_members(organization_id, {"members":[user_id]})
    except RateLimitError as e:
        print("!!!!!!!!!!!! RateLimitError !!!!!!!!!!!!")
        print("Time per API call: " + str(time.perf_counter() - start_time))
        raise e
    
    print("Time per API call: " + str(time.perf_counter() - start_time))
```

### Additional context

_No response_

### auth0-python version

4.4.0

### Python version

3.11.4

Discussion:

Patch:
diff --git a/auth0/rest.py b/auth0/rest.py
index 41282b7..0b91323 100644
--- a/auth0/rest.py
+++ b/auth0/rest.py
@@ -1,9 +1,9 @@
 from __future__ import annotations
 
 import base64
-import json
 import platform
 import sys
+from json import dumps, loads
 from random import randint
 from time import sleep
 from typing import TYPE_CHECKING, Any, Mapping
@@ -95,7 +95,7 @@ class RestClient:
             py_version = platform.python_version()
             version = sys.modules["auth0"].__version__
 
-            auth0_client = json.dumps(
+            auth0_client = dumps(
                 {
                     "name": "auth0-python",
                     "version": version,
@@ -136,32 +136,41 @@ class RestClient:
     def MIN_REQUEST_RETRY_DELAY(self) -> int:
         return 100
 
-    def get(
+    def _request(
         self,
+        method: str,
         url: str,
         params: dict[str, Any] | None = None,
+        data: RequestData | None = None,
+        json: RequestData | None = None,
         headers: dict[str, str] | None = None,
+        files: dict[str, Any] | None = None,
     ) -> Any:
-        request_headers = self.base_headers.copy()
-        request_headers.update(headers or {})
-
         # Track the API request attempt number
         attempt = 0
 
         # Reset the metrics tracker
         self._metrics = {"retries": 0, "backoff": []}
 
+        kwargs = {
+            k: v
+            for k, v in {
+                "params": params,
+                "json": json,
+                "data": data,
+                "headers": headers,
+                "files": files,
+                "timeout": self.options.timeout,
+            }.items()
+            if v is not None
+        }
+
         while True:
             # Increment attempt number
             attempt += 1
 
             # Issue the request
-            response = requests.get(
-                url,
-                params=params,
-                headers=request_headers,
-                timeout=self.options.timeout,
-            )
+            response = requests.request(method, url, **kwargs)
 
             # If the response did not have a 429 header, or the attempt number is greater than the configured retries, break
             if response.status_code != 429 or attempt > self._retries:
@@ -177,6 +186,16 @@ class RestClient:
         # Return the final Response
         return self._process_response(response)
 
+    def get(
+        self,
+        url: str,
+        params: dict[str, Any] | None = None,
+        headers: dict[str, str] | None = None,
+    ) -> Any:
+        request_headers = self.base_headers.copy()
+        request_headers.update(headers or {})
+        return self._request("GET", url, params=params, headers=request_headers)
+
     def post(
         self,
         url: str,
@@ -185,11 +204,7 @@ class RestClient:
     ) -> Any:
         request_headers = self.base_headers.copy()
         request_headers.update(headers or {})
-
-        response = requests.post(
-            url, json=data, headers=request_headers, timeout=self.options.timeout
-        )
-        return self._process_response(response)
+        return self._request("POST", url, json=data, headers=request_headers)
 
     def file_post(
         self,
@@ -199,27 +214,15 @@ class RestClient:
     ) -> Any:
         headers = self.base_headers.copy()
         headers.pop("Content-Type", None)
-
-        response = requests.post(
-            url, data=data, files=files, headers=headers, timeout=self.options.timeout
-        )
-        return self._process_response(response)
+        return self._request("POST", url, data=data, files=files, headers=headers)
 
     def patch(self, url: str, data: RequestData | None = None) -> Any:
         headers = self.base_headers.copy()
-
-        response = requests.patch(
-            url, json=data, headers=headers, timeout=self.options.timeout
-        )
-        return self._process_response(response)
+        return self._request("PATCH", url, json=data, headers=headers)
 
     def put(self, url: str, data: RequestData | None = None) -> Any:
         headers = self.base_headers.copy()
-
-        response = requests.put(
-            url, json=data, headers=headers, timeout=self.options.timeout
-        )
-        return self._process_response(response)
+        return self._request("PUT", url, json=data, headers=headers)
 
     def delete(
         self,
@@ -228,15 +231,7 @@ class RestClient:
         data: RequestData | None = None,
     ) -> Any:
         headers = self.base_headers.copy()
-
-        response = requests.delete(
-            url,
-            headers=headers,
-            params=params or {},
-            json=data,
-            timeout=self.options.timeout,
-        )
-        return self._process_response(response)
+        return self._request("DELETE", url, params=params, json=data, headers=headers)
 
     def _calculate_wait(self, attempt: int) -> int:
         # Retry the request. Apply a exponential backoff for subsequent attempts, using this formula:
@@ -317,7 +312,7 @@ class Response:
 
 class JsonResponse(Response):
     def __init__(self, response: requests.Response | RequestsResponse) -> None:
-        content = json.loads(response.text)
+        content = loads(response.text)
         super().__init__(response.status_code, content, response.headers)
 
     def _error_code(self) -> str:
diff --git a/auth0/rest_async.py b/auth0/rest_async.py
index 5ac4e6b..0581b81 100644
--- a/auth0/rest_async.py
+++ b/auth0/rest_async.py
@@ -52,43 +52,23 @@ class AsyncRestClient(RestClient):
         """
         self._session = session
 
-    async def _request(self, *args: Any, **kwargs: Any) -> Any:
-        kwargs["headers"] = kwargs.get("headers", self.base_headers)
-        kwargs["timeout"] = self.timeout
-        if self._session is not None:
-            # Request with re-usable session
-            async with self._session.request(*args, **kwargs) as response:
-                return await self._process_response(response)
-        else:
-            # Request without re-usable session
-            async with aiohttp.ClientSession() as session:
-                async with session.request(*args, **kwargs) as response:
-                    return await self._process_response(response)
-
-    async def get(
-        self,
-        url: str,
-        params: dict[str, Any] | None = None,
-        headers: dict[str, str] | None = None,
+    async def _request_with_session(
+        self, session: aiohttp.ClientSession, *args: Any, **kwargs: Any
     ) -> Any:
-        request_headers = self.base_headers.copy()
-        request_headers.update(headers or {})
         # Track the API request attempt number
         attempt = 0
 
         # Reset the metrics tracker
         self._metrics = {"retries": 0, "backoff": []}
 
-        params = _clean_params(params)
         while True:
             # Increment attempt number
             attempt += 1
 
             try:
-                response = await self._request(
-                    "get", url, params=params, headers=request_headers
-                )
-                return response
+                async with session.request(*args, **kwargs) as response:
+                    return await self._process_response(response)
+
             except RateLimitError as e:
                 # If the attempt number is greater than the configured retries, raise RateLimitError
                 if attempt > self._retries:
@@ -101,6 +81,30 @@ class AsyncRestClient(RestClient):
                 # sleep() functions in seconds, so convert the milliseconds formula above accordingly
                 await asyncio.sleep(wait / 1000)
 
+    async def _request(self, *args: Any, **kwargs: Any) -> Any:
+        kwargs["headers"] = kwargs.get("headers", self.base_headers)
+        kwargs["timeout"] = self.timeout
+        if self._session is not None:
+            # Request with re-usable session
+            return self._request_with_session(self.session, *args, **kwargs)
+        else:
+            # Request without re-usable session
+            async with aiohttp.ClientSession() as session:
+                return self._request_with_session(session, *args, **kwargs)
+
+    async def get(
+        self,
+        url: str,
+        params: dict[str, Any] | None = None,
+        headers: dict[str, str] | None = None,
+    ) -> Any:
+        request_headers = self.base_headers.copy()
+        request_headers.update(headers or {})
+
+        return await self._request(
+            "get", url, params=_clean_params(params), headers=request_headers
+        )
+
     async def post(
         self,
         url: str,
@@ -118,7 +122,7 @@ class AsyncRestClient(RestClient):
         files: dict[str, Any],
     ) -> Any:
         headers = self.base_headers.copy()
-        headers.pop("Content-Type", None)
+        headers.pop("Content-Type")
         return await self._request("post", url, data={**data, **files}, headers=headers)
 
     async def patch(self, url: str, data: RequestData | None = None) -> Any:


Test patch:
diff --git a/auth0/test/authentication/test_base.py b/auth0/test/authentication/test_base.py
index 21a42d8..eed9d04 100644
--- a/auth0/test/authentication/test_base.py
+++ b/auth0/test/authentication/test_base.py
@@ -42,16 +42,17 @@ class TestBase(unittest.TestCase):
 
         self.assertEqual(ab.client.base_headers, {"Content-Type": "application/json"})
 
-    @mock.patch("requests.post")
-    def test_post(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post(self, mock_request):
         ab = AuthenticationBase("auth0.com", "cid", telemetry=False, timeout=(10, 2))
 
-        mock_post.return_value.status_code = 200
-        mock_post.return_value.text = '{"x": "y"}'
+        mock_request.return_value.status_code = 200
+        mock_request.return_value.text = '{"x": "y"}'
 
         data = ab.post("the-url", data={"a": "b"}, headers={"c": "d"})
 
-        mock_post.assert_called_with(
+        mock_request.assert_called_with(
+            "POST",
             "the-url",
             json={"a": "b"},
             headers={"c": "d", "Content-Type": "application/json"},
@@ -60,37 +61,38 @@ class TestBase(unittest.TestCase):
 
         self.assertEqual(data, {"x": "y"})
 
-    @mock.patch("requests.post")
-    def test_post_with_defaults(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post_with_defaults(self, mock_request):
         ab = AuthenticationBase("auth0.com", "cid", telemetry=False)
 
-        mock_post.return_value.status_code = 200
-        mock_post.return_value.text = '{"x": "y"}'
+        mock_request.return_value.status_code = 200
+        mock_request.return_value.text = '{"x": "y"}'
 
         # Only required params are passed
         data = ab.post("the-url")
 
-        mock_post.assert_called_with(
+        mock_request.assert_called_with(
+            "POST",
             "the-url",
-            json=None,
             headers={"Content-Type": "application/json"},
             timeout=5.0,
         )
 
         self.assertEqual(data, {"x": "y"})
 
-    @mock.patch("requests.post")
-    def test_post_includes_telemetry(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post_includes_telemetry(self, mock_request):
         ab = AuthenticationBase("auth0.com", "cid")
 
-        mock_post.return_value.status_code = 200
-        mock_post.return_value.text = '{"x": "y"}'
+        mock_request.return_value.status_code = 200
+        mock_request.return_value.text = '{"x": "y"}'
 
         data = ab.post("the-url", data={"a": "b"}, headers={"c": "d"})
 
-        self.assertEqual(mock_post.call_count, 1)
-        call_args, call_kwargs = mock_post.call_args
-        self.assertEqual(call_args[0], "the-url")
+        self.assertEqual(mock_request.call_count, 1)
+        call_args, call_kwargs = mock_request.call_args
+        self.assertEqual(call_args[0], "POST")
+        self.assertEqual(call_args[1], "the-url")
         self.assertEqual(call_kwargs["json"], {"a": "b"})
         headers = call_kwargs["headers"]
         self.assertEqual(headers["c"], "d")
@@ -100,13 +102,15 @@ class TestBase(unittest.TestCase):
 
         self.assertEqual(data, {"x": "y"})
 
-    @mock.patch("requests.post")
-    def test_post_error(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post_error(self, mock_request):
         ab = AuthenticationBase("auth0.com", "cid", telemetry=False)
 
         for error_status in [400, 500, None]:
-            mock_post.return_value.status_code = error_status
-            mock_post.return_value.text = '{"error": "e0","error_description": "desc"}'
+            mock_request.return_value.status_code = error_status
+            mock_request.return_value.text = (
+                '{"error": "e0","error_description": "desc"}'
+            )
 
             with self.assertRaises(Auth0Error) as context:
                 ab.post("the-url", data={"a": "b"}, headers={"c": "d"})
@@ -115,12 +119,12 @@ class TestBase(unittest.TestCase):
             self.assertEqual(context.exception.error_code, "e0")
             self.assertEqual(context.exception.message, "desc")
 
-    @mock.patch("requests.post")
-    def test_post_error_mfa_required(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post_error_mfa_required(self, mock_request):
         ab = AuthenticationBase("auth0.com", "cid", telemetry=False)
 
-        mock_post.return_value.status_code = 403
-        mock_post.return_value.text = '{"error": "mfa_required", "error_description": "Multifactor authentication required", "mfa_token": "Fe26...Ha"}'
+        mock_request.return_value.status_code = 403
+        mock_request.return_value.text = '{"error": "mfa_required", "error_description": "Multifactor authentication required", "mfa_token": "Fe26...Ha"}'
 
         with self.assertRaises(Auth0Error) as context:
             ab.post("the-url", data={"a": "b"}, headers={"c": "d"})
@@ -132,15 +136,15 @@ class TestBase(unittest.TestCase):
         )
         self.assertEqual(context.exception.content.get("mfa_token"), "Fe26...Ha")
 
-    @mock.patch("requests.post")
-    def test_post_rate_limit_error(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post_rate_limit_error(self, mock_request):
         ab = AuthenticationBase("auth0.com", "cid", telemetry=False)
 
-        mock_post.return_value.text = (
+        mock_request.return_value.text = (
             '{"statusCode": 429, "error": "e0", "error_description": "desc"}'
         )
-        mock_post.return_value.status_code = 429
-        mock_post.return_value.headers = {
+        mock_request.return_value.status_code = 429
+        mock_request.return_value.headers = {
             "x-ratelimit-limit": "3",
             "x-ratelimit-remaining": "6",
             "x-ratelimit-reset": "9",
@@ -155,15 +159,15 @@ class TestBase(unittest.TestCase):
         self.assertIsInstance(context.exception, RateLimitError)
         self.assertEqual(context.exception.reset_at, 9)
 
-    @mock.patch("requests.post")
-    def test_post_rate_limit_error_without_headers(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post_rate_limit_error_without_headers(self, mock_request):
         ab = AuthenticationBase("auth0.com", "cid", telemetry=False)
 
-        mock_post.return_value.text = (
+        mock_request.return_value.text = (
             '{"statusCode": 429, "error": "e0", "error_description": "desc"}'
         )
-        mock_post.return_value.status_code = 429
-        mock_post.return_value.headers = {}
+        mock_request.return_value.status_code = 429
+        mock_request.return_value.headers = {}
 
         with self.assertRaises(Auth0Error) as context:
             ab.post("the-url", data={"a": "b"}, headers={"c": "d"})
@@ -174,13 +178,15 @@ class TestBase(unittest.TestCase):
         self.assertIsInstance(context.exception, RateLimitError)
         self.assertEqual(context.exception.reset_at, -1)
 
-    @mock.patch("requests.post")
-    def test_post_error_with_code_property(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post_error_with_code_property(self, mock_request):
         ab = AuthenticationBase("auth0.com", "cid", telemetry=False)
 
         for error_status in [400, 500, None]:
-            mock_post.return_value.status_code = error_status
-            mock_post.return_value.text = '{"code": "e0","error_description": "desc"}'
+            mock_request.return_value.status_code = error_status
+            mock_request.return_value.text = (
+                '{"code": "e0","error_description": "desc"}'
+            )
 
             with self.assertRaises(Auth0Error) as context:
                 ab.post("the-url", data={"a": "b"}, headers={"c": "d"})
@@ -189,13 +195,13 @@ class TestBase(unittest.TestCase):
             self.assertEqual(context.exception.error_code, "e0")
             self.assertEqual(context.exception.message, "desc")
 
-    @mock.patch("requests.post")
-    def test_post_error_with_no_error_code(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post_error_with_no_error_code(self, mock_request):
         ab = AuthenticationBase("auth0.com", "cid", telemetry=False)
 
         for error_status in [400, 500, None]:
-            mock_post.return_value.status_code = error_status
-            mock_post.return_value.text = '{"error_description": "desc"}'
+            mock_request.return_value.status_code = error_status
+            mock_request.return_value.text = '{"error_description": "desc"}'
 
             with self.assertRaises(Auth0Error) as context:
                 ab.post("the-url", data={"a": "b"}, headers={"c": "d"})
@@ -204,13 +210,13 @@ class TestBase(unittest.TestCase):
             self.assertEqual(context.exception.error_code, "a0.sdk.internal.unknown")
             self.assertEqual(context.exception.message, "desc")
 
-    @mock.patch("requests.post")
-    def test_post_error_with_text_response(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post_error_with_text_response(self, mock_request):
         ab = AuthenticationBase("auth0.com", "cid", telemetry=False)
 
         for error_status in [400, 500, None]:
-            mock_post.return_value.status_code = error_status
-            mock_post.return_value.text = "there has been a terrible error"
+            mock_request.return_value.status_code = error_status
+            mock_request.return_value.text = "there has been a terrible error"
 
             with self.assertRaises(Auth0Error) as context:
                 ab.post("the-url", data={"a": "b"}, headers={"c": "d"})
@@ -221,13 +227,13 @@ class TestBase(unittest.TestCase):
                 context.exception.message, "there has been a terrible error"
             )
 
-    @mock.patch("requests.post")
-    def test_post_error_with_no_response_text(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post_error_with_no_response_text(self, mock_request):
         ab = AuthenticationBase("auth0.com", "cid", telemetry=False)
 
         for error_status in [400, 500, None]:
-            mock_post.return_value.status_code = error_status
-            mock_post.return_value.text = None
+            mock_request.return_value.status_code = error_status
+            mock_request.return_value.text = None
 
             with self.assertRaises(Auth0Error) as context:
                 ab.post("the-url", data={"a": "b"}, headers={"c": "d"})
@@ -236,16 +242,17 @@ class TestBase(unittest.TestCase):
             self.assertEqual(context.exception.error_code, "a0.sdk.internal.unknown")
             self.assertEqual(context.exception.message, "")
 
-    @mock.patch("requests.get")
-    def test_get(self, mock_get):
+    @mock.patch("requests.request")
+    def test_get(self, mock_request):
         ab = AuthenticationBase("auth0.com", "cid", telemetry=False, timeout=(10, 2))
 
-        mock_get.return_value.status_code = 200
-        mock_get.return_value.text = '{"x": "y"}'
+        mock_request.return_value.status_code = 200
+        mock_request.return_value.text = '{"x": "y"}'
 
         data = ab.get("the-url", params={"a": "b"}, headers={"c": "d"})
 
-        mock_get.assert_called_with(
+        mock_request.assert_called_with(
+            "GET",
             "the-url",
             params={"a": "b"},
             headers={"c": "d", "Content-Type": "application/json"},
@@ -254,37 +261,38 @@ class TestBase(unittest.TestCase):
 
         self.assertEqual(data, {"x": "y"})
 
-    @mock.patch("requests.get")
-    def test_get_with_defaults(self, mock_get):
+    @mock.patch("requests.request")
+    def test_get_with_defaults(self, mock_request):
         ab = AuthenticationBase("auth0.com", "cid", telemetry=False)
 
-        mock_get.return_value.status_code = 200
-        mock_get.return_value.text = '{"x": "y"}'
+        mock_request.return_value.status_code = 200
+        mock_request.return_value.text = '{"x": "y"}'
 
         # Only required params are passed
         data = ab.get("the-url")
 
-        mock_get.assert_called_with(
+        mock_request.assert_called_with(
+            "GET",
             "the-url",
-            params=None,
             headers={"Content-Type": "application/json"},
             timeout=5.0,
         )
 
         self.assertEqual(data, {"x": "y"})
 
-    @mock.patch("requests.get")
-    def test_get_includes_telemetry(self, mock_get):
+    @mock.patch("requests.request")
+    def test_get_includes_telemetry(self, mock_request):
         ab = AuthenticationBase("auth0.com", "cid")
 
-        mock_get.return_value.status_code = 200
-        mock_get.return_value.text = '{"x": "y"}'
+        mock_request.return_value.status_code = 200
+        mock_request.return_value.text = '{"x": "y"}'
 
         data = ab.get("the-url", params={"a": "b"}, headers={"c": "d"})
 
-        self.assertEqual(mock_get.call_count, 1)
-        call_args, call_kwargs = mock_get.call_args
-        self.assertEqual(call_args[0], "the-url")
+        self.assertEqual(mock_request.call_count, 1)
+        call_args, call_kwargs = mock_request.call_args
+        self.assertEqual(call_args[0], "GET")
+        self.assertEqual(call_args[1], "the-url")
         self.assertEqual(call_kwargs["params"], {"a": "b"})
         headers = call_kwargs["headers"]
         self.assertEqual(headers["c"], "d")
diff --git a/auth0/test/management/test_branding.py b/auth0/test/management/test_branding.py
index fd2c858..daf2ac7 100644
--- a/auth0/test/management/test_branding.py
+++ b/auth0/test/management/test_branding.py
@@ -59,7 +59,7 @@ class TestBranding(unittest.TestCase):
             "https://domain/api/v2/branding/templates/universal-login",
         )
 
-    @mock.patch("auth0.rest.requests.put")
+    @mock.patch("auth0.rest.requests.request")
     def test_update_template_universal_login(self, mock_rc):
         mock_rc.return_value.status_code = 200
         mock_rc.return_value.text = "{}"
@@ -68,6 +68,7 @@ class TestBranding(unittest.TestCase):
         branding.update_template_universal_login({"a": "b", "c": "d"})
 
         mock_rc.assert_called_with(
+            "PUT",
             "https://domain/api/v2/branding/templates/universal-login",
             json={"template": {"a": "b", "c": "d"}},
             headers=mock.ANY,
diff --git a/auth0/test/management/test_rest.py b/auth0/test/management/test_rest.py
index 125ea92..7113c44 100644
--- a/auth0/test/management/test_rest.py
+++ b/auth0/test/management/test_rest.py
@@ -4,8 +4,6 @@ import sys
 import unittest
 from unittest import mock
 
-import requests
-
 from auth0.rest import RestClient, RestClientOptions
 
 from ...exceptions import Auth0Error, RateLimitError
@@ -135,117 +133,119 @@ class TestRest(unittest.TestCase):
     #     with self.assertRaises(requests.exceptions.Timeout):
     #         rc.delete("https://google.com")
 
-    @mock.patch("requests.get")
-    def test_get_custom_timeout(self, mock_get):
+    @mock.patch("requests.request")
+    def test_get_custom_timeout(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False, timeout=(10, 2))
         headers = {
             "Authorization": "Bearer a-token",
             "Content-Type": "application/json",
         }
-        mock_get.return_value.text = '["a", "b"]'
-        mock_get.return_value.status_code = 200
+        mock_request.return_value.text = '["a", "b"]'
+        mock_request.return_value.status_code = 200
 
         rc.get("the-url")
-        mock_get.assert_called_with(
-            "the-url", params=None, headers=headers, timeout=(10, 2)
+        mock_request.assert_called_with(
+            "GET", "the-url", headers=headers, timeout=(10, 2)
         )
 
-    @mock.patch("requests.post")
-    def test_post_custom_timeout(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post_custom_timeout(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False, timeout=(10, 2))
         headers = {
             "Authorization": "Bearer a-token",
             "Content-Type": "application/json",
         }
-        mock_post.return_value.text = '["a", "b"]'
-        mock_post.return_value.status_code = 200
+        mock_request.return_value.text = '["a", "b"]'
+        mock_request.return_value.status_code = 200
 
         rc.post("the-url")
-        mock_post.assert_called_with(
-            "the-url", json=None, headers=headers, timeout=(10, 2)
+        mock_request.assert_called_with(
+            "POST", "the-url", headers=headers, timeout=(10, 2)
         )
 
-    @mock.patch("requests.put")
-    def test_put_custom_timeout(self, mock_put):
+    @mock.patch("requests.request")
+    def test_put_custom_timeout(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False, timeout=(10, 2))
         headers = {
             "Authorization": "Bearer a-token",
             "Content-Type": "application/json",
         }
-        mock_put.return_value.text = '["a", "b"]'
-        mock_put.return_value.status_code = 200
+        mock_request.return_value.text = '["a", "b"]'
+        mock_request.return_value.status_code = 200
 
         rc.put("the-url")
-        mock_put.assert_called_with(
-            "the-url", json=None, headers=headers, timeout=(10, 2)
+        mock_request.assert_called_with(
+            "PUT", "the-url", headers=headers, timeout=(10, 2)
         )
 
-    @mock.patch("requests.patch")
-    def test_patch_custom_timeout(self, mock_patch):
+    @mock.patch("requests.request")
+    def test_patch_custom_timeout(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False, timeout=(10, 2))
         headers = {
             "Authorization": "Bearer a-token",
             "Content-Type": "application/json",
         }
-        mock_patch.return_value.text = '["a", "b"]'
-        mock_patch.return_value.status_code = 200
+        mock_request.return_value.text = '["a", "b"]'
+        mock_request.return_value.status_code = 200
 
         rc.patch("the-url")
-        mock_patch.assert_called_with(
-            "the-url", json=None, headers=headers, timeout=(10, 2)
+        mock_request.assert_called_with(
+            "PATCH", "the-url", headers=headers, timeout=(10, 2)
         )
 
-    @mock.patch("requests.delete")
-    def test_delete_custom_timeout(self, mock_delete):
+    @mock.patch("requests.request")
+    def test_delete_custom_timeout(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False, timeout=(10, 2))
         headers = {
             "Authorization": "Bearer a-token",
             "Content-Type": "application/json",
         }
-        mock_delete.return_value.text = '["a", "b"]'
-        mock_delete.return_value.status_code = 200
+        mock_request.return_value.text = '["a", "b"]'
+        mock_request.return_value.status_code = 200
 
         rc.delete("the-url")
-        mock_delete.assert_called_with(
-            "the-url", params={}, json=None, headers=headers, timeout=(10, 2)
+        mock_request.assert_called_with(
+            "DELETE", "the-url", headers=headers, timeout=(10, 2)
         )
 
-    @mock.patch("requests.get")
-    def test_get(self, mock_get):
+    @mock.patch("requests.request")
+    def test_get(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False)
         headers = {
             "Authorization": "Bearer a-token",
             "Content-Type": "application/json",
         }
 
-        mock_get.return_value.text = '["a", "b"]'
-        mock_get.return_value.status_code = 200
+        mock_request.return_value.text = '["a", "b"]'
+        mock_request.return_value.status_code = 200
 
         response = rc.get("the-url")
-        mock_get.assert_called_with(
-            "the-url", params=None, headers=headers, timeout=5.0
-        )
+        mock_request.assert_called_with("GET", "the-url", headers=headers, timeout=5.0)
 
         self.assertEqual(response, ["a", "b"])
 
         response = rc.get(url="the/url", params={"A": "param", "B": "param"})
-        mock_get.assert_called_with(
-            "the/url", params={"A": "param", "B": "param"}, headers=headers, timeout=5.0
+        mock_request.assert_called_with(
+            "GET",
+            "the/url",
+            params={"A": "param", "B": "param"},
+            headers=headers,
+            timeout=5.0,
         )
         self.assertEqual(response, ["a", "b"])
 
-        mock_get.return_value.text = ""
+        mock_request.return_value.text = ""
         response = rc.get("the/url")
         self.assertEqual(response, "")
 
-    @mock.patch("requests.get")
-    def test_get_errors(self, mock_get):
+    @mock.patch("requests.request")
+    def test_get_errors(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False)
 
-        mock_get.return_value.text = (
+        mock_request.return_value.text = (
             '{"statusCode": 999, "errorCode": "code", "message": "message"}'
         )
-        mock_get.return_value.status_code = 999
+        mock_request.return_value.status_code = 999
 
         with self.assertRaises(Auth0Error) as context:
             rc.get("the/url")
@@ -254,17 +254,17 @@ class TestRest(unittest.TestCase):
         self.assertEqual(context.exception.error_code, "code")
         self.assertEqual(context.exception.message, "message")
 
-    @mock.patch("requests.get")
-    def test_get_rate_limit_error(self, mock_get):
+    @mock.patch("requests.request")
+    def test_get_rate_limit_error(self, mock_request):
         options = RestClientOptions(telemetry=False, retries=0)
         rc = RestClient(jwt="a-token", options=options)
         rc._skip_sleep = True
 
-        mock_get.return_value.text = (
+        mock_request.return_value.text = (
             '{"statusCode": 429, "errorCode": "code", "message": "message"}'
         )
-        mock_get.return_value.status_code = 429
-        mock_get.return_value.headers = {
+        mock_request.return_value.status_code = 429
+        mock_request.return_value.headers = {
             "x-ratelimit-limit": "3",
             "x-ratelimit-remaining": "6",
             "x-ratelimit-reset": "9",
@@ -281,17 +281,17 @@ class TestRest(unittest.TestCase):
 
         self.assertEqual(rc._metrics["retries"], 0)
 
-    @mock.patch("requests.get")
-    def test_get_rate_limit_error_without_headers(self, mock_get):
+    @mock.patch("requests.request")
+    def test_get_rate_limit_error_without_headers(self, mock_request):
         options = RestClientOptions(telemetry=False, retries=1)
         rc = RestClient(jwt="a-token", options=options)
 
-        mock_get.return_value.text = (
+        mock_request.return_value.text = (
             '{"statusCode": 429, "errorCode": "code", "message": "message"}'
         )
-        mock_get.return_value.status_code = 429
+        mock_request.return_value.status_code = 429
 
-        mock_get.return_value.headers = {}
+        mock_request.return_value.headers = {}
         with self.assertRaises(Auth0Error) as context:
             rc.get("the/url")
 
@@ -303,17 +303,17 @@ class TestRest(unittest.TestCase):
 
         self.assertEqual(rc._metrics["retries"], 1)
 
-    @mock.patch("requests.get")
-    def test_get_rate_limit_custom_retries(self, mock_get):
+    @mock.patch("requests.request")
+    def test_get_rate_limit_custom_retries(self, mock_request):
         options = RestClientOptions(telemetry=False, retries=5)
         rc = RestClient(jwt="a-token", options=options)
         rc._skip_sleep = True
 
-        mock_get.return_value.text = (
+        mock_request.return_value.text = (
             '{"statusCode": 429, "errorCode": "code", "message": "message"}'
         )
-        mock_get.return_value.status_code = 429
-        mock_get.return_value.headers = {
+        mock_request.return_value.status_code = 429
+        mock_request.return_value.headers = {
             "x-ratelimit-limit": "3",
             "x-ratelimit-remaining": "6",
             "x-ratelimit-reset": "9",
@@ -331,17 +331,17 @@ class TestRest(unittest.TestCase):
         self.assertEqual(rc._metrics["retries"], 5)
         self.assertEqual(rc._metrics["retries"], len(rc._metrics["backoff"]))
 
-    @mock.patch("requests.get")
-    def test_get_rate_limit_invalid_retries_below_min(self, mock_get):
+    @mock.patch("requests.request")
+    def test_get_rate_limit_invalid_retries_below_min(self, mock_request):
         options = RestClientOptions(telemetry=False, retries=-1)
         rc = RestClient(jwt="a-token", options=options)
         rc._skip_sleep = True
 
-        mock_get.return_value.text = (
+        mock_request.return_value.text = (
             '{"statusCode": 429, "errorCode": "code", "message": "message"}'
         )
-        mock_get.return_value.status_code = 429
-        mock_get.return_value.headers = {
+        mock_request.return_value.status_code = 429
+        mock_request.return_value.headers = {
             "x-ratelimit-limit": "3",
             "x-ratelimit-remaining": "6",
             "x-ratelimit-reset": "9",
@@ -358,17 +358,17 @@ class TestRest(unittest.TestCase):
 
         self.assertEqual(rc._metrics["retries"], 0)
 
-    @mock.patch("requests.get")
-    def test_get_rate_limit_invalid_retries_above_max(self, mock_get):
+    @mock.patch("requests.request")
+    def test_get_rate_limit_invalid_retries_above_max(self, mock_request):
         options = RestClientOptions(telemetry=False, retries=11)
         rc = RestClient(jwt="a-token", options=options)
         rc._skip_sleep = True
 
-        mock_get.return_value.text = (
+        mock_request.return_value.text = (
             '{"statusCode": 429, "errorCode": "code", "message": "message"}'
         )
-        mock_get.return_value.status_code = 429
-        mock_get.return_value.headers = {
+        mock_request.return_value.status_code = 429
+        mock_request.return_value.headers = {
             "x-ratelimit-limit": "3",
             "x-ratelimit-remaining": "6",
             "x-ratelimit-reset": "9",
@@ -385,17 +385,17 @@ class TestRest(unittest.TestCase):
 
         self.assertEqual(rc._metrics["retries"], rc.MAX_REQUEST_RETRIES())
 
-    @mock.patch("requests.get")
-    def test_get_rate_limit_retries_use_exponential_backoff(self, mock_get):
+    @mock.patch("requests.request")
+    def test_get_rate_limit_retries_use_exponential_backoff(self, mock_request):
         options = RestClientOptions(telemetry=False, retries=10)
         rc = RestClient(jwt="a-token", options=options)
         rc._skip_sleep = True
 
-        mock_get.return_value.text = (
+        mock_request.return_value.text = (
             '{"statusCode": 429, "errorCode": "code", "message": "message"}'
         )
-        mock_get.return_value.status_code = 429
-        mock_get.return_value.headers = {
+        mock_request.return_value.status_code = 429
+        mock_request.return_value.headers = {
             "x-ratelimit-limit": "3",
             "x-ratelimit-remaining": "6",
             "x-ratelimit-reset": "9",
@@ -473,32 +473,52 @@ class TestRest(unittest.TestCase):
         # Ensure total delay sum is never more than 10s.
         self.assertLessEqual(finalBackoff, 10000)
 
-    @mock.patch("requests.post")
-    def test_post(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post_rate_limit_retries(self, mock_request):
+        options = RestClientOptions(telemetry=False, retries=10)
+        rc = RestClient(jwt="a-token", options=options)
+        rc._skip_sleep = True
+
+        mock_request.return_value.text = (
+            '{"statusCode": 429, "errorCode": "code", "message": "message"}'
+        )
+        mock_request.return_value.status_code = 429
+
+        with self.assertRaises(Auth0Error) as context:
+            rc.post("the/url")
+
+        self.assertEqual(context.exception.status_code, 429)
+
+        self.assertEqual(len(rc._metrics["backoff"]), 10)
+
+    @mock.patch("requests.request")
+    def test_post(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False)
         headers = {
             "Authorization": "Bearer a-token",
             "Content-Type": "application/json",
         }
 
-        mock_post.return_value.text = '{"a": "b"}'
+        mock_request.return_value.text = '{"a": "b"}'
 
         data = {"some": "data"}
 
-        mock_post.return_value.status_code = 200
+        mock_request.return_value.status_code = 200
         response = rc.post("the/url", data=data)
-        mock_post.assert_called_with("the/url", json=data, headers=headers, timeout=5.0)
+        mock_request.assert_called_with(
+            "POST", "the/url", json=data, headers=headers, timeout=5.0
+        )
 
         self.assertEqual(response, {"a": "b"})
 
-    @mock.patch("requests.post")
-    def test_post_errors(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post_errors(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False)
 
-        mock_post.return_value.text = (
+        mock_request.return_value.text = (
             '{"statusCode": 999, "errorCode": "code", "message": "message"}'
         )
-        mock_post.return_value.status_code = 999
+        mock_request.return_value.status_code = 999
 
         with self.assertRaises(Auth0Error) as context:
             rc.post("the-url")
@@ -507,14 +527,14 @@ class TestRest(unittest.TestCase):
         self.assertEqual(context.exception.error_code, "code")
         self.assertEqual(context.exception.message, "message")
 
-    @mock.patch("requests.post")
-    def test_post_errors_with_no_message_property(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post_errors_with_no_message_property(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False)
 
-        mock_post.return_value.text = json.dumps(
+        mock_request.return_value.text = json.dumps(
             {"statusCode": 999, "errorCode": "code", "error": "error"}
         )
-        mock_post.return_value.status_code = 999
+        mock_request.return_value.status_code = 999
 
         with self.assertRaises(Auth0Error) as context:
             rc.post("the-url")
@@ -523,14 +543,14 @@ class TestRest(unittest.TestCase):
         self.assertEqual(context.exception.error_code, "code")
         self.assertEqual(context.exception.message, "error")
 
-    @mock.patch("requests.post")
-    def test_post_errors_with_no_message_or_error_property(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post_errors_with_no_message_or_error_property(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False)
 
-        mock_post.return_value.text = json.dumps(
+        mock_request.return_value.text = json.dumps(
             {"statusCode": 999, "errorCode": "code"}
         )
-        mock_post.return_value.status_code = 999
+        mock_request.return_value.status_code = 999
 
         with self.assertRaises(Auth0Error) as context:
             rc.post("the-url")
@@ -539,11 +559,11 @@ class TestRest(unittest.TestCase):
         self.assertEqual(context.exception.error_code, "code")
         self.assertEqual(context.exception.message, "")
 
-    @mock.patch("requests.post")
-    def test_post_errors_with_message_and_error_property(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post_errors_with_message_and_error_property(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False)
 
-        mock_post.return_value.text = json.dumps(
+        mock_request.return_value.text = json.dumps(
             {
                 "statusCode": 999,
                 "errorCode": "code",
@@ -551,7 +571,7 @@ class TestRest(unittest.TestCase):
                 "message": "message",
             }
         )
-        mock_post.return_value.status_code = 999
+        mock_request.return_value.status_code = 999
 
         with self.assertRaises(Auth0Error) as context:
             rc.post("the-url")
@@ -560,13 +580,13 @@ class TestRest(unittest.TestCase):
         self.assertEqual(context.exception.error_code, "code")
         self.assertEqual(context.exception.message, "message")
 
-    @mock.patch("requests.post")
-    def test_post_error_with_code_property(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post_error_with_code_property(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False)
 
         for error_status in [400, 500, None]:
-            mock_post.return_value.status_code = error_status
-            mock_post.return_value.text = '{"errorCode": "e0","message": "desc"}'
+            mock_request.return_value.status_code = error_status
+            mock_request.return_value.text = '{"errorCode": "e0","message": "desc"}'
 
             with self.assertRaises(Auth0Error) as context:
                 rc.post("the-url")
@@ -575,13 +595,13 @@ class TestRest(unittest.TestCase):
             self.assertEqual(context.exception.error_code, "e0")
             self.assertEqual(context.exception.message, "desc")
 
-    @mock.patch("requests.post")
-    def test_post_error_with_no_error_code(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post_error_with_no_error_code(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False)
 
         for error_status in [400, 500, None]:
-            mock_post.return_value.status_code = error_status
-            mock_post.return_value.text = '{"message": "desc"}'
+            mock_request.return_value.status_code = error_status
+            mock_request.return_value.text = '{"message": "desc"}'
 
             with self.assertRaises(Auth0Error) as context:
                 rc.post("the-url")
@@ -590,13 +610,13 @@ class TestRest(unittest.TestCase):
             self.assertEqual(context.exception.error_code, "a0.sdk.internal.unknown")
             self.assertEqual(context.exception.message, "desc")
 
-    @mock.patch("requests.post")
-    def test_post_error_with_text_response(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post_error_with_text_response(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False)
 
         for error_status in [400, 500, None]:
-            mock_post.return_value.status_code = error_status
-            mock_post.return_value.text = "there has been a terrible error"
+            mock_request.return_value.status_code = error_status
+            mock_request.return_value.text = "there has been a terrible error"
 
             with self.assertRaises(Auth0Error) as context:
                 rc.post("the-url")
@@ -607,13 +627,13 @@ class TestRest(unittest.TestCase):
                 context.exception.message, "there has been a terrible error"
             )
 
-    @mock.patch("requests.post")
-    def test_post_error_with_no_response_text(self, mock_post):
+    @mock.patch("requests.request")
+    def test_post_error_with_no_response_text(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False)
 
         for error_status in [400, 500, None]:
-            mock_post.return_value.status_code = error_status
-            mock_post.return_value.text = None
+            mock_request.return_value.status_code = error_status
+            mock_request.return_value.text = None
 
             with self.assertRaises(Auth0Error) as context:
                 rc.post("the-url")
@@ -622,48 +642,50 @@ class TestRest(unittest.TestCase):
             self.assertEqual(context.exception.error_code, "a0.sdk.internal.unknown")
             self.assertEqual(context.exception.message, "")
 
-    @mock.patch("requests.post")
-    def test_file_post_content_type_is_none(self, mock_post):
+    @mock.patch("requests.request")
+    def test_file_post_content_type_is_none(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False)
         headers = {"Authorization": "Bearer a-token"}
-        mock_post.return_value.status_code = 200
-        mock_post.return_value.text = "Success"
+        mock_request.return_value.status_code = 200
+        mock_request.return_value.text = "Success"
 
         data = {"some": "data"}
         files = [mock.Mock()]
 
         rc.file_post("the-url", data=data, files=files)
 
-        mock_post.assert_called_once_with(
-            "the-url", data=data, files=files, headers=headers, timeout=5.0
+        mock_request.assert_called_once_with(
+            "POST", "the-url", data=data, files=files, headers=headers, timeout=5.0
         )
 
-    @mock.patch("requests.put")
-    def test_put(self, mock_put):
+    @mock.patch("requests.request")
+    def test_put(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False)
         headers = {
             "Authorization": "Bearer a-token",
             "Content-Type": "application/json",
         }
 
-        mock_put.return_value.text = '["a", "b"]'
-        mock_put.return_value.status_code = 200
+        mock_request.return_value.text = '["a", "b"]'
+        mock_request.return_value.status_code = 200
 
         data = {"some": "data"}
 
         response = rc.put(url="the-url", data=data)
-        mock_put.assert_called_with("the-url", json=data, headers=headers, timeout=5.0)
+        mock_request.assert_called_with(
+            "PUT", "the-url", json=data, headers=headers, timeout=5.0
+        )
 
         self.assertEqual(response, ["a", "b"])
 
-    @mock.patch("requests.put")
-    def test_put_errors(self, mock_put):
+    @mock.patch("requests.request")
+    def test_put_errors(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False)
 
-        mock_put.return_value.text = (
+        mock_request.return_value.text = (
             '{"statusCode": 999, "errorCode": "code", "message": "message"}'
         )
-        mock_put.return_value.status_code = 999
+        mock_request.return_value.status_code = 999
 
         with self.assertRaises(Auth0Error) as context:
             rc.put(url="the/url")
@@ -672,34 +694,34 @@ class TestRest(unittest.TestCase):
         self.assertEqual(context.exception.error_code, "code")
         self.assertEqual(context.exception.message, "message")
 
-    @mock.patch("requests.patch")
-    def test_patch(self, mock_patch):
+    @mock.patch("requests.request")
+    def test_patch(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False)
         headers = {
             "Authorization": "Bearer a-token",
             "Content-Type": "application/json",
         }
 
-        mock_patch.return_value.text = '["a", "b"]'
-        mock_patch.return_value.status_code = 200
+        mock_request.return_value.text = '["a", "b"]'
+        mock_request.return_value.status_code = 200
 
         data = {"some": "data"}
 
         response = rc.patch(url="the-url", data=data)
-        mock_patch.assert_called_with(
-            "the-url", json=data, headers=headers, timeout=5.0
+        mock_request.assert_called_with(
+            "PATCH", "the-url", json=data, headers=headers, timeout=5.0
         )
 
         self.assertEqual(response, ["a", "b"])
 
-    @mock.patch("requests.patch")
-    def test_patch_errors(self, mock_patch):
+    @mock.patch("requests.request")
+    def test_patch_errors(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False)
 
-        mock_patch.return_value.text = (
+        mock_request.return_value.text = (
             '{"statusCode": 999, "errorCode": "code", "message": "message"}'
         )
-        mock_patch.return_value.status_code = 999
+        mock_request.return_value.status_code = 999
 
         with self.assertRaises(Auth0Error) as context:
             rc.patch(url="the/url")
@@ -708,53 +730,58 @@ class TestRest(unittest.TestCase):
         self.assertEqual(context.exception.error_code, "code")
         self.assertEqual(context.exception.message, "message")
 
-    @mock.patch("requests.delete")
-    def test_delete(self, mock_delete):
+    @mock.patch("requests.request")
+    def test_delete(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False)
         headers = {
             "Authorization": "Bearer a-token",
             "Content-Type": "application/json",
         }
 
-        mock_delete.return_value.text = '["a", "b"]'
-        mock_delete.return_value.status_code = 200
+        mock_request.return_value.text = '["a", "b"]'
+        mock_request.return_value.status_code = 200
 
         response = rc.delete(url="the-url/ID")
-        mock_delete.assert_called_with(
-            "the-url/ID", headers=headers, params={}, json=None, timeout=5.0
+        mock_request.assert_called_with(
+            "DELETE", "the-url/ID", headers=headers, timeout=5.0
         )
 
         self.assertEqual(response, ["a", "b"])
 
-    @mock.patch("requests.delete")
-    def test_delete_with_body_and_params(self, mock_delete):
+    @mock.patch("requests.request")
+    def test_delete_with_body_and_params(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False)
         headers = {
             "Authorization": "Bearer a-token",
             "Content-Type": "application/json",
         }
 
-        mock_delete.return_value.text = '["a", "b"]'
-        mock_delete.return_value.status_code = 200
+        mock_request.return_value.text = '["a", "b"]'
+        mock_request.return_value.status_code = 200
 
         data = {"some": "data"}
         params = {"A": "param", "B": "param"}
 
         response = rc.delete(url="the-url/ID", params=params, data=data)
-        mock_delete.assert_called_with(
-            "the-url/ID", headers=headers, params=params, json=data, timeout=5.0
+        mock_request.assert_called_with(
+            "DELETE",
+            "the-url/ID",
+            headers=headers,
+            params=params,
+            json=data,
+            timeout=5.0,
         )
 
         self.assertEqual(response, ["a", "b"])
 
-    @mock.patch("requests.delete")
-    def test_delete_errors(self, mock_delete):
+    @mock.patch("requests.request")
+    def test_delete_errors(self, mock_request):
         rc = RestClient(jwt="a-token", telemetry=False)
 
-        mock_delete.return_value.text = (
+        mock_request.return_value.text = (
             '{"statusCode": 999, "errorCode": "code", "message": "message"}'
         )
-        mock_delete.return_value.status_code = 999
+        mock_request.return_value.status_code = 999
 
         with self.assertRaises(Auth0Error) as context:
             rc.delete(url="the-url")
diff --git a/auth0/test_async/test_asyncify.py b/auth0/test_async/test_asyncify.py
index c133e3c..2c0317e 100644
--- a/auth0/test_async/test_asyncify.py
+++ b/auth0/test_async/test_asyncify.py
@@ -233,6 +233,20 @@ class TestAsyncify(unittest.TestCase):
         (a, b, c) = rest_client._metrics["backoff"]
         self.assertTrue(100 <= a < b < c <= 1000)
 
+    @pytest.mark.asyncio
+    @aioresponses()
+    async def test_rate_limit_post(self, mocked):
+        callback, mock = get_callback(status=429)
+        await mocked.post(clients, callback=callback)
+        await mocked.post(clients, callback=callback)
+        await mocked.post(clients, callback=callback)
+        await mocked.post(clients, payload=payload)
+        c = asyncify(Clients)(domain="example.com", token="jwt")
+        rest_client = c._async_client.client
+        rest_client._skip_sleep = True
+        self.assertEqual(await c.all_async(), payload)
+        self.assertEqual(3, mock.call_count)
+
     @pytest.mark.asyncio
     @aioresponses()
     async def test_timeout(self, mocked):