diff --git a/mwclient/client.py b/mwclient/client.py
index dff61e9e194e10eabbb9011999321ffb6acdcb28..98e060c3071463adff210c94e1aecc2ff9f0292c 100644
--- a/mwclient/client.py
+++ b/mwclient/client.py
@@ -131,7 +131,7 @@ class Site(object):
     def site_init(self):
 
         if self.initialized:
-            info = self.api('query', meta='userinfo', uiprop='groups|rights')
+            info = self.get('query', meta='userinfo', uiprop='groups|rights')
             userinfo = info['query']['userinfo']
             self.username = userinfo['name']
             self.groups = userinfo.get('groups', [])
@@ -139,7 +139,7 @@ class Site(object):
             self.tokens = {}
             return
 
-        meta = self.api('query', meta='siteinfo|userinfo',
+        meta = self.get('query', meta='siteinfo|userinfo',
                         siprop='general|namespaces', uiprop='groups|rights',
                         retry_on_error=False)
 
@@ -214,7 +214,29 @@ class Site(object):
     def __repr__(self):
         return "<Site object '%s%s'>" % (self.host, self.path)
 
-    def api(self, action, *args, **kwargs):
+    def get(self, action, *args, **kwargs):
+        """Perform a generic API call using GET.
+
+        This is just a shorthand for calling api() with http_method='GET'.
+        All arguments will be passed on.
+
+        Returns:
+            The raw response from the API call, as a dictionary.
+        """
+        return self.api(action, 'GET', *args, **kwargs)
+
+    def post(self, action, *args, **kwargs):
+        """Perform a generic API call using POST.
+
+        This is just a shorthand for calling api() with http_method='POST'.
+        All arguments will be passed on.
+
+        Returns:
+            The raw response from the API call, as a dictionary.
+        """
+        return self.api(action, 'POST', *args, **kwargs)
+
+    def api(self, action, http_method='POST', *args, **kwargs):
         """Perform a generic API call and handle errors.
 
         All arguments will be passed on.
@@ -252,7 +274,7 @@ class Site(object):
         sleeper = self.sleepers.make()
 
         while True:
-            info = self.raw_api(action, **kwargs)
+            info = self.raw_api(action, http_method, **kwargs)
             if not info:
                 info = {}
             if self.handle_api_result(info, sleeper=sleeper):
@@ -291,7 +313,7 @@ class Site(object):
         qs2 = [(k, v) for k, v in six.iteritems(kwargs) if k in {'wpEditToken', 'token'}]
         return OrderedDict(qs1 + qs2)
 
-    def raw_call(self, script, data, files=None, retry_on_error=True):
+    def raw_call(self, script, data, files=None, retry_on_error=True, http_method='POST'):
         """
         Perform a generic request and return the raw text.
 
@@ -312,22 +334,28 @@ class Site(object):
         Returns:
             The raw text response.
         """
-        url = self.path + script + self.ext
         headers = {}
         if self.compress and gzip:
             headers['Accept-Encoding'] = 'gzip'
         sleeper = self.sleepers.make((script, data))
-        while True:
-            scheme = 'https'
-            host = self.host
-            if isinstance(host, (list, tuple)):
-                scheme, host = host
 
-            fullurl = '{scheme}://{host}{url}'.format(scheme=scheme, host=host, url=url)
+        scheme = 'https'
+        host = self.host
+        if isinstance(host, (list, tuple)):
+            scheme, host = host
+
+        url = '{scheme}://{host}{path}{script}{ext}'.format(scheme=scheme, host=host,
+                                                            path=self.path, script=script,
+                                                            ext=self.ext)
 
+        while True:
             try:
-                stream = self.connection.post(fullurl, data=data, files=files,
-                                              headers=headers, **self.requests)
+                if http_method == 'GET':
+                    stream = self.connection.get(url, params=data, files=files,
+                                                 headers=headers, **self.requests)
+                else:
+                    stream = self.connection.post(url, data=data, files=files,
+                                                  headers=headers, **self.requests)
                 if stream.headers.get('x-database-lag'):
                     wait_time = int(stream.headers.get('retry-after'))
                     log.warning('Database lag exceeds max lag. '
@@ -355,7 +383,7 @@ class Site(object):
                 log.warning('Connection error. Retrying in a moment.')
                 sleeper.sleep()
 
-    def raw_api(self, action, *args, **kwargs):
+    def raw_api(self, action, http_method='POST', *args, **kwargs):
         """Send a call to the API."""
         try:
             retry_on_error = kwargs.pop('retry_on_error')
@@ -364,7 +392,8 @@ class Site(object):
         kwargs['action'] = action
         kwargs['format'] = 'json'
         data = self._query_string(*args, **kwargs)
-        res = self.raw_call('api', data, retry_on_error=retry_on_error)
+        res = self.raw_call('api', data, retry_on_error=retry_on_error,
+                            http_method=http_method)
 
         try:
             return json.loads(res)
@@ -373,12 +402,12 @@ class Site(object):
                 raise errors.APIDisabledError
             raise errors.InvalidResponse(res)
 
-    def raw_index(self, action, *args, **kwargs):
-        """Send a call to index.php rather than the API."""
+    def raw_index(self, action, http_method='POST', *args, **kwargs):
+        """Sends a call to index.php rather than the API."""
         kwargs['action'] = action
         kwargs['maxlag'] = self.max_lag
         data = self._query_string(*args, **kwargs)
-        return self.raw_call('index', data)
+        return self.raw_call('index', data, http_method=http_method)
 
     def require(self, major, minor, revision=None, raise_error=True):
         if self.version is None:
@@ -428,8 +457,8 @@ class Site(object):
         token = self.get_token('email')
 
         try:
-            info = self.api('emailuser', target=user, subject=subject,
-                            text=text, ccme=cc, token=token)
+            info = self.post('emailuser', target=user, subject=subject,
+                             text=text, ccme=cc, token=token)
         except errors.APIError as e:
             if e.args[0] == u'noemail':
                 raise errors.NoSpecifiedEmail(user, e.args[1])
@@ -454,7 +483,7 @@ class Site(object):
             if self.credentials[2]:
                 kwargs['lgdomain'] = self.credentials[2]
             while True:
-                login = self.api('login', **kwargs)
+                login = self.post('login', **kwargs)
                 if login['login']['result'] == 'Success':
                     break
                 elif login['login']['result'] == 'NeedToken':
@@ -480,15 +509,15 @@ class Site(object):
         if self.tokens.get(type, '0') == '0' or force:
 
             if self.version[:2] >= (1, 24):
-                info = self.api('query', meta='tokens', type=type)
+                info = self.post('query', meta='tokens', type=type)
                 self.tokens[type] = info['query']['tokens']['%stoken' % type]
 
             else:
                 if title is None:
                     # Some dummy title was needed to get a token prior to 1.24
                     title = 'Test'
-                info = self.api('query', titles=title,
-                                prop='info', intoken=type)
+                info = self.post('query', titles=title,
+                                 prop='info', intoken=type)
                 for i in six.itervalues(info['query']['pages']):
                     if i['title'] == title:
                         self.tokens[type] = i['%stoken' % type]
@@ -608,7 +637,7 @@ class Site(object):
             kwargs['redirects'] = '1'
         if mobileformat:
             kwargs['mobileformat'] = '1'
-        result = self.api('parse', **kwargs)
+        result = self.get('parse', **kwargs)
         return result['parse']
 
     # def block(self): TODO?
@@ -813,7 +842,7 @@ class Site(object):
             kwargs['rvdiffto'] = diffto
 
         revisions = []
-        pages = self.api('query', **kwargs).get('query', {}).get('pages', {}).values()
+        pages = self.get('query', **kwargs).get('query', {}).get('pages', {}).values()
         for page in pages:
             for revision in page.get('revisions', ()):
                 revision['pageid'] = page.get('pageid')
@@ -902,7 +931,7 @@ class Site(object):
         if generatexml:
             kwargs['generatexml'] = '1'
 
-        result = self.api('expandtemplates', text=text, **kwargs)
+        result = self.get('expandtemplates', text=text, **kwargs)
 
         if generatexml:
             return result['expandtemplates']['*'], result['parsetree']['*']
diff --git a/mwclient/listing.py b/mwclient/listing.py
index b612c2c8c3db711c1c1598b8c5ca7cb897a403f0..34d4d72fd6d8a72fb9f05beb189360cea05edfd2 100644
--- a/mwclient/listing.py
+++ b/mwclient/listing.py
@@ -86,7 +86,7 @@ class List(object):
 
         Else, set `self.last` to True.
         """
-        data = self.site.api(
+        data = self.site.get(
             'query', (self.generator, self.list_name),
             *[(text_type(k), v) for k, v in six.iteritems(self.args)]
         )
diff --git a/mwclient/page.py b/mwclient/page.py
index 7d6d071e3881e753fc06ea5191cd1c79eacc86cf..54c763ce07ea10b5144af67e14d5c05244755306 100644
--- a/mwclient/page.py
+++ b/mwclient/page.py
@@ -28,10 +28,10 @@ class Page(object):
                 extra_props = ()
 
             if type(name) is int:
-                info = self.site.api('query', prop=prop, pageids=name,
+                info = self.site.get('query', prop=prop, pageids=name,
                                      inprop='protection', *extra_props)
             else:
-                info = self.site.api('query', prop=prop, titles=name,
+                info = self.site.get('query', prop=prop, titles=name,
                                      inprop='protection', *extra_props)
             info = six.next(six.itervalues(info['query']['pages']))
         self._info = info
@@ -63,7 +63,7 @@ class Page(object):
 
     def redirects_to(self):
         """ Returns the redirect target page, or None if the page is not a redirect page."""
-        info = self.site.api('query', prop='pageprops', titles=self.name, redirects='')['query']
+        info = self.site.get('query', prop='pageprops', titles=self.name, redirects='')['query']
         if 'redirects' in info:
             for page in info['redirects']:
                 if page['from'] == self.name:
@@ -206,9 +206,9 @@ class Page(object):
         data.update(kwargs)
 
         def do_edit():
-            result = self.site.api('edit', title=self.name, text=text,
-                                   summary=summary, token=self.get_token('edit'),
-                                   **data)
+            result = self.site.post('edit', title=self.name, text=text,
+                                    summary=summary, token=self.get_token('edit'),
+                                    **data)
             if result['edit'].get('result').lower() == 'failure':
                 raise mwclient.errors.EditError(self, result['edit'])
             return result
@@ -264,8 +264,8 @@ class Page(object):
             data['movetalk'] = '1'
         if no_redirect:
             data['noredirect'] = '1'
-        result = self.site.api('move', ('from', self.name), to=new_title,
-                               token=self.get_token('move'), reason=reason, **data)
+        result = self.site.post('move', ('from', self.name), to=new_title,
+                                token=self.get_token('move'), reason=reason, **data)
         return result['move']
 
     def delete(self, reason='', watch=False, unwatch=False, oldimage=False):
@@ -288,9 +288,9 @@ class Page(object):
             data['unwatch'] = '1'
         if oldimage:
             data['oldimage'] = oldimage
-        result = self.site.api('delete', title=self.name,
-                               token=self.get_token('delete'),
-                               reason=reason, **data)
+        result = self.site.post('delete', title=self.name,
+                                token=self.get_token('delete'),
+                                reason=reason, **data)
         return result['delete']
 
     def purge(self):
diff --git a/tests/test_client.py b/tests/test_client.py
index 2bf3847920274d0e8b100e1f3d8a7d0608499d19..bcf7e0310578466a92454b1cb2323465843fca7c 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -45,12 +45,13 @@ class TestCase(unittest.TestCase):
         return json.dumps(self.metaResponse(**kwargs))
 
     def httpShouldReturn(self, body=None, callback=None, scheme='https', host='test.wikipedia.org', path='/w/',
-                         script='api', headers=None, status=200):
+                         script='api', headers=None, status=200, method='GET'):
         url = '{scheme}://{host}{path}{script}.php'.format(scheme=scheme, host=host, path=path, script=script)
+        mock = responses.GET if method == 'GET' else responses.POST
         if body is None:
-            responses.add_callback(responses.POST, url, callback=callback)
+            responses.add_callback(mock, url, callback=callback)
         else:
-            responses.add(responses.POST, url, body=body, content_type='application/json',
+            responses.add(mock, url, body=body, content_type='application/json',
                           adding_headers=headers, status=status)
 
     def stdSetup(self):
@@ -105,7 +106,7 @@ class TestClient(TestCase):
         site = mwclient.Site('test.wikipedia.org')
 
         assert len(responses.calls) == 1
-        assert responses.calls[0].request.method == 'POST'
+        assert responses.calls[0].request.method == 'GET'
 
     @responses.activate
     def test_max_lag(self):
@@ -134,18 +135,6 @@ class TestClient(TestCase):
         with pytest.raises(requests.exceptions.HTTPError):
             site = mwclient.Site('test.wikipedia.org')
 
-    @responses.activate
-    def test_headers(self):
-        # Content-type should be 'application/x-www-form-urlencoded'
-
-        self.httpShouldReturn(self.metaResponseAsJson(), scheme='https')
-
-        site = mwclient.Site('test.wikipedia.org')
-
-        assert len(responses.calls) == 1
-        assert 'content-type' in responses.calls[0].request.headers
-        assert responses.calls[0].request.headers['content-type'] == 'application/x-www-form-urlencoded'
-
     @responses.activate
     def test_force_http(self):
         # Setting http should work
@@ -173,8 +162,8 @@ class TestClient(TestCase):
 
         site = mwclient.Site('test.wikipedia.org')
 
-        assert 'action=query' in responses.calls[0].request.body
-        assert 'meta=siteinfo%7Cuserinfo' in responses.calls[0].request.body
+        assert 'action=query' in responses.calls[0].request.url
+        assert 'meta=siteinfo%7Cuserinfo' in responses.calls[0].request.url
 
     @responses.activate
     def test_httpauth_defaults_to_basic_auth(self):
@@ -249,6 +238,19 @@ class TestClient(TestCase):
 
     # ----- Use standard setup for rest
 
+    @responses.activate
+    def test_headers(self):
+        # Content-type should be 'application/x-www-form-urlencoded' for POST requests
+
+        site = self.stdSetup()
+
+        self.httpShouldReturn('{}', method='POST')
+        site.post('purge', title='Main Page')
+
+        assert len(responses.calls) == 1
+        assert 'content-type' in responses.calls[0].request.headers
+        assert responses.calls[0].request.headers['content-type'] == 'application/x-www-form-urlencoded'
+
     @responses.activate
     def test_raw_index(self):
         # Initializing the client should result in one request
@@ -256,7 +258,7 @@ class TestClient(TestCase):
         site = self.stdSetup()
 
         self.httpShouldReturn('Some data', script='index')
-        site.raw_index(action='purge', title='Main Page')
+        site.raw_index(action='purge', title='Main Page', http_method='GET')
 
         assert len(responses.calls) == 1
 
@@ -272,7 +274,7 @@ class TestClient(TestCase):
                 'info': 'Assertion that the user is logged in failed',
                 '*': 'See https://en.wikipedia.org/w/api.php for API usage'
             }
-        }))
+        }), method='POST')
         with pytest.raises(mwclient.errors.APIError) as excinfo:
             site.api(action='edit', title='Wikipedia:Sandbox')
 
