Add support for managing lists
authorHarmon <Harmon758@gmail.com>
Mon, 25 Oct 2021 07:32:52 +0000 (02:32 -0500)
committerHarmon <Harmon758@gmail.com>
Mon, 25 Oct 2021 07:32:52 +0000 (02:32 -0500)
cassettes/test_follow_and_unfollow_list.yaml [new file with mode: 0644]
cassettes/test_manage_list.yaml [new file with mode: 0644]
docs/client.rst
tests/test_client.py
tweepy/client.py

diff --git a/cassettes/test_follow_and_unfollow_list.yaml b/cassettes/test_follow_and_unfollow_list.yaml
new file mode 100644 (file)
index 0000000..287e066
--- /dev/null
@@ -0,0 +1,129 @@
+interactions:
+- request:
+    body: '{"list_id": "84839422"}'
+    headers:
+      Accept:
+      - '*/*'
+      Accept-Encoding:
+      - gzip, deflate
+      Connection:
+      - keep-alive
+      Content-Length:
+      - '23'
+      Content-Type:
+      - application/json
+      User-Agent:
+      - Python/3.10.0 Requests/2.26.0 Tweepy/4.1.0
+    method: POST
+    uri: https://api.twitter.com/2/users/1072250532645998596/followed_lists
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAAKpWSkksSVSyqlZKy8/JyS/PzEtXsiopKk2trQUAAAD//wMA/FRoehsAAAA=
+    headers:
+      api-version:
+      - '2.27'
+      cache-control:
+      - no-cache, no-store, max-age=0
+      content-disposition:
+      - attachment; filename=json.json
+      content-encoding:
+      - gzip
+      content-length:
+      - '53'
+      content-type:
+      - application/json; charset=utf-8
+      date:
+      - Mon, 25 Oct 2021 07:24:49 UTC
+      server:
+      - tsa_b
+      set-cookie:
+      - personalization_id="v1_hlVVKDuf5oESwpgKPKVpkA=="; Max-Age=63072000; Expires=Wed,
+        25 Oct 2023 07:24:49 GMT; Path=/; Domain=.twitter.com; Secure; SameSite=None
+      - guest_id=v1%3A163514668949543599; Max-Age=63072000; Expires=Wed, 25 Oct 2023
+        07:24:49 GMT; Path=/; Domain=.twitter.com; Secure; SameSite=None
+      strict-transport-security:
+      - max-age=631138519
+      x-access-level:
+      - read-write-directmessages
+      x-connection-hash:
+      - bd61a0a6b7381c3a8f1601ff0c1e66c9ef64b2aa429e196fc71e553d3c848a65
+      x-content-type-options:
+      - nosniff
+      x-frame-options:
+      - SAMEORIGIN
+      x-rate-limit-limit:
+      - '50'
+      x-rate-limit-remaining:
+      - '47'
+      x-rate-limit-reset:
+      - '1635146788'
+      x-response-time:
+      - '120'
+      x-xss-protection:
+      - '0'
+    status:
+      code: 200
+      message: OK
+- request:
+    body: null
+    headers:
+      Accept:
+      - '*/*'
+      Accept-Encoding:
+      - gzip, deflate
+      Connection:
+      - keep-alive
+      Content-Length:
+      - '0'
+      Cookie:
+      - guest_id=v1%3A163514668949543599; personalization_id="v1_hlVVKDuf5oESwpgKPKVpkA=="
+      User-Agent:
+      - Python/3.10.0 Requests/2.26.0 Tweepy/4.1.0
+    method: DELETE
+    uri: https://api.twitter.com/2/users/1072250532645998596/followed_lists/84839422
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAAKpWSkksSVSyqlZKy8/JyS/PzEtXskpLzClOra0FAAAA//8DAMXGczccAAAA
+    headers:
+      api-version:
+      - '2.27'
+      cache-control:
+      - no-cache, no-store, max-age=0
+      content-disposition:
+      - attachment; filename=json.json
+      content-encoding:
+      - gzip
+      content-length:
+      - '54'
+      content-type:
+      - application/json; charset=utf-8
+      date:
+      - Mon, 25 Oct 2021 07:24:49 UTC
+      server:
+      - tsa_b
+      strict-transport-security:
+      - max-age=631138519
+      x-access-level:
+      - read-write-directmessages
+      x-connection-hash:
+      - bd61a0a6b7381c3a8f1601ff0c1e66c9ef64b2aa429e196fc71e553d3c848a65
+      x-content-type-options:
+      - nosniff
+      x-frame-options:
+      - SAMEORIGIN
+      x-rate-limit-limit:
+      - '50'
+      x-rate-limit-remaining:
+      - '48'
+      x-rate-limit-reset:
+      - '1635146822'
+      x-response-time:
+      - '55'
+      x-xss-protection:
+      - '0'
+    status:
+      code: 200
+      message: OK
+version: 1
diff --git a/cassettes/test_manage_list.yaml b/cassettes/test_manage_list.yaml
new file mode 100644 (file)
index 0000000..6fe1b77
--- /dev/null
@@ -0,0 +1,443 @@
+interactions:
+- request:
+    body: '{"name": "Test List", "private": true}'
+    headers:
+      Accept:
+      - '*/*'
+      Accept-Encoding:
+      - gzip, deflate
+      Connection:
+      - keep-alive
+      Content-Length:
+      - '38'
+      Content-Type:
+      - application/json
+      User-Agent:
+      - Python/3.10.0 Requests/2.26.0 Tweepy/4.1.0
+    method: POST
+    uri: https://api.twitter.com/2/lists
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAAKpWSkksSVSyqlbKTFGyUjI0MTUyNTYzMzQzMjC2tDQ3tDRQ0lHKS8xNBUqGpBaX
+        KPhkFpco1dYCAAAA//8DAAZ8t6c4AAAA
+    headers:
+      api-version:
+      - '2.27'
+      cache-control:
+      - no-cache, no-store, max-age=0
+      content-disposition:
+      - attachment; filename=json.json
+      content-encoding:
+      - gzip
+      content-length:
+      - '81'
+      content-type:
+      - application/json; charset=utf-8
+      date:
+      - Mon, 25 Oct 2021 07:24:50 UTC
+      location:
+      - https://api.twitter.com/2/lists/1452536616203997190
+      server:
+      - tsa_b
+      set-cookie:
+      - personalization_id="v1_f6Q7tQ/Do3NkovyN4sJfog=="; Max-Age=63072000; Expires=Wed,
+        25 Oct 2023 07:24:50 GMT; Path=/; Domain=.twitter.com; Secure; SameSite=None
+      - guest_id=v1%3A163514669039140044; Max-Age=63072000; Expires=Wed, 25 Oct 2023
+        07:24:50 GMT; Path=/; Domain=.twitter.com; Secure; SameSite=None
+      strict-transport-security:
+      - max-age=631138519
+      x-access-level:
+      - read-write-directmessages
+      x-connection-hash:
+      - b20657636698db22333ea81a4e5d78f071184b672a5e536b229e6cada14038b3
+      x-content-type-options:
+      - nosniff
+      x-frame-options:
+      - SAMEORIGIN
+      x-rate-limit-limit:
+      - '300'
+      x-rate-limit-remaining:
+      - '299'
+      x-rate-limit-reset:
+      - '1635147590'
+      x-response-time:
+      - '412'
+      x-xss-protection:
+      - '0'
+    status:
+      code: 201
+      message: Created
+- request:
+    body: '{"user_id": "783214"}'
+    headers:
+      Accept:
+      - '*/*'
+      Accept-Encoding:
+      - gzip, deflate
+      Connection:
+      - keep-alive
+      Content-Length:
+      - '21'
+      Content-Type:
+      - application/json
+      Cookie:
+      - guest_id=v1%3A163514669039140044; personalization_id="v1_f6Q7tQ/Do3NkovyN4sJfog=="
+      User-Agent:
+      - Python/3.10.0 Requests/2.26.0 Tweepy/4.1.0
+    method: POST
+    uri: https://api.twitter.com/2/lists/1452536616203997190/members
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAAKpWSkksSVSyqlbKLI7PTc1NSi1SsiopKk2trQUAAAD//wMAl7jcXBsAAAA=
+    headers:
+      api-version:
+      - '2.27'
+      cache-control:
+      - no-cache, no-store, max-age=0
+      content-disposition:
+      - attachment; filename=json.json
+      content-encoding:
+      - gzip
+      content-length:
+      - '53'
+      content-type:
+      - application/json; charset=utf-8
+      date:
+      - Mon, 25 Oct 2021 07:24:50 UTC
+      server:
+      - tsa_b
+      strict-transport-security:
+      - max-age=631138519
+      x-access-level:
+      - read-write-directmessages
+      x-connection-hash:
+      - b20657636698db22333ea81a4e5d78f071184b672a5e536b229e6cada14038b3
+      x-content-type-options:
+      - nosniff
+      x-frame-options:
+      - SAMEORIGIN
+      x-rate-limit-limit:
+      - '300'
+      x-rate-limit-remaining:
+      - '299'
+      x-rate-limit-reset:
+      - '1635147589'
+      x-response-time:
+      - '101'
+      x-xss-protection:
+      - '0'
+    status:
+      code: 200
+      message: OK
+- request:
+    body: '{"list_id": "1452536616203997190"}'
+    headers:
+      Accept:
+      - '*/*'
+      Accept-Encoding:
+      - gzip, deflate
+      Connection:
+      - keep-alive
+      Content-Length:
+      - '34'
+      Content-Type:
+      - application/json
+      Cookie:
+      - guest_id=v1%3A163514669039140044; personalization_id="v1_f6Q7tQ/Do3NkovyN4sJfog=="
+      User-Agent:
+      - Python/3.10.0 Requests/2.26.0 Tweepy/4.1.0
+    method: POST
+    uri: https://api.twitter.com/2/users/1072250532645998596/pinned_lists
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAAKpWSkksSVSyqlYqyMzLS01RsiopKk2trQUAAAD//wMAEmYA3BgAAAA=
+    headers:
+      api-version:
+      - '2.27'
+      cache-control:
+      - no-cache, no-store, max-age=0
+      content-disposition:
+      - attachment; filename=json.json
+      content-encoding:
+      - gzip
+      content-length:
+      - '50'
+      content-type:
+      - application/json; charset=utf-8
+      date:
+      - Mon, 25 Oct 2021 07:24:51 UTC
+      server:
+      - tsa_b
+      strict-transport-security:
+      - max-age=631138519
+      x-access-level:
+      - read-write-directmessages
+      x-connection-hash:
+      - b20657636698db22333ea81a4e5d78f071184b672a5e536b229e6cada14038b3
+      x-content-type-options:
+      - nosniff
+      x-frame-options:
+      - SAMEORIGIN
+      x-rate-limit-limit:
+      - '50'
+      x-rate-limit-remaining:
+      - '49'
+      x-rate-limit-reset:
+      - '1635147591'
+      x-response-time:
+      - '47'
+      x-xss-protection:
+      - '0'
+    status:
+      code: 200
+      message: OK
+- request:
+    body: null
+    headers:
+      Accept:
+      - '*/*'
+      Accept-Encoding:
+      - gzip, deflate
+      Connection:
+      - keep-alive
+      Content-Length:
+      - '0'
+      Cookie:
+      - guest_id=v1%3A163514669039140044; personalization_id="v1_f6Q7tQ/Do3NkovyN4sJfog=="
+      User-Agent:
+      - Python/3.10.0 Requests/2.26.0 Tweepy/4.1.0
+    method: DELETE
+    uri: https://api.twitter.com/2/lists/1452536616203997190/members/783214
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAAKpWSkksSVSyqlbKLI7PTc1NSi1SskpLzClOra0FAAAA//8DAPnKNe0cAAAA
+    headers:
+      api-version:
+      - '2.27'
+      cache-control:
+      - no-cache, no-store, max-age=0
+      content-disposition:
+      - attachment; filename=json.json
+      content-encoding:
+      - gzip
+      content-length:
+      - '54'
+      content-type:
+      - application/json; charset=utf-8
+      date:
+      - Mon, 25 Oct 2021 07:24:51 UTC
+      server:
+      - tsa_b
+      strict-transport-security:
+      - max-age=631138519
+      x-access-level:
+      - read-write-directmessages
+      x-connection-hash:
+      - b20657636698db22333ea81a4e5d78f071184b672a5e536b229e6cada14038b3
+      x-content-type-options:
+      - nosniff
+      x-frame-options:
+      - SAMEORIGIN
+      x-rate-limit-limit:
+      - '300'
+      x-rate-limit-remaining:
+      - '299'
+      x-rate-limit-reset:
+      - '1635147591'
+      x-response-time:
+      - '66'
+      x-xss-protection:
+      - '0'
+    status:
+      code: 200
+      message: OK
+- request:
+    body: null
+    headers:
+      Accept:
+      - '*/*'
+      Accept-Encoding:
+      - gzip, deflate
+      Connection:
+      - keep-alive
+      Content-Length:
+      - '0'
+      Cookie:
+      - guest_id=v1%3A163514669039140044; personalization_id="v1_f6Q7tQ/Do3NkovyN4sJfog=="
+      User-Agent:
+      - Python/3.10.0 Requests/2.26.0 Tweepy/4.1.0
+    method: DELETE
+    uri: https://api.twitter.com/2/users/1072250532645998596/pinned_lists/1452536616203997190
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAAKpWSkksSVSyqlYqyMzLS01RskpLzClOra0FAAAA//8DAIhhZ3AZAAAA
+    headers:
+      api-version:
+      - '2.27'
+      cache-control:
+      - no-cache, no-store, max-age=0
+      content-disposition:
+      - attachment; filename=json.json
+      content-encoding:
+      - gzip
+      content-length:
+      - '51'
+      content-type:
+      - application/json; charset=utf-8
+      date:
+      - Mon, 25 Oct 2021 07:24:51 UTC
+      server:
+      - tsa_b
+      strict-transport-security:
+      - max-age=631138519
+      x-access-level:
+      - read-write-directmessages
+      x-connection-hash:
+      - b20657636698db22333ea81a4e5d78f071184b672a5e536b229e6cada14038b3
+      x-content-type-options:
+      - nosniff
+      x-frame-options:
+      - SAMEORIGIN
+      x-rate-limit-limit:
+      - '50'
+      x-rate-limit-remaining:
+      - '49'
+      x-rate-limit-reset:
+      - '1635147591'
+      x-response-time:
+      - '46'
+      x-xss-protection:
+      - '0'
+    status:
+      code: 200
+      message: OK
+- request:
+    body: '{"description": "Test List Description"}'
+    headers:
+      Accept:
+      - '*/*'
+      Accept-Encoding:
+      - gzip, deflate
+      Connection:
+      - keep-alive
+      Content-Length:
+      - '40'
+      Content-Type:
+      - application/json
+      Cookie:
+      - guest_id=v1%3A163514669039140044; personalization_id="v1_f6Q7tQ/Do3NkovyN4sJfog=="
+      User-Agent:
+      - Python/3.10.0 Requests/2.26.0 Tweepy/4.1.0
+    method: PUT
+    uri: https://api.twitter.com/2/lists/1452536616203997190
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAAKpWKi1ISSxJTVGyKikqTa0FAAAA//8DACu2J84QAAAA
+    headers:
+      api-version:
+      - '2.27'
+      cache-control:
+      - no-cache, no-store, max-age=0
+      content-disposition:
+      - attachment; filename=json.json
+      content-encoding:
+      - gzip
+      content-length:
+      - '42'
+      content-type:
+      - application/json; charset=utf-8
+      date:
+      - Mon, 25 Oct 2021 07:24:51 UTC
+      server:
+      - tsa_b
+      strict-transport-security:
+      - max-age=631138519
+      x-access-level:
+      - read-write-directmessages
+      x-connection-hash:
+      - b20657636698db22333ea81a4e5d78f071184b672a5e536b229e6cada14038b3
+      x-content-type-options:
+      - nosniff
+      x-frame-options:
+      - SAMEORIGIN
+      x-rate-limit-limit:
+      - '300'
+      x-rate-limit-remaining:
+      - '298'
+      x-rate-limit-reset:
+      - '1635147202'
+      x-response-time:
+      - '387'
+      x-xss-protection:
+      - '0'
+    status:
+      code: 200
+      message: OK
+- request:
+    body: null
+    headers:
+      Accept:
+      - '*/*'
+      Accept-Encoding:
+      - gzip, deflate
+      Connection:
+      - keep-alive
+      Content-Length:
+      - '0'
+      Cookie:
+      - guest_id=v1%3A163514669039140044; personalization_id="v1_f6Q7tQ/Do3NkovyN4sJfog=="
+      User-Agent:
+      - Python/3.10.0 Requests/2.26.0 Tweepy/4.1.0
+    method: DELETE
+    uri: https://api.twitter.com/2/lists/1452536616203997190
+  response:
+    body:
+      string: !!binary |
+        H4sIAAAAAAAAAKpWSkksSVSyqlZKSc1JLUlNUbIqKSpNra0FAAAA//8DAD5d+0oZAAAA
+    headers:
+      api-version:
+      - '2.27'
+      cache-control:
+      - no-cache, no-store, max-age=0
+      content-disposition:
+      - attachment; filename=json.json
+      content-encoding:
+      - gzip
+      content-length:
+      - '51'
+      content-type:
+      - application/json; charset=utf-8
+      date:
+      - Mon, 25 Oct 2021 07:24:51 UTC
+      server:
+      - tsa_b
+      strict-transport-security:
+      - max-age=631138519
+      x-access-level:
+      - read-write-directmessages
+      x-connection-hash:
+      - b20657636698db22333ea81a4e5d78f071184b672a5e536b229e6cada14038b3
+      x-content-type-options:
+      - nosniff
+      x-frame-options:
+      - SAMEORIGIN
+      x-rate-limit-limit:
+      - '300'
+      x-rate-limit-remaining:
+      - '299'
+      x-rate-limit-reset:
+      - '1635147591'
+      x-response-time:
+      - '50'
+      x-xss-protection:
+      - '0'
+    status:
+      code: 200
+      message: OK
+version: 1
index f4c488beeef2819258451a9c6a4c7d5d98d3851a..4c3f6f7c5ecd75585dc2d1c7dae7a4f7d83598b0 100644 (file)
@@ -120,6 +120,30 @@ Spaces lookup
 
 .. automethod:: Client.get_space
 
