Repository: plivo/plivo-python (language: python)

Issue:
AsynchronousFlow



Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3f7b278c..d1216eec 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Change Log
 
+## [4.24.1](https://github.com/plivo/plivo-python/tree/v4.24.1) (2022-05-16)
+**Bug Fix - Asynchronous Flow Added**
+- `callback_url` and `callback_method` added in API's [Asynchronous requests](https://www.plivo.com/docs/voice/api/request#asynchronous-request)
+
 ## [4.24.0](https://github.com/plivo/plivo-python/tree/v4.24.0) (2022-05-05)
 **Feature - List all recordings and The MultiPartyCall element**
 - `from_number` and `to_number` added to filtering param [List all recordings](https://www.plivo.com/docs/voice/api/recording#list-all-recordings)
diff --git a/plivo/resources/applications.py b/plivo/resources/applications.py
index 9d791619..c6c609f5 100644
--- a/plivo/resources/applications.py
+++ b/plivo/resources/applications.py
@@ -58,7 +58,10 @@ class Applications(PlivoResourceInterface):
         default_endpoint_app=[optional(of_type_exact(bool))],
         subaccount=[optional(is_subaccount())],
         log_incoming_messages=[optional(of_type_exact(bool))],
-        public_uri=[optional(of_type_exact(bool))])
+        public_uri=[optional(of_type_exact(bool))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
     def create(self,
                app_name,
                answer_url=None,
@@ -73,17 +76,27 @@ def create(self,
                default_endpoint_app=False,
                subaccount=None,
                log_incoming_messages=True,
-               public_uri=None):
+               public_uri=None,
+               callback_url=None,
+               callback_method=None):
 
         if subaccount:
             if isinstance(subaccount, Subaccount):
                 subaccount = subaccount.id
         return self.client.request('POST', ('Application', ), to_param_dict(self.create, locals()), is_voice_request=True)
 
-    @validate_args(app_id=[of_type(six.text_type)])
-    def get(self, app_id):
-        return self.client.request(
-            'GET', ('Application', app_id), response_type=Application, is_voice_request=True)
+    @validate_args(app_id=[of_type(six.text_type)],
+                   callback_url=[optional(is_url())],
+                   callback_method=[optional(of_type(six.text_type))],
+                   )
+    def get(self, app_id, callback_url=None, callback_method=None):
+        if not callback_url:
+            return self.client.request(
+                'GET', ('Application', app_id), response_type=Application, is_voice_request=True)
+        else:
+            return self.client.request(
+                'GET', ('Application', app_id), to_param_dict(self.get, locals()),
+                response_type=Application, is_voice_request=True)
 
     @validate_args(
         subaccount=[optional(is_subaccount())],
@@ -98,16 +111,26 @@ def get(self, app_id):
                 all_of(
                     of_type(*six.integer_types),
                     check(lambda offset: 0 <= offset, '0 <= offset')))
-        ])
-    def list(self, subaccount=None, limit=20, offset=0):
+        ],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def list(self, subaccount=None, limit=20, offset=0, callback_url=None, callback_method=None):
         if subaccount:
             if isinstance(subaccount, Subaccount):
                 subaccount = subaccount.id
-        return self.client.request(
-            'GET', ('Application', ),
-            to_param_dict(self.list, locals()),
-            response_type=ListResponseObject,
-            objects_type=Application, is_voice_request=True)
+
+        if not callback_url:
+            return self.client.request(
+                'GET', ('Application',),
+                to_param_dict(self.list, locals()),
+                response_type=ListResponseObject,
+                objects_type=Application, is_voice_request=True)
+        else:
+            return self.client.request(
+                'GET', ('Application',),
+                to_param_dict(self.list, locals()),
+                objects_type=Application, is_voice_request=True)
 
     @validate_args(
         app_id=[of_type(six.text_type)],
@@ -123,7 +146,10 @@ def list(self, subaccount=None, limit=20, offset=0):
         default_endpoint_app=[optional(of_type_exact(bool))],
         subaccount=[optional(is_subaccount())],
         log_incoming_messages=[optional(of_type_exact(bool))],
-        public_uri=[optional(of_type_exact(bool))])
+        public_uri=[optional(of_type_exact(bool))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
     def update(self,
                app_id,
                answer_url=None,
@@ -138,7 +164,10 @@ def update(self,
                default_endpoint_app=False,
                subaccount=None,
                log_incoming_messages=True,
-               public_uri=None):
+               public_uri=None,
+               callback_url=None,
+               callback_method=None
+               ):
         if subaccount:
             if isinstance(subaccount, Subaccount):
                 subaccount = subaccount.id
@@ -149,27 +178,30 @@ def update(self,
             'self': self,
             'answer_url': answer_url,
             'answer_method': answer_method,
-            'hangup_url' : hangup_url,
-            'hangup_method' : hangup_method,
-            'fallback_answer_url' : fallback_answer_url,
-            'fallback_method' : fallback_method,
-            'message_url' : message_url,
-            'message_method' : message_method,
-            'default_number_app' : default_number_app,
-            'default_endpoint_app' : default_endpoint_app,
-            'subaccount' : subaccount,
-            'log_incoming_messages' : log_incoming_messages,
-            'public_uri' : public_uri
+            'hangup_url': hangup_url,
+            'hangup_method': hangup_method,
+            'fallback_answer_url': fallback_answer_url,
+            'fallback_method': fallback_method,
+            'message_url': message_url,
+            'message_method': message_method,
+            'default_number_app': default_number_app,
+            'default_endpoint_app': default_endpoint_app,
+            'subaccount': subaccount,
+            'log_incoming_messages': log_incoming_messages,
+            'public_uri': public_uri,
+            'callback_url': callback_url,
+            'callback_method': callback_method
         }
-
         return self.client.request('POST', ('Application', app_id),
                                    to_param_dict(self.update, localVariablesObject), is_voice_request=True)
 
     @validate_args(
         app_id=[of_type(six.text_type)],
         new_endpoint_application=[optional(of_type(six.text_type))],
-        cascade=[optional(of_type_exact(bool))]
+        cascade=[optional(of_type_exact(bool))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
-    def delete(self, app_id, cascade=None, new_endpoint_application=None):
+    def delete(self, app_id, cascade=None, new_endpoint_application=None, callback_url=None, callback_method=None):
         return self.client.request('DELETE', ('Application', app_id),
                                    to_param_dict(self.delete, locals()), is_voice_request=True)
diff --git a/plivo/resources/calls.py b/plivo/resources/calls.py
index f4717e1c..150c9b93 100644
--- a/plivo/resources/calls.py
+++ b/plivo/resources/calls.py
@@ -129,6 +129,8 @@ class Calls(PlivoResourceInterface):
                 lambda ring_timeout: 0 <= ring_timeout,
                 message='0 <= ring_timeout')
         ],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
     def create(self,
                from_,
@@ -153,7 +155,9 @@ def create(self,
                sip_headers=None,
                ring_timeout=120,
                parent_call_uuid=None,
-               error_if_parent_not_found=False):
+               error_if_parent_not_found=False,
+               callback_url=None,
+               callback_method=None):
         if from_ in to_.split('<'):
             raise ValidationError('src and destination cannot overlap')
         return self.client.request('POST', ('Call', ), to_param_dict(self.create, locals()), is_voice_request=True)
@@ -187,7 +191,10 @@ def create(self,
         ],
         hangup_source=[
             optional(of_type(six.text_type))
-        ])
+        ],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
     def list(self,
              subaccount=None,
              call_direction=None,
@@ -208,18 +215,39 @@ def list(self,
              status=None,
              parent_call_uuid=None,
              hangup_cause_code=None,
-             hangup_source=None):
-        return self.client.request(
-            'GET',
-            ('Call', ),
-            to_param_dict(self.list, locals()),
-            response_type=ListResponseObject,
-            is_voice_request=True
-        )
+             hangup_source=None,
+             callback_url=None,
+             callback_method=None
+             ):
+        # Adding if else block because if we are fetching response without callback_url then response will be of type
+        # ListResponseObject, if passing callback_url then will be of type
+        # {'api_id': '94722e88-ae7c-11ec-b52e-0242ac11000a', 'message': 'async api spawned'}
+        if callback_url :
+            return self.client.request(
+                'GET',
+                ('Call',),
+                to_param_dict(self.list, locals()),
+                is_voice_request=True
+            )
+        else :
+            return self.client.request(
+                'GET',
+                ('Call',),
+                to_param_dict(self.list, locals()),
+                response_type=ListResponseObject,
+                is_voice_request=True
+            )
 