@@ -351,8 +353,8 @@ class TestClientApiMethods(TestCase):
         call_args = self.api.call_args_list
 
         assert len(call_args) == 3
-        assert call_args[1] == mock.call('login', lgname='myusername', lgpassword='mypassword')
-        assert call_args[2] == mock.call('login', lgname='myusername', lgpassword='mypassword', lgtoken=login_token)
+        assert call_args[1] == mock.call('login', 'POST', lgname='myusername', lgpassword='mypassword')
+        assert call_args[2] == mock.call('login', 'POST', lgname='myusername', lgpassword='mypassword', lgtoken=login_token)
 
 
 class TestClientUploadArgs(TestCase):
diff --git a/tests/test_listing.py b/tests/test_listing.py
index 749649ed390c5d1b31cf07bbfb72fde9d3cc46a4..f1d5e84b04de87b410351bdf0402fbca5a707059 100644
--- a/tests/test_listing.py
+++ b/tests/test_listing.py
@@ -30,7 +30,7 @@ class TestList(unittest.TestCase):
     def setupDummyResponses(self, mock_site, result_member, ns=None):
         if ns is None:
             ns = [0, 0, 0]
-        mock_site.api.side_effect = [
+        mock_site.get.side_effect = [
             {
                 'continue': {
                     'apcontinue': 'Kre_Mbaye',
diff --git a/tests/test_page.py b/tests/test_page.py
index c2228eacbe4c6f1ace5771d821bca21d7f18ce3b..d7babe51b678b5e2ba3e8f2848721c4ddce34e28 100644
--- a/tests/test_page.py
+++ b/tests/test_page.py
@@ -9,6 +9,7 @@ import responses
 import mock
 import mwclient
 from mwclient.page import Page
+from mwclient.client import Site
 
 try:
     import json
@@ -29,23 +30,23 @@ class TestPage(unittest.TestCase):
 
     @mock.patch('mwclient.client.Site')
     def test_api_call_on_page_init(self, mock_site):
-        # Check that site.api() is called once on Page init
+        # Check that site.get() is called once on Page init
 
         title = 'Some page'
-        mock_site.api.return_value = {
+        mock_site.get.return_value = {
             'query': {'pages': {'1': {}}}
         }
         page = Page(mock_site, title)
 
-        # test that Page called site.api with the right parameters
-        mock_site.api.assert_called_once_with('query', inprop='protection', titles=title, prop='info')
+        # test that Page called site.get with the right parameters
+        mock_site.get.assert_called_once_with('query', inprop='protection', titles=title, prop='info')
 
     @mock.patch('mwclient.client.Site')
     def test_nonexisting_page(self, mock_site):
         # Check that API response results in page.exists being set to False
 
         title = 'Some nonexisting page'
-        mock_site.api.return_value = {
+        mock_site.get.return_value = {
             'query': {'pages': {'-1': {'missing': ''}}}
         }
         page = Page(mock_site, title)
@@ -57,7 +58,7 @@ class TestPage(unittest.TestCase):
         # Check that API response results in page.exists being set to True
 
         title = 'Norge'
-        mock_site.api.return_value = {
+        mock_site.get.return_value = {
             'query': {'pages': {'728': {}}}
         }
         page = Page(mock_site, title)
@@ -69,7 +70,7 @@ class TestPage(unittest.TestCase):
         # Check that variouse page props are read correctly from API response
 
         title = 'Some page'
-        mock_site.api.return_value = {
+        mock_site.get.return_value = {
             'query': {
                 'pages': {
                     '728': {
@@ -102,7 +103,7 @@ class TestPage(unittest.TestCase):
         # If page is protected, check that protection is parsed correctly
 
         title = 'Some page'
-        mock_site.api.return_value = {
+        mock_site.get.return_value = {
             'query': {
                 'pages': {
                     '728': {
@@ -146,7 +147,7 @@ class TestPage(unittest.TestCase):
         # Check that page.redirect is set correctly
 
         title = 'Some redirect page'
-        mock_site.api.return_value = {
+        mock_site.get.return_value = {
             "query": {
                 "pages": {
                     "796917": {
@@ -177,11 +178,11 @@ class TestPage(unittest.TestCase):
         mock_site.rights = ['read', 'edit']
 
         title = 'Norge'
-        mock_site.api.return_value = {
+        mock_site.get.return_value = {
             'query': {'pages': {'728': {'protection': []}}}
         }
         page = Page(mock_site, title)
-        mock_site.api.return_value = {
+        mock_site.post.return_value = {
             'edit': {'result': 'Failure', 'captcha': {
                 'type': 'math',
                 'mime': 'text/tex',
@@ -205,17 +206,17 @@ class TestPageApiArgs(unittest.TestCase):
         MockSite = mock.patch('mwclient.client.Site').start()
         self.site = MockSite()
 
-        self.site.api.return_value = {'query': {'pages': {'1': {'title': title}}}}
+        self.site.get.return_value = {'query': {'pages': {'1': {'title': title}}}}
         self.site.rights = ['read']
 
         self.page = Page(self.site, title)
 
-        self.site.api.return_value = {'query': {'pages': {'2': {
+        self.site.get.return_value = {'query': {'pages': {'2': {
             'ns': 0, 'pageid': 2, 'revisions': [{'*': 'Hello world', 'timestamp': '2014-08-29T22:25:15Z'}], 'title': title
         }}}}
 
     def get_last_api_call_args(self):
-        args, kwargs = self.site.api.call_args
+        args, kwargs = self.site.get.call_args
         action = args[0]
         args = args[1:]
         kwargs.update(args)