diff --git a/tests/test_client.py b/tests/test_client.py
index ccfc1df..70fbbf3 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -1,7 +1,4 @@
 # Copyright (C) 2015 Twitter, Inc.
-
-import pytest
-import requests_oauthlib
 import responses
 
 from tests.support import with_resource, with_fixture, characters
@@ -11,11 +8,12 @@
 from twitter_ads.cursor import Cursor
 from twitter_ads import API_VERSION
 
+
 @responses.activate
 def test_accounts_with_no_id():
     responses.add(responses.GET, with_resource('/' + API_VERSION + '/accounts'),
-                                 body=with_fixture('accounts_all'),
-                                 content_type='application/json')
+                  body=with_fixture('accounts_all'),
+                  content_type='application/json')
 
     client = Client(
         characters(40),
@@ -29,11 +27,12 @@ def test_accounts_with_no_id():
     assert isinstance(cursor, Cursor)
     assert cursor.count == 5
 
+
 @responses.activate
 def test_accounts_with_id():
     responses.add(responses.GET, with_resource('/' + API_VERSION + '/accounts/2iqph'),
-                                 body=with_fixture('accounts_load'),
-                                 content_type='application/json')
+                  body=with_fixture('accounts_load'),
+                  content_type='application/json')
 
     client = Client(
         characters(40),
@@ -46,3 +45,24 @@ def test_accounts_with_id():
     assert account is not None
     assert isinstance(account, Account)
     assert account.id == '2iqph'
+
+
+@responses.activate
+def test_accounts_with_options():
+
+    client = Client(
+        characters(40),
+        characters(40),
+        characters(40),
+        characters(40),
+        options={
+            'handle_rate_limit': True,
+            'retry_max': 1,
+            'retry_delay': 3000,
+            'retry_on_status': [404, 500, 503]
+        }
+    )
+
+    assert client is not None
+    assert isinstance(client, Client)
+    assert len(client.options) == 4
diff --git a/tests/test_rate_limit.py b/tests/test_rate_limit.py
index 6a992d9..3e89e05 100644
--- a/tests/test_rate_limit.py
+++ b/tests/test_rate_limit.py
@@ -1,5 +1,6 @@
 import responses
 import unittest
+import time
 
 from tests.support import with_resource, with_fixture, characters
 
@@ -10,6 +11,251 @@
 from twitter_ads.http import Request
 from twitter_ads.resource import Resource
 from twitter_ads import API_VERSION
+from twitter_ads.error import RateLimit
+
+
+@responses.activate
+def test_rate_limit_handle_with_retry_success_1(monkeypatch):
+    # scenario:
+    #  - 500 (retry) -> 429 (handle rate limit) -> 200 (end)
+    monkeypatch.setattr(time, 'sleep', lambda s: None)
+
+    responses.add(responses.GET,
+                  with_resource('/' + API_VERSION + '/accounts/2iqph'),
+                  body=with_fixture('accounts_load'),
+                  content_type='application/json')
+
+    responses.add(responses.GET,
+                  with_resource('/' + API_VERSION + '/accounts/2iqph/campaigns'),
+                  status=500,
+                  body=with_fixture('campaigns_all'),
+                  content_type='application/json',
+                  headers={
+                      'x-account-rate-limit-limit': '10000',
+                      'x-account-rate-limit-remaining': '0',
+                      'x-account-rate-limit-reset': '1546300800'
+                  })
+
+    responses.add(responses.GET,
+                  with_resource('/' + API_VERSION + '/accounts/2iqph/campaigns'),
+                  status=429,
+                  body=with_fixture('campaigns_all'),
+                  content_type='application/json',
+                  headers={
+                      'x-account-rate-limit-limit': '10000',
+                      'x-account-rate-limit-remaining': '0',
+                      'x-account-rate-limit-reset': str(int(time.time()) + 5)
+                  })
+
+    responses.add(responses.GET,
+                  with_resource('/' + API_VERSION + '/accounts/2iqph/campaigns'),
+                  status=200,
+                  body=with_fixture('campaigns_all'),
+                  content_type='application/json',
+                  headers={
+                      'x-account-rate-limit-limit': '10000',
+                      'x-account-rate-limit-remaining': '9999',
+                      'x-account-rate-limit-reset': '1546300800'
+                  })
+
+    client = Client(
+        characters(40),
+        characters(40),
+        characters(40),
+        characters(40),
+        options={
+            'handle_rate_limit': True,
+            'retry_max': 1,
+            'retry_delay': 3000,
+            'retry_on_status': [500]
+        }
+    )
+
+    account = Account.load(client, '2iqph')
+
+    cursor = Campaign.all(account)
+    assert len(responses.calls) == 4
+    assert cursor is not None
+    assert isinstance(cursor, Cursor)
+    assert cursor.rate_limit is None
+    assert cursor.account_rate_limit == '10000'
+    assert cursor.account_rate_limit_remaining == '9999'
+    assert cursor.account_rate_limit_reset == '1546300800'
+
+
+@responses.activate
+def test_rate_limit_handle_with_retry_success_2(monkeypatch):
+    # scenario:
+    #  - 429 (handle rate limit) -> 500 (retry) -> 200 (end)
+    monkeypatch.setattr(time, 'sleep', lambda s: None)
+
+    responses.add(responses.GET,
+                  with_resource('/' + API_VERSION + '/accounts/2iqph'),
+                  body=with_fixture('accounts_load'),
+                  content_type='application/json')
+
+    responses.add(responses.GET,
+                  with_resource('/' + API_VERSION + '/accounts/2iqph/campaigns'),
+                  status=429,
+                  body=with_fixture('campaigns_all'),
+                  content_type='application/json',
+                  headers={
+                      'x-account-rate-limit-limit': '10000',
+                      'x-account-rate-limit-remaining': '0',
+                      'x-account-rate-limit-reset': '1546300800'
+                  })
+
+    responses.add(responses.GET,
+                  with_resource('/' + API_VERSION + '/accounts/2iqph/campaigns'),
+                  status=500,
+                  body=with_fixture('campaigns_all'),
+                  content_type='application/json',
+                  headers={
+                      'x-account-rate-limit-limit': '10000',
+                      'x-account-rate-limit-remaining': '0',
+                      'x-account-rate-limit-reset': str(int(time.time()) + 5)
+                  })
+
+    responses.add(responses.GET,
+                  with_resource('/' + API_VERSION + '/accounts/2iqph/campaigns'),
+                  status=200,
+                  body=with_fixture('campaigns_all'),
+                  content_type='application/json',
+                  headers={
+                      'x-account-rate-limit-limit': '10000',
+                      'x-account-rate-limit-remaining': '9999',
+                      'x-account-rate-limit-reset': '1546300800'
+                  })
+
+    client = Client(
+        characters(40),
+        characters(40),
+        characters(40),
+        characters(40),
+        options={
+            'handle_rate_limit': True,
+            'retry_max': 1,
+            'retry_delay': 3000,
+            'retry_on_status': [500]
+        }
+    )
+
+    account = Account.load(client, '2iqph')
+
+    cursor = Campaign.all(account)
+    assert len(responses.calls) == 4
+    assert cursor is not None
+    assert isinstance(cursor, Cursor)
+    assert cursor.rate_limit is None
+    assert cursor.account_rate_limit == '10000'
+    assert cursor.account_rate_limit_remaining == '9999'
+    assert cursor.account_rate_limit_reset == '1546300800'
+
+
+@responses.activate
+def test_rate_limit_handle_success(monkeypatch):
+    monkeypatch.setattr(time, 'sleep', lambda s: None)
+
+    responses.add(responses.GET,
+                  with_resource('/' + API_VERSION + '/accounts/2iqph'),
+                  body=with_fixture('accounts_load'),
+                  content_type='application/json')
+
+    responses.add(responses.GET,
+                  with_resource('/' + API_VERSION + '/accounts/2iqph/campaigns'),
+                  status=429,
+                  body=with_fixture('campaigns_all'),
+                  content_type='application/json',
+                  headers={
+                      'x-account-rate-limit-limit': '10000',
+                      'x-account-rate-limit-remaining': '0',
+                      'x-account-rate-limit-reset': str(int(time.time()) + 5)
+                  })
+
+    responses.add(responses.GET,
+                  with_resource('/' + API_VERSION + '/accounts/2iqph/campaigns'),
+                  status=200,
+                  body=with_fixture('campaigns_all'),
+                  content_type='application/json',
+                  headers={
+                      'x-account-rate-limit-limit': '10000',
+                      'x-account-rate-limit-remaining': '9999',
+                      'x-account-rate-limit-reset': '1546300800'
+                  })
+
+    client = Client(
+        characters(40),
+        characters(40),
+        characters(40),
+        characters(40),
+        options={
+            'handle_rate_limit': True
+        }
+    )
+
+    account = Account.load(client, '2iqph')
+
+    cursor = Campaign.all(account)
+    assert len(responses.calls) == 3
+    assert cursor is not None
+    assert isinstance(cursor, Cursor)
+    assert cursor.rate_limit is None
+    assert cursor.account_rate_limit == '10000'
+    assert cursor.account_rate_limit_remaining == '9999'
+    assert cursor.account_rate_limit_reset == '1546300800'
+
+
+@responses.activate
+def test_rate_limit_handle_error(monkeypatch):
+    monkeypatch.setattr(time, 'sleep', lambda s: None)
+
+    responses.add(responses.GET,
+                  with_resource('/' + API_VERSION + '/accounts/2iqph'),
+                  body=with_fixture('accounts_load'),
+                  content_type='application/json')
+
+    responses.add(responses.GET,
+                  with_resource('/' + API_VERSION + '/accounts/2iqph/campaigns'),
+                  status=429,
+                  body=with_fixture('campaigns_all'),
+                  content_type='application/json',
+                  headers={
+                      'x-account-rate-limit-limit': '10000',
+                      'x-account-rate-limit-remaining': '0',
+                      'x-account-rate-limit-reset': str(int(time.time()) + 5)
+                  })
+
+    responses.add(responses.GET,
+                  with_resource('/' + API_VERSION + '/accounts/2iqph/campaigns'),
+                  status=429,
+                  body=with_fixture('campaigns_all'),
+                  content_type='application/json',
+                  headers={
+                      'x-account-rate-limit-limit': '10000',
+                      'x-account-rate-limit-remaining': '0',
+                      'x-account-rate-limit-reset': '1546300800'
+                  })
+
+    client = Client(
+        characters(40),
+        characters(40),
+        characters(40),
+        characters(40),
+        options={
+            'handle_rate_limit': True
+        }
+    )
+
+    account = Account.load(client, '2iqph')
+
+    try:
+        cursor = Campaign.all(account)
+    except Exception as e:
+        error = e
+        print(error)
+    assert len(responses.calls) == 3
+    assert isinstance(error, RateLimit)
+    assert error.reset_at == '1546300800'
 
 
 @responses.activate
diff --git a/tests/test_retry_count.py b/tests/test_retry_count.py
new file mode 100644
index 0000000..270126d
--- /dev/null
+++ b/tests/test_retry_count.py
@@ -0,0 +1,121 @@
+import responses
+import unittest
+import time
+
+from tests.support import with_resource, with_fixture, characters
+
+from twitter_ads.account import Account
+from twitter_ads.campaign import Campaign
+from twitter_ads.client import Client
+from twitter_ads.cursor import Cursor
+from twitter_ads import API_VERSION
+from twitter_ads.error import NotFound
+
+
+@responses.activate
+def test_retry_count_success(monkeypatch):
+    monkeypatch.setattr(time, 'sleep', lambda s: None)
+
+    responses.add(responses.GET,
+                  with_resource('/' + API_VERSION + '/accounts/2iqph'),
+                  body=with_fixture('accounts_load'),
+                  content_type='application/json')
+
+    responses.add(responses.GET,
+                  with_resource('/' + API_VERSION + '/accounts/2iqph/campaigns'),
+                  status=404,
+                  body=with_fixture('campaigns_all'),
+                  content_type='application/json',
+                  headers={
+                      'x-account-rate-limit-limit': '10000',
+                      'x-account-rate-limit-remaining': '0',
+                      'x-account-rate-limit-reset': str(int(time.time()) + 5)
+                  })
+
+    responses.add(responses.GET,
+                  with_resource('/' + API_VERSION + '/accounts/2iqph/campaigns'),
+                  status=200,
+                  body=with_fixture('campaigns_all'),
+                  content_type='application/json',
+                  headers={
+                      'x-account-rate-limit-limit': '10000',
+                      'x-account-rate-limit-remaining': '9999',
+                      'x-account-rate-limit-reset': '1546300800'
+                  })
+
+    client = Client(
+        characters(40),
+        characters(40),
+        characters(40),
+        characters(40),
+        options={
+            'retry_max': 1,
+            'retry_delay': 3000,
+            'retry_on_status': [404, 500, 503]
+        }
+    )
+
+    account = Account.load(client, '2iqph')
+
+    cursor = Campaign.all(account)
+    assert len(responses.calls) == 3
+    assert cursor is not None
+    assert isinstance(cursor, Cursor)
+    assert cursor.rate_limit is None
+    assert cursor.account_rate_limit == '10000'
+    assert cursor.account_rate_limit_remaining == '9999'
+    assert cursor.account_rate_limit_reset == '1546300800'
+
+
+@responses.activate
+def test_retry_count_error(monkeypatch):
+    monkeypatch.setattr(time, 'sleep', lambda s: None)
+
+    responses.add(responses.GET,
+                  with_resource('/' + API_VERSION + '/accounts/2iqph'),
+                  body=with_fixture('accounts_load'),
+                  content_type='application/json')
+
+    responses.add(responses.GET,
+                  with_resource('/' + API_VERSION + '/accounts/2iqph/campaigns'),
+                  status=404,
+                  body=with_fixture('campaigns_all'),
+                  content_type='application/json',
+                  headers={
+                      'x-account-rate-limit-limit': '10000',
+                      'x-account-rate-limit-remaining': '0',
+                      'x-account-rate-limit-reset': str(int(time.time()) + 5)
+                  })
+
+    responses.add(responses.GET,
+                  with_resource('/' + API_VERSION + '/accounts/2iqph/campaigns'),
+                  status=404,
+                  body=with_fixture('campaigns_all'),
+                  content_type='application/json',
+                  headers={
+                      'x-account-rate-limit-limit': '10000',
+                      'x-account-rate-limit-remaining': '9999',
+                      'x-account-rate-limit-reset': '1546300800'
+                  })
+
+    client = Client(
+        characters(40),
+        characters(40),
+        characters(40),
+        characters(40),
+        options={
+            'retry_max': 1,
+            'retry_delay': 3000,
+            'retry_on_status': [404, 500, 503]
+        }
+    )
+
+    account = Account.load(client, '2iqph')
+
+    try:
+        cursor = Campaign.all(account)
+    except Exception as e:
+        error = e
+        print(error)
+    assert len(responses.calls) == 3
+    assert isinstance(error, NotFound)
diff --git a/twitter_ads/client.py b/twitter_ads/client.py
index 433d1f7..6b91a5c 100644
--- a/twitter_ads/client.py
+++ b/twitter_ads/client.py
@@ -28,7 +28,7 @@ def __init__(self,
         self._consumer_secret = consumer_secret
         self._access_token = access_token
         self._access_token_secret = access_token_secret
-        self._options = kwargs
+        self._options = kwargs.get('options', {})
 
     def __repr__(self):
         return '<{name} object at {mem} consumer_key={key}>'.format(
@@ -37,6 +37,11 @@ def __repr__(self):
             key=getattr(self, 'consumer_key')
         )
 
+    @property
+    def options(self):
+        """Returns the options value."""
+        return self._options
+
     @property
     def consumer_key(self):
         """Returns the consumer_key value."""
diff --git a/twitter_ads/error.py b/twitter_ads/error.py
index 8d84205..65df9f6 100644
--- a/twitter_ads/error.py
+++ b/twitter_ads/error.py
@@ -72,17 +72,13 @@ class RateLimit(ClientError):
 
     def __init__(self, response, **kwargs):
         super(RateLimit, self).__init__(response, **kwargs)
-        self._retry_after = response.headers.get('retry-after', None)
-        self._reset_at = response.headers.get('rate_limit_reset', None)
+        self._reset_at = response.headers.get('x-account-rate-limit-reset')\
+            or response.headers.get('x-rate-limit-reset')
 
     @property
     def reset_at(self):
         return self._reset_at
 
-    @property
-    def retry_after(self):
-        return self._retry_after
-
 
 class ServerError(Error):
     """Server Error (500)."""
diff --git a/twitter_ads/http.py b/twitter_ads/http.py
index 23d6db9..c49a434 100644
--- a/twitter_ads/http.py
+++ b/twitter_ads/http.py
@@ -5,8 +5,10 @@
 import sys
 import platform
 import logging
+logger = logging.getLogger(__name__)
 import json
 import zlib
+import time
 
 if sys.version_info[0] != 3:
     import httplib
@@ -77,6 +79,13 @@ def __oauth_request(self):
         files = self.options.get('files', None)
         stream = self.options.get('stream', False)
 
+        handle_rate_limit = self._client.options.get('handle_rate_limit', False)
+        retry_max = self._client.options.get('retry_max', 0)
+        retry_delay = self._client.options.get('retry_delay', 1500)
+        retry_on_status = self._client.options.get('retry_on_status', [500, 503])
+        retry_count = 0
+        retry_after = None
+
         consumer = OAuth1Session(
             self._client.consumer_key,
             client_secret=self._client.consumer_secret,
@@ -86,8 +95,30 @@ def __oauth_request(self):
         url = self.__domain() + self._resource
         method = getattr(consumer, self._method)
 
-        response = method(url, headers=headers, data=data, params=params,
-                          files=files, stream=stream)
+        while (retry_count <= retry_max):
+            response = method(url, headers=headers, data=data, params=params,
+                              files=files, stream=stream)
+            # do not retry on 2XX status code
+            if 200 <= response.status_code < 300:
+                break
+
+            if handle_rate_limit and retry_after is None:
+                rate_limit_reset = response.headers.get('x-account-rate-limit-reset') \
+                    or response.headers.get('x-rate-limit-reset')
+
+                if response.status_code == 429:
+                    retry_after = int(rate_limit_reset) - int(time.time())
+                    logger.warning("Request reached Rate Limit: resume in %d seconds"
+                                   % retry_after)
+                    time.sleep(retry_after + 5)
+                    continue
+
+            if retry_max > 0:
+                if response.status_code not in retry_on_status:
+                    break
+                time.sleep(int(retry_delay) / 1000)
+
+            retry_count += 1
 
         raw_response_body = response.raw.read() if stream else response.text
 