-    @validate_args(call_uuid=[of_type(six.text_type)])
-    def get(self, call_uuid):
-        return self.client.request('GET', ('Call', call_uuid), is_voice_request=True)
+    @validate_args(
+        call_uuid=[of_type(six.text_type)],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def get(self,
+            call_uuid,
+            callback_url=None,
+            callback_method=None):
+        return self.client.request('GET', ('Call', call_uuid), to_param_dict(self.get, locals()), is_voice_request=True)
 
     @validate_args(
         call_uuid=[of_type(six.text_type)],
@@ -236,24 +264,35 @@ def update(self,
                aleg_url=None,
                aleg_method=None,
                bleg_url=None,
-               bleg_method=None):
+               bleg_method=None,
+               callback_url=None,
+               callback_method=None):
         return self.client.request('POST', ('Call', call_uuid),
                                    to_param_dict(self.update, locals()), is_voice_request=True)
 
+    @validate_args(
+        call_uuid=[of_type(six.text_type)],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
     def transfer(self,
                  call_uuid,
                  legs=None,
                  aleg_url=None,
                  aleg_method=None,
                  bleg_url=None,
-                 bleg_method=None):
+                 bleg_method=None,
+                 callback_url=None,
+                 callback_method=None):
         return self.update(
             call_uuid,
             legs=legs,
             aleg_method=aleg_method,
             aleg_url=aleg_url,
             bleg_url=bleg_url,
-            bleg_method=bleg_method)
+            bleg_method=bleg_method,
+            callback_url=callback_url,
+            callback_method=callback_method)
 
     @validate_args(call_uuid=[of_type(six.text_type)])
     def record(self,
@@ -282,12 +321,15 @@ def start_recording(self,
                                    to_param_dict(self.start_recording,
                                                  locals()), is_voice_request=True)
 
-    def record_stop(self, call_uuid):
-        return self.client.calls.stop_recording(call_uuid)
+    def record_stop(self, call_uuid, callback_url=None, callback_method=None):
+        return self.client.calls.stop_recording(call_uuid, callback_url, callback_method)
 
-    @validate_args(call_uuid=[of_type(six.text_type)])
-    def stop_recording(self, call_uuid):
-        return self.client.request('DELETE', ('Call', call_uuid, 'Record'), is_voice_request=True)
+    @validate_args(call_uuid=[of_type(six.text_type)],
+                   callback_url=[optional(is_url())],
+                   callback_method=[optional(of_type(six.text_type))]
+                   )
+    def stop_recording(self, call_uuid, callback_url, callback_method):
+        return self.client.request('DELETE', ('Call', call_uuid, 'Record'), to_param_dict(self.stop_recording, locals()), is_voice_request=True)
 
     @validate_args(call_uuid=[of_type(six.text_type)])
     def play(self,
@@ -314,14 +356,20 @@ def start_playing(self,
         return self.client.request('POST', ('Call', call_uuid, 'Play'),
                                    to_param_dict(self.play, locals()), is_voice_request=True)
 
-    def play_stop(self, call_uuid):
-        return self.client.calls.stop_playing(call_uuid)
+    def play_stop(self, call_uuid, callback_url=None, callback_method=None):
+        return self.client.calls.stop_playing(call_uuid, callback_url, callback_method)
 
-    @validate_args(call_uuid=[of_type(six.text_type)])
-    def stop_playing(self, call_uuid):
-        return self.client.request('DELETE', ('Call', call_uuid, 'Play'), is_voice_request=True)
+    @validate_args(call_uuid=[of_type(six.text_type)],
+                   callback_url=[optional(is_url())],
+                   callback_method=[optional(of_type(six.text_type))]
+                   )
+    def stop_playing(self, call_uuid, callback_url=None, callback_method=None):
+        return self.client.request('DELETE', ('Call', call_uuid, 'Play'), to_param_dict(self.stop_playing, locals()), is_voice_request=True)
 
-    @validate_args(call_uuid=[of_type(six.text_type)])
+    @validate_args(call_uuid=[of_type(six.text_type)],
+                   callback_url=[optional(is_url())],
+                   callback_method=[optional(of_type(six.text_type))],
+                   )
     def speak(self,
               call_uuid,
               text,
@@ -329,9 +377,12 @@ def speak(self,
               language=None,
               legs=None,
               loop=None,
-              mix=None):
+              mix=None,
+              callback_url=None,
+              callback_method=None
+              ):
         return self.start_speaking(call_uuid, text, voice, language, legs,
-                                   loop, mix)
+                                   loop, mix, callback_url, callback_method)
 
     @validate_args(call_uuid=[of_type(six.text_type)])
     def start_speaking(self,
@@ -341,26 +392,43 @@ def start_speaking(self,
                        language=None,
                        legs=None,
                        loop=None,
-                       mix=None):
+                       mix=None,
+                       callback_url=None,
+                       callback_method=None
+                       ):
         return self.client.request('POST', ('Call', call_uuid, 'Speak'),
                                    to_param_dict(self.start_speaking,
                                                  locals()), is_voice_request=True)
 
     @validate_args(call_uuid=[of_type(six.text_type)])
-    def stop_speaking(self, call_uuid):
-        return self.client.request('DELETE', ('Call', call_uuid, 'Speak'), is_voice_request=True)
+    def stop_speaking(self, call_uuid, callback_url=None, callback_method=None):
+        return self.client.request('DELETE', ('Call', call_uuid, 'Speak'), to_param_dict(self.stop_speaking, locals()), is_voice_request=True)
 
-    def speak_stop(self, call_uuid):
-        return self.client.calls.stop_speaking(call_uuid)
-
-    @validate_args(call_uuid=[of_type(six.text_type)])
-    def send_digits(self, call_uuid, digits, leg=None):
+    @validate_args(
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))]
+    )
+    def speak_stop(self, call_uuid, callback_url=None, callback_method=None):
+        return self.client.calls.stop_speaking(call_uuid, callback_url, callback_method)
+
+    @validate_args(call_uuid=[of_type(six.text_type)],
+                   callback_url=[optional(is_url())],
+                   callback_method=[optional(of_type(six.text_type))],
+                   )
+    def send_digits(self, call_uuid, digits, leg=None, callback_url=None, callback_method=None):
         return self.client.request('POST', ('Call', call_uuid, 'DTMF'),
                                    to_param_dict(self.send_digits, locals()), is_voice_request=True)
 