+Lists
+=====
+
+Manage Lists
+------------
+
+.. automethod:: Client.delete_list
+
+.. automethod:: Client.remove_list_member
+
+.. automethod:: Client.unfollow_list
+
+.. automethod:: Client.unpin_list
+
+.. automethod:: Client.update_list
+
+.. automethod:: Client.create_list
+
+.. automethod:: Client.add_list_member
+
+.. automethod:: Client.follow_list
+
+.. automethod:: Client.pin_list
+
 Compliance
 ==========
 
index 4d6f99c03544524421046477dfef38f529410fed..a7bea722ce551020cd0bd09b7b37975aa02d4a97 100644 (file)
@@ -147,6 +147,25 @@ class TweepyTestCase(unittest.TestCase):
         # https://twitter.com/TwitterSpaces/status/1436382283347283969
         self.client.get_space(space_id)
 
+    @tape.use_cassette("test_follow_and_unfollow_list.yaml",
+                        serializer = "yaml")
+    def test_follow_and_unfollow_list(self):
+        list_id = 84839422  # List ID for Official Twitter Accounts (@Twitter)
+        self.client.follow_list(list_id)
+        self.client.unfollow_list(list_id)
+
+    @tape.use_cassette("test_manage_list.yaml", serializer="yaml")
+    def test_manage_list(self):
+        response = self.client.create_list("Test List", private=True)
+        list_id = response.data["id"]
+        user_id = 783214  # User ID for @Twitter
+        self.client.add_list_member(list_id, user_id)
+        self.client.pin_list(list_id)
+        self.client.remove_list_member(list_id, user_id)
+        self.client.unpin_list(list_id)
+        self.client.update_list(list_id, description="Test List Description")
+        self.client.delete_list(list_id)
+
     @tape.use_cassette("test_create_and_get_compliance_job_and_jobs.yaml",
                        serializer="yaml")
     def test_create_and_get_compliance_job_and_jobs(self):