-    @validate_args(call_uuid=[of_type(six.text_type)])
-    def delete(self, call_uuid):
-        return self.client.request('DELETE', ('Call', call_uuid), is_voice_request=True)
+    @validate_args(
+        call_uuid=[of_type(six.text_type)],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def delete(self,
+               call_uuid,
+               callback_url=None,
+               callback_method=None):
+        return self.client.request('DELETE', ('Call', call_uuid), to_param_dict(self.delete, locals()), is_voice_request=True)
 
     @validate_args(call_uuid=[of_type(six.text_type)])
     def hangup(self, call_uuid):
diff --git a/plivo/resources/conferences.py b/plivo/resources/conferences.py
index f7538202..d246e38a 100644
--- a/plivo/resources/conferences.py
+++ b/plivo/resources/conferences.py
@@ -2,6 +2,8 @@
 """
 Conference class - along with its list class
 """
+from plivo.utils.validators import *
+from plivo.utils import to_param_dict
 
 from plivo.base import PlivoResource, PlivoResourceInterface
 from plivo.exceptions import InvalidRequestError
@@ -82,75 +84,143 @@ class Conferences(PlivoResourceInterface):
     _resource_type = Conference
     _iterable = False
 
-    def list(self):
-        return self.client.request('GET', ('Conference', ), is_voice_request=True)
-
-    def get(self, conference_name):
-        return self.client.request('GET', ('Conference', conference_name), is_voice_request=True)
-
-    def delete(self, conference_name):
-        return self.client.request('DELETE', ('Conference', conference_name), is_voice_request=True)
-
-    def delete_all(self):
-        return self.client.request('DELETE', ('Conference', ), is_voice_request=True)
-
-    def hangup_all(self):
-        return self.delete_all()
+    @validate_args(
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def list(self, callback_url=None, callback_method=None):
+        return self.client.request('GET', ('Conference', ), to_param_dict(self.list, locals()), is_voice_request=True)
+
+    @validate_args(
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def get(self, conference_name, callback_url=None, callback_method=None):
+        return self.client.request('GET', ('Conference', conference_name), to_param_dict(self.get, locals()),
+                                   is_voice_request=True)
+
+    @validate_args(
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def delete(self, conference_name, callback_url=None, callback_method=None):
+        return self.client.request('DELETE', ('Conference', conference_name), to_param_dict(self.delete, locals()),
+                                   is_voice_request=True)
+
+    @validate_args(
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def delete_all(self, callback_url=None, callback_method=None):
+        return self.client.request('DELETE', ('Conference', ), to_param_dict(self.delete_all, locals()),
+                                   is_voice_request=True)
+
+    @validate_args(
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def hangup_all(self, callback_url=None, callback_method=None):
+        return self.delete_all(callback_url, callback_method)
 
     def hangup(self, conference_name):
         return self.delete(conference_name)
 
+    @validate_args(
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
     def member_speak(self,
                      conference_name,
                      member_id,
                      text,
                      voice=None,
-                     language=None):
+                     language=None,
+                     callback_url=None,
+                     callback_method=None):
         return self.client.request(
             'POST',
             ('Conference', conference_name, 'Member', member_id, 'Speak'),
             to_param_dict(self.member_speak, locals()), is_voice_request=True)
 
-    def member_play(self, conference_name, member_id, url):
+    @validate_args(
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def member_play(self, conference_name, member_id, url, callback_url=None, callback_method=None):
         return self.client.request(
             'POST',
             ('Conference', conference_name, 'Member', member_id, 'Play'),
             to_param_dict(self.member_play, locals()), is_voice_request=True)
 
-    def member_deaf(self, conference_name, member_id):
+    @validate_args(
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def member_deaf(self, conference_name, member_id, callback_url=None, callback_method=None):
         return self.client.request(
             'POST',
-            ('Conference', conference_name, 'Member', member_id, 'Deaf'), is_voice_request=True)
-
-    def member_mute(self, conference_name, member_id):
+            ('Conference', conference_name, 'Member', member_id, 'Deaf'),
+            to_param_dict(self.member_deaf, locals()), is_voice_request=True)
+
+    @validate_args(
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def member_mute(self, conference_name, member_id, callback_url=None, callback_method=None):
         return self.client.request(
             'POST',
-            ('Conference', conference_name, 'Member', member_id, 'Mute'), is_voice_request=True)
-
-    def member_speak_stop(self, conference_name, member_id):
+            ('Conference', conference_name, 'Member', member_id, 'Mute'), to_param_dict(self.member_mute, locals()),
+            is_voice_request=True)
+
+    @validate_args(
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def member_speak_stop(self, conference_name, member_id, callback_url=None, callback_method=None):
         return self.client.request(
             'DELETE',
-            ('Conference', conference_name, 'Member', member_id, 'Speak'), is_voice_request=True)
+            ('Conference', conference_name, 'Member', member_id, 'Speak'),
+            to_param_dict(self.member_speak_stop, locals()), is_voice_request=True)
 
-    def member_play_stop(self, conference_name, member_id):
+    @validate_args(
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def member_play_stop(self, conference_name, member_id, callback_url=None, callback_method=None):
         return self.client.request(
             'DELETE',
-            ('Conference', conference_name, 'Member', member_id, 'Play'), is_voice_request=True)
+            ('Conference', conference_name, 'Member', member_id, 'Play'),
+            to_param_dict(self.member_play_stop, locals()), is_voice_request=True)
 
-    def member_deaf_stop(self, conference_name, member_id):
+    @validate_args(
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def member_deaf_stop(self, conference_name, member_id, callback_url=None, callback_method=None):
         return self.client.request(
             'DELETE',
-            ('Conference', conference_name, 'Member', member_id, 'Deaf'), is_voice_request=True)
-
-    def member_mute_stop(self, conference_name, member_id):
+            ('Conference', conference_name, 'Member', member_id, 'Deaf'),
+            to_param_dict(self.member_deaf_stop, locals()), is_voice_request=True)
+
+    @validate_args(
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def member_mute_stop(self, conference_name, member_id, callback_url=None, callback_method=None):
         return self.client.request(
             'DELETE',
-            ('Conference', conference_name, 'Member', member_id, 'Mute'), is_voice_request=True)
-
-    def member_kick(self, conference_name, member_id):
+            ('Conference', conference_name, 'Member', member_id, 'Mute'),
+            to_param_dict(self.member_mute_stop, locals()), is_voice_request=True)
+
+    @validate_args(
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def member_kick(self, conference_name, member_id, callback_url=None, callback_method=None):
         return self.client.request(
             'POST',
-            ('Conference', conference_name, 'Member', member_id, 'Kick'), is_voice_request=True)
+            ('Conference', conference_name, 'Member', member_id, 'Kick'),
+            to_param_dict(self.member_kick, locals()), is_voice_request=True)
 
     def member_hangup(self, conference_name, member_id):
         return self.client.request(
@@ -165,8 +235,14 @@ def record(self,
                callback_url=None,
                callback_method=None):
         return self.client.request('POST',
-                                   ('Conference', conference_name, 'Record'), to_param_dict(self.record, locals()), is_voice_request=True)
-
-    def record_stop(self, conference_name):
+                                   ('Conference', conference_name, 'Record'),
+                                   to_param_dict(self.record, locals()), is_voice_request=True)
+
+    @validate_args(
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def record_stop(self, conference_name, callback_url=None, callback_method=None):
         return self.client.request('DELETE',
-                                   ('Conference', conference_name, 'Record'), is_voice_request=True)
+                                   ('Conference', conference_name, 'Record'),
+                                   to_param_dict(self.record_stop, locals()), is_voice_request=True)
diff --git a/plivo/resources/endpoints.py b/plivo/resources/endpoints.py
index bea88d75..72557c00 100644
--- a/plivo/resources/endpoints.py
+++ b/plivo/resources/endpoints.py
@@ -29,14 +29,20 @@ class Endpoints(PlivoResourceInterface):
         username=[of_type(six.text_type)],
         password=[of_type(six.text_type)],
         alias=[of_type(six.text_type)],
-        app_id=[optional(of_type(six.text_type))])
-    def create(self, username, password, alias, app_id=None):
+        app_id=[optional(of_type(six.text_type))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def create(self, username, password, alias, app_id=None, callback_url=None, callback_method=None):
         return self.client.request('POST', ('Endpoint', ),
                                    to_param_dict(self.create, locals()), is_voice_request=True)
 
-    @validate_args(endpoint_id=[of_type(six.text_type)])
-    def get(self, endpoint_id):
-        return self.client.request('GET', ('Endpoint', endpoint_id), is_voice_request=True)
+    @validate_args(endpoint_id=[of_type(six.text_type)],
+                   callback_url=[optional(is_url())],
+                   callback_method=[optional(of_type(six.text_type))],
+                   )
+    def get(self, endpoint_id, callback_url=None, callback_method=None):
+        return self.client.request('GET', ('Endpoint', endpoint_id), to_param_dict(self.get, locals()), is_voice_request=True)
 
     @validate_args(
         limit=[
@@ -50,32 +56,52 @@ def get(self, endpoint_id):
                 all_of(
                     of_type(*six.integer_types),
                     check(lambda offset: 0 <= offset, '0 <= offset')))
-        ])
-    def list(self, limit=20, offset=0):
-        return self.client.request(
-            'GET',
-            ('Endpoint', ),
-            to_param_dict(self.list, locals()),
-            objects_type=Endpoint,
-            response_type=ListResponseObject, is_voice_request=True)
+        ],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def list(self, limit=20, offset=0, callback_url=None, callback_method=None):
+        if callback_url:
+            return self.client.request(
+                'GET',
+                ('Endpoint',),
+                to_param_dict(self.list, locals()),
+                objects_type=Endpoint, is_voice_request=True)
+        else:
+            return self.client.request(
+                'GET',
+                ('Endpoint',),
+                to_param_dict(self.list, locals()),
+                objects_type=Endpoint,
+                response_type=ListResponseObject, is_voice_request=True)
+
 
     @validate_args(
         endpoint_id=[of_type(six.text_type)],
         password=[optional(of_type(six.text_type))],
         alias=[optional(of_type(six.text_type))],
-        app_id=[optional(of_type(six.text_type))])
-    def update(self, endpoint_id, password=None, alias=None, app_id=None):
+        app_id=[optional(of_type(six.text_type))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def update(self, endpoint_id, password=None, alias=None, app_id=None, callback_url=None, callback_method=None):
 
         # not using locals() because we need to neglect endpoint_id
         temp = {
             'self': self,
             'password': password,
             'alias': alias,
-            'app_id': app_id
+            'app_id': app_id,
+            'callback_url': callback_url,
+            "callback_method": callback_method
         }
         return self.client.request('POST', ('Endpoint', endpoint_id),
                                    to_param_dict(self.update, temp), is_voice_request=True)
 
-    @validate_args(endpoint_id=[of_type(six.text_type)])
-    def delete(self, endpoint_id):
-        return self.client.request('DELETE', ('Endpoint', endpoint_id), is_voice_request=True)
+    @validate_args(endpoint_id=[of_type(six.text_type)],
+                   callback_url=[optional(is_url())],
+                   callback_method=[optional(of_type(six.text_type))],
+                   )
+    def delete(self, endpoint_id, callback_url=None, callback_method=None):
+        return self.client.request('DELETE', ('Endpoint', endpoint_id), to_param_dict(self.delete, locals()),
+                                   is_voice_request=True)
diff --git a/plivo/resources/live_calls.py b/plivo/resources/live_calls.py
index cb0b7aad..c57eb3a6 100644
--- a/plivo/resources/live_calls.py
+++ b/plivo/resources/live_calls.py
@@ -34,7 +34,9 @@ class LiveCalls(PlivoResourceInterface):
             optional(of_type(six.text_type), is_in(('inbound', 'outbound')))
         ],
         from_number=[optional(is_phonenumber())],
-        to_number=[optional(is_iterable(of_type(six.text_type), sep='<'))]
+        to_number=[optional(is_iterable(of_type(six.text_type), sep='<'))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
     def list_ids(self,
                  call_direction=None,
@@ -42,13 +44,26 @@ def list_ids(self,
                  to_number=None,
                  limit=20,
                  offset=0,
+                 callback_url=None,
+                 callback_method=None
                  ):
         params = to_param_dict(self.list_ids, locals())
         params.update({'status': 'live'})
         return self.client.request('GET', ('Call',), params, is_voice_request=True)
 
-    @validate_args(_id=[of_type(six.text_type)])
-    def get(self, _id):
+    @validate_args(_id=[of_type(six.text_type)],
+                   callback_url=[optional(is_url())],
+                   callback_method=[optional(of_type(six.text_type))])
+    def get(self,
+            _id,
+            callback_url=None,
+            callback_method=None):
+        local_object = {}
+        local_object['status'] = 'live'
+        if callback_url:
+            local_object['callback_url'] = callback_url
+        if callback_method:
+            local_object['callback_method'] = callback_method
         return self.client.request(
-            'GET', ('Call', _id), {'status': 'live'}, is_voice_request=True
+            'GET', ('Call', _id), local_object, is_voice_request=True
         )
diff --git a/plivo/resources/multipartycall.py b/plivo/resources/multipartycall.py
index fe46d3b8..620ea4c3 100644
--- a/plivo/resources/multipartycall.py
+++ b/plivo/resources/multipartycall.py
@@ -191,7 +191,9 @@ def __clean_identifiers(params):
         creation_time__lt=[optional(is_proper_date_format())],
         creation_time__lte=[optional(is_proper_date_format())],
         limit=[optional(of_type(int), check(lambda limit: 0 < limit <= 20, '0 < limit <= 20'))],
-        offset=[optional(of_type(int), check(lambda offset: 0 <= offset, '0 <= offset'))]
+        offset=[optional(of_type(int), check(lambda offset: 0 <= offset, '0 <= offset'))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
     def list(self,
              sub_account=None,
@@ -207,19 +209,35 @@ def list(self,
              creation_time__lt=None,
              creation_time__lte=None,
              limit=None,
-             offset=None
+             offset=None,
+             callback_url=None,
+             callback_method=None
              ):
-        return self.client.request('GET', ('MultiPartyCall',), to_param_dict(self.list, locals()),
-                                   response_type=ListResponseObject, objects_type=MultiPartyCall, is_voice_request=True)
+
+        if not callback_url:
+            return self.client.request('GET', ('MultiPartyCall',), to_param_dict(self.list, locals()),
+                                       response_type=ListResponseObject, objects_type=MultiPartyCall,
+                                       is_voice_request=True)
+        else:
+            return self.client.request('GET', ('MultiPartyCall',), to_param_dict(self.list, locals()),
+                                       objects_type=MultiPartyCall, is_voice_request=True)
 
     @validate_args(
         friendly_name=[optional(of_type_exact(str))],
         uuid=[optional(of_type_exact(str))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
-    def get(self, uuid=None, friendly_name=None):
+    def get(self, uuid=None, friendly_name=None, callback_url=None, callback_method=None):
         mpc_id = self.__make_mpc_id(friendly_name, uuid)
-        return self.client.request('GET', ('MultiPartyCall', mpc_id),
-                                   is_voice_request=True, response_type=MultiPartyCall)
+
+        if not callback_url:
+            return self.client.request('GET', ('MultiPartyCall', mpc_id),
+                                       is_voice_request=True, response_type=MultiPartyCall)
+        else:
+            return self.client.request('GET', ('MultiPartyCall', mpc_id),
+                                       to_param_dict(self.get, locals()),
+                                       is_voice_request=True, response_type=MultiPartyCall)
 
     @validate_args(
         role=[of_type_exact(str), is_in(('agent', 'supervisor', 'customer'), case_sensitive=False, case_type='lower')],
@@ -298,6 +316,8 @@ def get(self, uuid=None, friendly_name=None):
         start_recording_audio_method=[optional(of_type_exact(str), is_in(('GET', 'POST'), case_sensitive=False))],
         stop_recording_audio=[optional(of_type_exact(str), is_url())],
         stop_recording_audio_method=[optional(of_type_exact(str), is_in(('GET', 'POST'), case_sensitive=False))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
     def add_participant(self,
                         role,
@@ -348,7 +368,9 @@ def add_participant(self,
                         start_recording_audio=None,
                         start_recording_audio_method='GET',
                         stop_recording_audio=None,
-                        stop_recording_audio_method='GET'
+                        stop_recording_audio_method='GET',
+                        callback_url=None,
+                        callback_method=None
                         ):
         mpc_id = self.__make_mpc_id(friendly_name, uuid)
         caller_name = caller_name or from_
@@ -373,18 +395,29 @@ def add_participant(self,
     @validate_args(
         friendly_name=[optional(of_type_exact(str))],
         uuid=[optional(of_type_exact(str))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
-    def start(self, uuid=None, friendly_name=None):
+    def start(self, uuid=None, friendly_name=None, callback_url=None, callback_method=None):
         mpc_id = self.__make_mpc_id(friendly_name, uuid)
-        return self.client.request('POST', ('MultiPartyCall', mpc_id), {'status': 'active'})
+        localObject={}
+        localObject['status'] = 'active',
+        if callback_url:
+            localObject['callback_url'] = callback_url,
+        if callback_method:
+            localObject['callback_method'] = callback_method,
+        return self.client.request('POST', ('MultiPartyCall', mpc_id), localObject)
 
     @validate_args(
         friendly_name=[optional(of_type_exact(str))],
         uuid=[optional(of_type_exact(str))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
-    def stop(self, uuid=None, friendly_name=None):
+    def stop(self, uuid=None, friendly_name=None, callback_url=None, callback_method=None):
         mpc_id = self.__make_mpc_id(friendly_name, uuid)
-        return self.client.request('DELETE', ('MultiPartyCall', mpc_id), is_voice_request=True)
+        return self.client.request('DELETE', ('MultiPartyCall', mpc_id),
+                                   to_param_dict(self.stop, locals()), is_voice_request=True)
 
     @validate_args(
         friendly_name=[optional(of_type_exact(str))],
@@ -393,13 +426,18 @@ def stop(self, uuid=None, friendly_name=None):
                                                         case_type='lower'))],
         recording_callback_url=[optional(of_type_exact(str), is_url())],
         recording_callback_method=[optional(of_type_exact(str), is_in(('GET', 'POST'), case_sensitive=False))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
     def start_recording(self,
                         uuid=None,
                         friendly_name=None,
                         file_format='mp3',
                         recording_callback_url=None,
-                        recording_callback_method='POST'):
+                        recording_callback_method='POST',
+                        callback_url=None,
+                        callback_method=None
+                        ):
         mpc_id = self.__make_mpc_id(friendly_name, uuid)
         return self.client.request('POST', ('MultiPartyCall', mpc_id, 'Record'),
                                    self.__clean_identifiers(to_param_dict(self.start_recording, locals())),
@@ -408,38 +446,55 @@ def start_recording(self,
     @validate_args(
         friendly_name=[optional(of_type_exact(str))],
         uuid=[optional(of_type_exact(str))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
-    def stop_recording(self, uuid=None, friendly_name=None):
+    def stop_recording(self, uuid=None, friendly_name=None, callback_url=None, callback_method=None):
         mpc_id = self.__make_mpc_id(friendly_name, uuid)
-        return self.client.request('DELETE', ('MultiPartyCall', mpc_id, 'Record'), is_voice_request=True)
+        return self.client.request('DELETE', ('MultiPartyCall', mpc_id, 'Record'),
+                                   to_param_dict(self.stop_recording, locals()), is_voice_request=True)
 
     @validate_args(
         friendly_name=[optional(of_type_exact(str))],
         uuid=[optional(of_type_exact(str))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
-    def pause_recording(self, uuid=None, friendly_name=None):
+    def pause_recording(self, uuid=None, friendly_name=None, callback_url=None, callback_method=None):
         mpc_id = self.__make_mpc_id(friendly_name, uuid)
-        return self.client.request('POST', ('MultiPartyCall', mpc_id, 'Record', 'Pause'), is_voice_request=True)
+        return self.client.request('POST', ('MultiPartyCall', mpc_id, 'Record', 'Pause'),
+                                   to_param_dict(self.pause_recording, locals()), is_voice_request=True)
 
     @validate_args(
         friendly_name=[optional(of_type_exact(str))],
         uuid=[optional(of_type_exact(str))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
-    def resume_recording(self, uuid=None, friendly_name=None):
+    def resume_recording(self, uuid=None, friendly_name=None, callback_url=None, callback_method=None):
         mpc_id = self.__make_mpc_id(friendly_name, uuid)
-        return self.client.request('POST', ('MultiPartyCall', mpc_id, 'Record', 'Resume'), is_voice_request=True)
+        return self.client.request('POST', ('MultiPartyCall', mpc_id, 'Record', 'Resume'),
+                                   to_param_dict(self.pause_recording, locals()), is_voice_request=True)
 
     @validate_args(
         friendly_name=[optional(of_type_exact(str))],
         uuid=[optional(of_type_exact(str))],
-        call_uuid=[optional(of_type_exact(str))]
+        call_uuid=[optional(of_type_exact(str))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
-    def list_participants(self, uuid=None, friendly_name=None, call_uuid=None):
+    def list_participants(self, uuid=None, friendly_name=None, call_uuid=None, callback_url=None, callback_method=None):
         mpc_id = self.__make_mpc_id(friendly_name, uuid)
-        return self.client.request('GET', ('MultiPartyCall', mpc_id, 'Participant'),
-                                   self.__clean_identifiers(to_param_dict(self.list_participants, locals())),
-                                   response_type=ListResponseObject, objects_type=MultiPartyCallParticipant,
-                                   is_voice_request=True)
+        if not callback_url:
+            return self.client.request('GET', ('MultiPartyCall', mpc_id, 'Participant'),
+                                       self.__clean_identifiers(to_param_dict(self.list_participants, locals())),
+                                       response_type=ListResponseObject, objects_type=MultiPartyCallParticipant,
+                                       is_voice_request=True)
+        else:
+            return self.client.request('GET', ('MultiPartyCall', mpc_id, 'Participant'),
+                                       self.__clean_identifiers(to_param_dict(self.list_participants, locals())),
+                                       objects_type=MultiPartyCallParticipant,
+                                       is_voice_request=True)
 
     @validate_args(
         participant_id=[one_of(of_type_exact(str), of_type_exact(int))],
@@ -447,9 +502,12 @@ def list_participants(self, uuid=None, friendly_name=None, call_uuid=None):
         uuid=[optional(of_type_exact(str))],
         coach_mode=[optional(of_type_exact(bool))],
         mute=[optional(of_type_exact(bool))],
-        hold=[optional(of_type_exact(bool))]
+        hold=[optional(of_type_exact(bool))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
-    def update_participant(self, participant_id, uuid=None, friendly_name=None, coach_mode=None, mute=None, hold=None):
+    def update_participant(self, participant_id, uuid=None, friendly_name=None, coach_mode=None, mute=None, hold=None,
+                           callback_url=None, callback_method=None):
         mpc_id = self.__make_mpc_id(friendly_name, uuid)
         if str(participant_id).lower() == 'all' and coach_mode is not None:
             raise ValidationError('cannot specify coach_mode when updating all participants')
@@ -463,21 +521,30 @@ def update_participant(self, participant_id, uuid=None, friendly_name=None, coac
         participant_id=[one_of(of_type_exact(str), of_type_exact(int))],
         friendly_name=[optional(of_type_exact(str))],
         uuid=[optional(of_type_exact(str))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
-    def kick_participant(self, participant_id, uuid=None, friendly_name=None):
+    def kick_participant(self, participant_id, uuid=None, friendly_name=None, callback_url=None, callback_method=None):
         mpc_id = self.__make_mpc_id(friendly_name, uuid)
         return self.client.request('DELETE', ('MultiPartyCall', mpc_id, 'Participant', participant_id),
-                                   is_voice_request=True)
+                                   to_param_dict(self.kick_participant, locals()), is_voice_request=True)
 
     @validate_args(
         participant_id=[one_of(of_type_exact(str), of_type_exact(int))],
         friendly_name=[optional(of_type_exact(str))],
         uuid=[optional(of_type_exact(str))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
-    def get_participant(self, participant_id, uuid=None, friendly_name=None):
+    def get_participant(self, participant_id, uuid=None, friendly_name=None,
+                        callback_url=None, callback_method=None):
         mpc_id = self.__make_mpc_id(friendly_name, uuid)
-        return self.client.request('GET', ('MultiPartyCall', mpc_id, 'Participant', participant_id),
-                                   response_type=MultiPartyCallParticipant, is_voice_request=True)
+        if not callback_url:
+            return self.client.request('GET', ('MultiPartyCall', mpc_id, 'Participant', participant_id),
+                                       response_type=MultiPartyCallParticipant, is_voice_request=True)
+        else:
+            return self.client.request('GET', ('MultiPartyCall', mpc_id, 'Participant', participant_id),
+                                       to_param_dict(self.get_participant, locals()), is_voice_request=True)
 
     @validate_args(
         participant_id=[one_of(of_type_exact(str), of_type_exact(int))],
@@ -487,9 +554,12 @@ def get_participant(self, participant_id, uuid=None, friendly_name=None):
                                                         case_type='lower'))],
         recording_callback_url=[optional(of_type_exact(str), is_url())],
         recording_callback_method=[optional(of_type_exact(str), is_in(('GET', 'POST'), case_sensitive=False))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
     def start_participant_recording(self, participant_id, uuid=None, friendly_name=None, file_format='mp3',
-                                    recording_callback_url=None, recording_callback_method='POST'):
+                                    recording_callback_url=None, recording_callback_method='POST',
+                                    callback_url=None, callback_method=None):
         mpc_id = self.__make_mpc_id(friendly_name, uuid)
         return self.client.request('POST', ('MultiPartyCall', mpc_id, 'Participant', participant_id, 'Record'),
                                    self.__clean_identifiers(to_param_dict(self.start_recording, locals())),
@@ -499,32 +569,45 @@ def start_participant_recording(self, participant_id, uuid=None, friendly_name=N
         participant_id=[one_of(of_type_exact(str), of_type_exact(int))],
         friendly_name=[optional(of_type_exact(str))],
         uuid=[optional(of_type_exact(str))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
-    def stop_participant_recording(self, participant_id, uuid=None, friendly_name=None):
+    def stop_participant_recording(self,
+                                   participant_id,
+                                   uuid=None,
+                                   friendly_name=None,
+                                   callback_url=None,
+                                   callback_method=None):
         mpc_id = self.__make_mpc_id(friendly_name, uuid)
         return self.client.request('DELETE', ('MultiPartyCall', mpc_id, 'Participant', participant_id, 'Record'),
-                                   is_voice_request=True)
+                                   to_param_dict(self.stop_participant_recording, locals()), is_voice_request=True)
 
     @validate_args(
         participant_id=[one_of(of_type_exact(str), of_type_exact(int))],
         friendly_name=[optional(of_type_exact(str))],
         uuid=[optional(of_type_exact(str))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
-    def pause_participant_recording(self, participant_id, uuid=None, friendly_name=None):
+    def pause_participant_recording(self, participant_id, uuid=None, friendly_name=None,
+                                    callback_url=None, callback_method=None):
         mpc_id = self.__make_mpc_id(friendly_name, uuid)
         return self.client.request('POST', ('MultiPartyCall', mpc_id, 'Participant', participant_id, 'Record', 'Pause'),
-                                   is_voice_request=True)
+                                   to_param_dict(self.pause_participant_recording, locals()), is_voice_request=True)
 
     @validate_args(
         participant_id=[one_of(of_type_exact(str), of_type_exact(int))],
         friendly_name=[optional(of_type_exact(str))],
         uuid=[optional(of_type_exact(str))],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
-    def resume_participant_recording(self, participant_id, uuid=None, friendly_name=None):
+    def resume_participant_recording(self, participant_id, uuid=None, friendly_name=None,
+                                     callback_url=None, callback_method=None):
         mpc_id = self.__make_mpc_id(friendly_name, uuid)
         return self.client.request('POST',
                                    ('MultiPartyCall', mpc_id, 'Participant', participant_id, 'Record', 'Resume'),
-                                   is_voice_request=True)
+                                   to_param_dict(self.resume_participant_recording, locals()), is_voice_request=True)
 
     @validate_args(
         participant_id=[one_of(of_type_exact(str), of_type_exact(int))],
diff --git a/plivo/resources/queued_calls.py b/plivo/resources/queued_calls.py
index 1379b59f..a42ac71c 100644
--- a/plivo/resources/queued_calls.py
+++ b/plivo/resources/queued_calls.py
@@ -26,14 +26,30 @@ class QueuedCalls(PlivoResourceInterface):
                 all_of(
                     of_type(*six.integer_types),
                     check(lambda offset: 0 <= offset, message='0 <= offset')))
-        ])
-    def list_ids(self, limit=20, offset=0):
+        ],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],)
+    def list_ids(self, limit=20, offset=0, callback_url=None, callback_method=None):
         return self.client.request('GET', ('Call', ), {
             'status': 'queued',
             'limit': limit,
             'offset': offset,
+            'callback_url': callback_url,
+            'callback_method': callback_method
         }, is_voice_request=True)
 
-    @validate_args(_id=[of_type(six.text_type)])
-    def get(self, _id):
-        return self.client.request('GET', ('Call', _id), {'status': 'queued'}, is_voice_request=True)
+    @validate_args(_id=[of_type(six.text_type)],
+                   callback_url=[optional(is_url())],
+                   callback_method=[optional(of_type(six.text_type))],)
+    def get(self,
+            _id,
+            callback_url=None,
+            callback_method=None):
+        local_object={}
+        local_object['status'] = 'queued'
+        if callback_url:
+            local_object['callback_url'] = callback_url
+        if callback_method:
+            local_object['callback_method'] = callback_method
+
+        return self.client.request('GET', ('Call', _id), local_object, is_voice_request=True)
diff --git a/plivo/resources/recordings.py b/plivo/resources/recordings.py
index d414fbdc..a3a1ee55 100644
--- a/plivo/resources/recordings.py
+++ b/plivo/resources/recordings.py
@@ -42,6 +42,8 @@ class Recordings(PlivoResourceInterface):
                     of_type(*six.integer_types),
                     check(lambda offset: 0 <= offset, '0 <= offset')))
         ],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
     )
     def list(self,
              subaccount=None,
@@ -53,6 +55,8 @@ def list(self,
              add_time=None,
              limit=20,
              offset=0,
+             callback_url=None,
+             callback_method=None,
              from_number=None,
              to_number=None,
              conference_name=None,
@@ -79,20 +83,42 @@ def list(self,
         if add_time and is_valid_time_comparison(add_time):
             add_time = str(add_time)
 
-        return self.client.request(
-            'GET',
-            ('Recording', ),
-            to_param_dict(self.list, locals()),
-            objects_type=Recording,
-            response_type=ListResponseObject,
-            is_voice_request=True
-        )
-
-    @validate_args(recording_id=[of_type(six.text_type)])
-    def get(self, recording_id):
-        return self.client.request(
-            'GET', ('Recording', recording_id), response_type=Recording, is_voice_request=True)
-
-    @validate_args(recording_id=[of_type(six.text_type)])
-    def delete(self, recording_id):
-        return self.client.request('DELETE', ('Recording', recording_id), is_voice_request=True)
+        if not callback_url:
+            return self.client.request(
+                'GET',
+                ('Recording',),
+                to_param_dict(self.list, locals()),
+                objects_type=Recording,
+                response_type=ListResponseObject,
+                is_voice_request=True
+            )
+        else:
+            return self.client.request(
+                'GET',
+                ('Recording',),
+                to_param_dict(self.list, locals()),
+                objects_type=Recording,
+                is_voice_request=True
+            )
+
+
+    @validate_args(recording_id=[of_type(six.text_type)],
+                   callback_url=[optional(is_url())],
+                   callback_method=[optional(of_type(six.text_type))],
+                   )
+    def get(self, recording_id, callback_url=None, callback_method=None):
+        if not callback_url:
+            return self.client.request(
+                'GET', ('Recording', recording_id), response_type=Recording, is_voice_request=True)
+        else:
+            return self.client.request(
+                'GET', ('Recording', recording_id), to_param_dict(self.get, locals()), is_voice_request=True)
+
+    @validate_args(
+        recording_id=[of_type(six.text_type)],
+        callback_url=[optional(is_url())],
+        callback_method=[optional(of_type(six.text_type))],
+    )
+    def delete(self, recording_id, callback_url=None, callback_method=None):
+        return self.client.request('DELETE', ('Recording', recording_id),
+                                   to_param_dict(self.delete, locals()), is_voice_request=True)
diff --git a/plivo/version.py b/plivo/version.py
index 7b0b3668..01e044bc 100644
--- a/plivo/version.py
+++ b/plivo/version.py
@@ -1,3 +1,3 @@
 # -*- coding: utf-8 -*-
-__version__ = '4.24.0'
+__version__ = '4.24.1'
 
diff --git a/setup.py b/setup.py
index 635199a7..c194680f 100644
--- a/setup.py
+++ b/setup.py
@@ -10,7 +10,7 @@
 
 setup(
     name='plivo',
-    version='4.24.0',
+    version='4.24.1',
     description='A Python SDK to make voice calls & send SMS using Plivo and to generate Plivo XML',
     long_description=long_description,
     url='https://github.com/plivo/plivo-python',


Test patch:
diff --git a/tests/resources/test_calls.py b/tests/resources/test_calls.py
index f7ab946a..85ed461d 100644
--- a/tests/resources/test_calls.py
+++ b/tests/resources/test_calls.py
@@ -34,7 +34,7 @@ def test_get(self):
         self.assertResponseMatches(call)
         self.assertEqual(self.client.current_request.method, 'GET')
         self.assertUrlEqual(
-            self.get_voice_url('Call', uuid), self.client.current_request.url)
+            self.get_voice_url('Call', uuid) + 'call_uuid=' + uuid, self.client.current_request.url)
 
     @with_response(202)
     def test_update(self):
diff --git a/tests/resources/test_conferences.py b/tests/resources/test_conferences.py
index 8443de3c..7ee1e3f5 100644
--- a/tests/resources/test_conferences.py
+++ b/tests/resources/test_conferences.py
@@ -14,7 +14,7 @@ def test_get(self):
         self.assertResponseMatches(conference)
         self.assertEqual(self.client.current_request.method, 'GET')
         self.assertUrlEqual(
-            self.get_voice_url('Conference', conference_name),
+            self.get_voice_url('Conference', conference_name) + 'conference_name=' + conference_name,
             self.client.current_request.url)
         self.assertEqual(conference.conference_name, conference_name)
 
diff --git a/tests/resources/test_endpoints.py b/tests/resources/test_endpoints.py
index 4cf67e69..b58f2f5e 100644
--- a/tests/resources/test_endpoints.py
+++ b/tests/resources/test_endpoints.py
@@ -28,7 +28,7 @@ def test_get(self):
         self.assertResponseMatches(endpoint)
         self.assertEqual(self.client.current_request.method, 'GET')
         self.assertUrlEqual(
-            self.get_voice_url('Endpoint', uuid), self.client.current_request.url)
+            self.get_voice_url('Endpoint', uuid) + 'endpoint_id=' + uuid, self.client.current_request.url)
 
     @with_response(202)
     def test_update(self):
diff --git a/tests/resources/test_multipartycalls.py b/tests/resources/test_multipartycalls.py
index ad2cb9d6..ff527197 100644
--- a/tests/resources/test_multipartycalls.py
+++ b/tests/resources/test_multipartycalls.py
@@ -230,7 +230,7 @@ def test_add_participant(self):
     @with_response(200)
     def test_start_MPC(self):
 
-        request_body = {'status': 'active'}
+        request_body = {'status': ['active']}
 
         start_mpc_response = self.client.multi_party_calls.start(friendly_name='Voice')