index efae557ca66059e17024bff66cedd544388fe0c1..55aaf04bffe021fe4715ead543020ea954a912db 100644 (file)
@@ -1687,6 +1687,238 @@ class Client:
             ), data_type=Space
         )
 
+    # Manage Lists
+
+    def delete_list(self, id):
+        """Enables the authenticated user to delete a List that they own.
+
+        Parameters
+        ----------
+        id : Union[int, str]
+            The ID of the List to be deleted.
+
+        Returns
+        -------
+        Union[dict, requests.Response, Response]
+
+        References
+        ----------
+        https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/api-reference/delete-lists-id
+        """
+
+        return self._make_request(
+            "DELETE", f"/2/lists/{id}", user_auth=True
+        )
+
+    def remove_list_member(self, id, user_id):
+        """Enables the authenticated user to remove a member from a List they
+        own.
+
+        Parameters
+        ----------
+        id : Union[int, str]
+            The ID of the List you are removing a member from.
+        user_id : Union[int, str]
+            The ID of the user you wish to remove as a member of the List.
+
+        Returns
+        -------
+        Union[dict, requests.Response, Response]
+
+        References
+        ----------
+        https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/api-reference/delete-lists-id-members-user_id
+        """
+
+        return self._make_request(
+            "DELETE", f"/2/lists/{id}/members/{user_id}", user_auth=True
+        )
+
+    def unfollow_list(self, list_id):
+        """Enables the authenticated user to unfollow a List.
+
+        Parameters
+        ----------
+        list_id : Union[int, str]
+            The ID of the List that you would like the user to unfollow.
+
+        Returns
+        -------
+        Union[dict, requests.Response, Response]
+
+        References
+        ----------
+        https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/api-reference/delete-users-id-followed-lists-list_id
+        """
+        id = self.access_token.partition('-')[0]
+        route = f"/2/users/{id}/followed_lists/{list_id}"
+
+        return self._make_request(
+            "DELETE", route, user_auth=True
+        )
+
+    def unpin_list(self, list_id):
+        """Enables the authenticated user to unpin a List.
+
+        Parameters
+        ----------
+        list_id : Union[int, str]
+            The ID of the List that you would like the user to unpin.
+
+        Returns
+        -------
+        Union[dict, requests.Response, Response]
+
+        References
+        ----------
+        https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/api-reference/delete-users-id-pinned-lists-list_id
+        """
+        id = self.access_token.partition('-')[0]
+        route = f"/2/users/{id}/pinned_lists/{list_id}"
+
+        return self._make_request(
+            "DELETE", route, user_auth=True
+        )
+
+    def update_list(self, id, *, description=None, name=None, private=None):
+        """Enables the authenticated user to update the meta data of a
+        specified List that they own.
+
+        Parameters
+        ----------
+        id : Union[int, str]
+            The ID of the List to be updated.
+        description : str
+            Updates the description of the List.
+        name : str
+            Updates the name of the List.
+        private : str
+            Determines whether the List should be private.
+
+        Returns
+        -------
+        Union[dict, requests.Response, Response]
+
+        References
+        ----------
+        https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/api-reference/put-lists-id
+        """
+        json = {}
+
+        if description is not None:
+            json["description"] = description
+
+        if name is not None:
+            json["name"] = name
+
+        if private is not None:
+            json["private"] = private
+
+        return self._make_request(
+            "PUT", f"/2/lists/{id}", json=json, user_auth=True
+        )
+
+    def create_list(self, name, *, description=None, private=None):
+        """Enables the authenticated user to create a List.
+
+        Parameters
+        ----------
+        name : str
+            The name of the List you wish to create.
+        description : str
+            Description of the List.
+        private : bool
+            Determine whether the List should be private.
+
+        Returns
+        -------
+        Union[dict, requests.Response, Response]
+
+        References
+        ----------
+        https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/api-reference/post-lists
+        """
+        json = {"name": name}
+
+        if description is not None:
+            json["description"] = description
+
+        if private is not None:
+            json["private"] = private
+
+        return self._make_request(
+            "POST", f"/2/lists", json=json, user_auth=True
+        )
+
+    def add_list_member(self, id, user_id):
+        """Enables the authenticated user to add a member to a List they own.
+
+        Parameters
+        ----------
+        id : Union[int, str]
+            The ID of the List you are adding a member to.
+        user_id : Union[int, str]
+            The ID of the user you wish to add as a member of the List.
+
+        Returns
+        -------
+        Union[dict, requests.Response, Response]
+
+        References
+        ----------
+        https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/api-reference/post-lists-id-members
+        """
+        return self._make_request(
+            "POST", f"/2/lists/{id}/members", json={"user_id": str(user_id)},
+            user_auth=True
+        )
+
+    def follow_list(self, list_id):
+        """Enables the authenticated user to follow a List.
+
+        Parameters
+        ----------
+        list_id : Union[int, str]
+            The ID of the List that you would like the user to follow.
+
+        Returns
+        -------
+        Union[dict, requests.Response, Response]
+
+        References
+        ----------
+        https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/api-reference/post-users-id-followed-lists
+        """
+        id = self.access_token.partition('-')[0]
+        route = f"/2/users/{id}/followed_lists"
+
+        return self._make_request(
+            "POST", route, json={"list_id": str(list_id)}, user_auth=True
+        )
+
+    def pin_list(self, list_id):
+        """Enables the authenticated user to pin a List.
+
+        Parameters
+        ----------
+        list_id : Union[int, str]
+            The ID of the List that you would like the user to pin.
+
+        Returns
+        -------
+        Union[dict, requests.Response, Response]
+
+        References
+        ----------
+        https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/api-reference/post-users-id-pinned-lists
+        """
+        id = self.access_token.partition('-')[0]
+        route = f"/2/users/{id}/pinned_lists"
+
+        return self._make_request(
+            "POST", route, json={"list_id": str(list_id)}, user_auth=True
+        )
+
     # Batch Compliance
 
     def get_compliance_jobs(self, type, **params):