circle-so-python-sdk 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. circle_so_python_sdk-0.1.0/.env.example +2 -0
  2. circle_so_python_sdk-0.1.0/.github/workflows/ci.yml +21 -0
  3. circle_so_python_sdk-0.1.0/.github/workflows/publish.yml +19 -0
  4. circle_so_python_sdk-0.1.0/.gitignore +18 -0
  5. circle_so_python_sdk-0.1.0/CHANGELOG.md +18 -0
  6. circle_so_python_sdk-0.1.0/LICENSE +21 -0
  7. circle_so_python_sdk-0.1.0/PKG-INFO +120 -0
  8. circle_so_python_sdk-0.1.0/README.md +90 -0
  9. circle_so_python_sdk-0.1.0/docs/admin-api.md +98 -0
  10. circle_so_python_sdk-0.1.0/docs/auth-api.md +38 -0
  11. circle_so_python_sdk-0.1.0/docs/headless-api.md +103 -0
  12. circle_so_python_sdk-0.1.0/docs/models.md +40 -0
  13. circle_so_python_sdk-0.1.0/docs/quickstart.md +75 -0
  14. circle_so_python_sdk-0.1.0/docs/webhooks.md +26 -0
  15. circle_so_python_sdk-0.1.0/pyproject.toml +55 -0
  16. circle_so_python_sdk-0.1.0/src/circle/__init__.py +24 -0
  17. circle_so_python_sdk-0.1.0/src/circle/api/__init__.py +1 -0
  18. circle_so_python_sdk-0.1.0/src/circle/api/admin_access_groups.py +133 -0
  19. circle_so_python_sdk-0.1.0/src/circle/api/admin_community.py +122 -0
  20. circle_so_python_sdk-0.1.0/src/circle/api/admin_courses.py +172 -0
  21. circle_so_python_sdk-0.1.0/src/circle/api/admin_events.py +101 -0
  22. circle_so_python_sdk-0.1.0/src/circle/api/admin_misc.py +305 -0
  23. circle_so_python_sdk-0.1.0/src/circle/api/admin_posts.py +200 -0
  24. circle_so_python_sdk-0.1.0/src/circle/api/admin_spaces.py +301 -0
  25. circle_so_python_sdk-0.1.0/src/circle/api/admin_tags.py +146 -0
  26. circle_so_python_sdk-0.1.0/src/circle/api/auth.py +63 -0
  27. circle_so_python_sdk-0.1.0/src/circle/api/headless_chat_notif_members.py +323 -0
  28. circle_so_python_sdk-0.1.0/src/circle/api/headless_misc.py +218 -0
  29. circle_so_python_sdk-0.1.0/src/circle/api/headless_spaces_posts.py +279 -0
  30. circle_so_python_sdk-0.1.0/src/circle/client.py +197 -0
  31. circle_so_python_sdk-0.1.0/src/circle/constants.py +5 -0
  32. circle_so_python_sdk-0.1.0/src/circle/exceptions.py +34 -0
  33. circle_so_python_sdk-0.1.0/src/circle/http.py +227 -0
  34. circle_so_python_sdk-0.1.0/src/circle/models/__init__.py +5 -0
  35. circle_so_python_sdk-0.1.0/src/circle/models/admin/__init__.py +47 -0
  36. circle_so_python_sdk-0.1.0/src/circle/models/admin/community.py +82 -0
  37. circle_so_python_sdk-0.1.0/src/circle/models/admin/courses.py +30 -0
  38. circle_so_python_sdk-0.1.0/src/circle/models/admin/events.py +67 -0
  39. circle_so_python_sdk-0.1.0/src/circle/models/admin/members.py +105 -0
  40. circle_so_python_sdk-0.1.0/src/circle/models/admin/misc.py +240 -0
  41. circle_so_python_sdk-0.1.0/src/circle/models/admin/posts.py +172 -0
  42. circle_so_python_sdk-0.1.0/src/circle/models/admin/spaces.py +146 -0
  43. circle_so_python_sdk-0.1.0/src/circle/models/admin/tags.py +85 -0
  44. circle_so_python_sdk-0.1.0/src/circle/models/auth.py +21 -0
  45. circle_so_python_sdk-0.1.0/src/circle/models/base.py +28 -0
  46. circle_so_python_sdk-0.1.0/src/circle/models/headless/__init__.py +50 -0
  47. circle_so_python_sdk-0.1.0/src/circle/models/headless/chat.py +134 -0
  48. circle_so_python_sdk-0.1.0/src/circle/models/headless/comments.py +60 -0
  49. circle_so_python_sdk-0.1.0/src/circle/models/headless/courses.py +109 -0
  50. circle_so_python_sdk-0.1.0/src/circle/models/headless/members.py +105 -0
  51. circle_so_python_sdk-0.1.0/src/circle/models/headless/misc.py +120 -0
  52. circle_so_python_sdk-0.1.0/src/circle/models/headless/notifications.py +66 -0
  53. circle_so_python_sdk-0.1.0/src/circle/models/headless/posts.py +137 -0
  54. circle_so_python_sdk-0.1.0/src/circle/models/headless/spaces.py +80 -0
  55. circle_so_python_sdk-0.1.0/src/circle/pagination.py +116 -0
  56. circle_so_python_sdk-0.1.0/src/circle/py.typed +1 -0
  57. circle_so_python_sdk-0.1.0/src/circle/rate_limit.py +36 -0
  58. circle_so_python_sdk-0.1.0/src/circle/validation.py +67 -0
  59. circle_so_python_sdk-0.1.0/src/circle/webhooks.py +39 -0
  60. circle_so_python_sdk-0.1.0/tests/__init__.py +0 -0
  61. circle_so_python_sdk-0.1.0/tests/conftest.py +70 -0
  62. circle_so_python_sdk-0.1.0/tests/integration/__init__.py +0 -0
  63. circle_so_python_sdk-0.1.0/tests/integration/conftest.py +21 -0
  64. circle_so_python_sdk-0.1.0/tests/integration/test_smoke.py +22 -0
  65. circle_so_python_sdk-0.1.0/tests/test_admin.py +229 -0
  66. circle_so_python_sdk-0.1.0/tests/test_audit.py +150 -0
  67. circle_so_python_sdk-0.1.0/tests/test_auth.py +70 -0
  68. circle_so_python_sdk-0.1.0/tests/test_client.py +92 -0
  69. circle_so_python_sdk-0.1.0/tests/test_coverage_expansion.py +255 -0
  70. circle_so_python_sdk-0.1.0/tests/test_headless.py +170 -0
  71. circle_so_python_sdk-0.1.0/tests/test_http.py +93 -0
  72. circle_so_python_sdk-0.1.0/tests/test_models.py +171 -0
@@ -0,0 +1,2 @@
1
+ CIRCLE_API_TOKEN=your_token_here
2
+ CIRCLE_COMMUNITY_URL=https://your-community.circle.so
@@ -0,0 +1,21 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: actions/setup-python@v5
18
+ with:
19
+ python-version: ${{ matrix.python-version }}
20
+ - run: pip install -e .[dev]
21
+ - run: pytest tests/ -v --ignore=tests/integration
@@ -0,0 +1,19 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ id-token: write # trusted publishing
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: actions/setup-python@v5
15
+ with:
16
+ python-version: "3.12"
17
+ - run: pip install build
18
+ - run: python -m build
19
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,18 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .eggs/
8
+ *.egg
9
+ .venv/
10
+ venv/
11
+ env/
12
+ .env
13
+ .pytest_cache/
14
+ .ruff_cache/
15
+ .mypy_cache/
16
+ *.so
17
+ .DS_Store
18
+ scripts/
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 (2026-03-14)
4
+
5
+ Initial release covering all three Circle.so APIs:
6
+
7
+ - Headless Auth API (4 endpoints)
8
+ - Admin API V2 (~118 endpoints)
9
+ - Headless Client API V1 (~101 endpoints)
10
+
11
+ Features:
12
+ - Sync and async clients via httpx
13
+ - Pydantic V2 models for all API responses
14
+ - Typed exceptions (AuthenticationError, NotFoundError, ValidationError, ForbiddenError, RateLimitError)
15
+ - Auto-retry with exponential backoff and Retry-After support
16
+ - Auto-pagination helpers (page-based and search_after cursor-based)
17
+ - Context manager support
18
+ - py.typed marker for PEP 561 compliance
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 boiyelove
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,120 @@
1
+ Metadata-Version: 2.4
2
+ Name: circle-so-python-sdk
3
+ Version: 0.1.0
4
+ Summary: Python SDK for Circle.so - Admin V2, Headless Auth, and Headless Client V1 APIs
5
+ Project-URL: Homepage, https://github.com/boiyelove/circle-so-python-sdk
6
+ Project-URL: Documentation, https://github.com/boiyelove/circle-so-python-sdk/tree/main/docs
7
+ Project-URL: Repository, https://github.com/boiyelove/circle-so-python-sdk
8
+ Author: Damilola Afolabi
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: api,circle,circle.so,community,sdk
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.9
23
+ Requires-Dist: httpx>=0.24.0
24
+ Requires-Dist: pydantic>=2.0.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
27
+ Requires-Dist: pytest>=7.0; extra == 'dev'
28
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # circle-so-python-sdk
32
+
33
+ [![CI](https://github.com/boiyelove/circle-so-python-sdk/actions/workflows/ci.yml/badge.svg)](https://github.com/boiyelove/circle-so-python-sdk/actions/workflows/ci.yml)
34
+
35
+ Python SDK for [Circle.so](https://circle.so) covering three APIs:
36
+
37
+ - Headless Auth API -- token management for headless integrations
38
+ - Admin API V2 -- server-side community management (~120 endpoints)
39
+ - Headless Client API V1 -- member-facing operations (~100 endpoints)
40
+
41
+ ## Installation
42
+
43
+ ```bash
44
+ pip install circle-so-python-sdk
45
+ ```
46
+
47
+ ## Quick Start
48
+
49
+ ```python
50
+ from circle import CircleClient
51
+
52
+ # Admin API usage
53
+ client = CircleClient(api_token="YOUR_ADMIN_TOKEN")
54
+ community = client.admin.get_community()
55
+
56
+ # Headless Auth -- get member tokens
57
+ token = client.auth.create_auth_token(email="member@example.com")
58
+
59
+ # Headless Client -- use member access token
60
+ headless = CircleClient(api_token=token.access_token, community_url="https://your-community.circle.so")
61
+ spaces = headless.headless.list_spaces()
62
+ ```
63
+
64
+ ## Async Support
65
+
66
+ ```python
67
+ from circle import AsyncCircleClient
68
+
69
+ async with AsyncCircleClient(api_token="YOUR_TOKEN") as client:
70
+ members = await client.admin.list_community_members()
71
+ ```
72
+
73
+ ## API Coverage
74
+
75
+ | API | Endpoints | Sync | Async |
76
+ |---|---|---|---|
77
+ | Headless Auth | 4 | Yes | Yes |
78
+ | Admin V2 | ~118 | Yes | Yes |
79
+ | Headless Client V1 | ~101 | Yes | Yes |
80
+
81
+ ## Documentation
82
+
83
+ - [Quickstart](docs/quickstart.md) -- install, auth, basic usage
84
+ - [Admin API](docs/admin-api.md) -- all admin endpoints with examples
85
+ - [Headless API](docs/headless-api.md) -- all headless endpoints with examples
86
+ - [Auth API](docs/auth-api.md) -- headless auth token management
87
+ - [Models](docs/models.md) -- complete models reference
88
+ - [Webhooks](docs/webhooks.md) -- signature verification and payload parsing
89
+
90
+ ## Project Structure
91
+
92
+ ```
93
+ src/circle/
94
+ __init__.py # Public API exports
95
+ client.py # CircleClient / AsyncCircleClient facade
96
+ http.py # Sync/Async HTTP transport with retry
97
+ exceptions.py # Typed exceptions (401/403/404/422/429)
98
+ pagination.py # Auto-pagination helpers
99
+ rate_limit.py # Token bucket rate limiter
100
+ validation.py # Request body validation models
101
+ webhooks.py # Webhook signature verification
102
+ models/
103
+ auth.py # HeadlessAuthToken, RefreshedAccessToken
104
+ admin/ # ~35 Pydantic models for Admin API
105
+ headless/ # ~40 Pydantic models for Headless API
106
+ api/
107
+ auth.py # Headless Auth client (4 endpoints)
108
+ admin_*.py # 8 Admin API client modules
109
+ headless_*.py # 3 Headless API client modules
110
+ ```
111
+
112
+ ## Contributing
113
+
114
+ 1. Clone the repo and install in dev mode: `pip install -e .[dev]`
115
+ 2. Run tests: `pytest tests/ -v --ignore=tests/integration`
116
+ 3. Follow conventional commit format for commit messages
117
+
118
+ ## License
119
+
120
+ MIT
@@ -0,0 +1,90 @@
1
+ # circle-so-python-sdk
2
+
3
+ [![CI](https://github.com/boiyelove/circle-so-python-sdk/actions/workflows/ci.yml/badge.svg)](https://github.com/boiyelove/circle-so-python-sdk/actions/workflows/ci.yml)
4
+
5
+ Python SDK for [Circle.so](https://circle.so) covering three APIs:
6
+
7
+ - Headless Auth API -- token management for headless integrations
8
+ - Admin API V2 -- server-side community management (~120 endpoints)
9
+ - Headless Client API V1 -- member-facing operations (~100 endpoints)
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ pip install circle-so-python-sdk
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ```python
20
+ from circle import CircleClient
21
+
22
+ # Admin API usage
23
+ client = CircleClient(api_token="YOUR_ADMIN_TOKEN")
24
+ community = client.admin.get_community()
25
+
26
+ # Headless Auth -- get member tokens
27
+ token = client.auth.create_auth_token(email="member@example.com")
28
+
29
+ # Headless Client -- use member access token
30
+ headless = CircleClient(api_token=token.access_token, community_url="https://your-community.circle.so")
31
+ spaces = headless.headless.list_spaces()
32
+ ```
33
+
34
+ ## Async Support
35
+
36
+ ```python
37
+ from circle import AsyncCircleClient
38
+
39
+ async with AsyncCircleClient(api_token="YOUR_TOKEN") as client:
40
+ members = await client.admin.list_community_members()
41
+ ```
42
+
43
+ ## API Coverage
44
+
45
+ | API | Endpoints | Sync | Async |
46
+ |---|---|---|---|
47
+ | Headless Auth | 4 | Yes | Yes |
48
+ | Admin V2 | ~118 | Yes | Yes |
49
+ | Headless Client V1 | ~101 | Yes | Yes |
50
+
51
+ ## Documentation
52
+
53
+ - [Quickstart](docs/quickstart.md) -- install, auth, basic usage
54
+ - [Admin API](docs/admin-api.md) -- all admin endpoints with examples
55
+ - [Headless API](docs/headless-api.md) -- all headless endpoints with examples
56
+ - [Auth API](docs/auth-api.md) -- headless auth token management
57
+ - [Models](docs/models.md) -- complete models reference
58
+ - [Webhooks](docs/webhooks.md) -- signature verification and payload parsing
59
+
60
+ ## Project Structure
61
+
62
+ ```
63
+ src/circle/
64
+ __init__.py # Public API exports
65
+ client.py # CircleClient / AsyncCircleClient facade
66
+ http.py # Sync/Async HTTP transport with retry
67
+ exceptions.py # Typed exceptions (401/403/404/422/429)
68
+ pagination.py # Auto-pagination helpers
69
+ rate_limit.py # Token bucket rate limiter
70
+ validation.py # Request body validation models
71
+ webhooks.py # Webhook signature verification
72
+ models/
73
+ auth.py # HeadlessAuthToken, RefreshedAccessToken
74
+ admin/ # ~35 Pydantic models for Admin API
75
+ headless/ # ~40 Pydantic models for Headless API
76
+ api/
77
+ auth.py # Headless Auth client (4 endpoints)
78
+ admin_*.py # 8 Admin API client modules
79
+ headless_*.py # 3 Headless API client modules
80
+ ```
81
+
82
+ ## Contributing
83
+
84
+ 1. Clone the repo and install in dev mode: `pip install -e .[dev]`
85
+ 2. Run tests: `pytest tests/ -v --ignore=tests/integration`
86
+ 3. Follow conventional commit format for commit messages
87
+
88
+ ## License
89
+
90
+ MIT
@@ -0,0 +1,98 @@
1
+ # Admin API V2
2
+
3
+ Server-side community management. All methods available under `client.admin.*`.
4
+
5
+ ## Sub-clients
6
+
7
+ | Namespace | Description |
8
+ |---|---|
9
+ | `client.admin.community` | Community settings, member CRUD |
10
+ | `client.admin.access_groups` | Access groups and their members |
11
+ | `client.admin.spaces` | Spaces, space groups, space members |
12
+ | `client.admin.posts` | Posts, comments, topics |
13
+ | `client.admin.events` | Events and attendees |
14
+ | `client.admin.courses` | Course sections, lessons, progress |
15
+ | `client.admin.tags` | Member tags, tagged members, profile fields |
16
+ | `client.admin.misc` | Forms, segments, invitations, embeds, uploads, search, leaderboard, flagged content, live rooms |
17
+
18
+ ## Community
19
+
20
+ ```python
21
+ community = client.admin.get_community()
22
+ updated = client.admin.community.update_community(name="New Name")
23
+ ```
24
+
25
+ ## Community Members
26
+
27
+ ```python
28
+ members = client.admin.community.list_community_members(page=1, per_page=20)
29
+ member = client.admin.community.show_community_member(123)
30
+ created = client.admin.community.create_community_member(email="new@example.com", name="New User")
31
+ client.admin.community.update_community_member(123, headline="Updated")
32
+ client.admin.community.deactivate_community_member(123)
33
+ found = client.admin.community.search_community_member(email="user@example.com")
34
+ client.admin.community.ban_community_member(123)
35
+ ```
36
+
37
+ ## Spaces
38
+
39
+ ```python
40
+ spaces = client.admin.spaces.list_spaces(per_page=30)
41
+ space = client.admin.spaces.show_space(1)
42
+ new_space = client.admin.spaces.create_space(name="My Space", slug="my-space", space_group_id=1, space_type="basic")
43
+ client.admin.spaces.update_space(1, name="Renamed")
44
+ client.admin.spaces.delete_space(1)
45
+ summary = client.admin.spaces.get_space_ai_summary(1)
46
+ ```
47
+
48
+ ## Space Groups
49
+
50
+ ```python
51
+ groups = client.admin.spaces.list_space_groups()
52
+ group = client.admin.spaces.create_space_group(name="VIP", slug="vip")
53
+ ```
54
+
55
+ ## Posts
56
+
57
+ ```python
58
+ posts = client.admin.posts.list_posts(space_id=1)
59
+ created = client.admin.posts.create_post(space_id=1, name="Hello", body="World")
60
+ post = client.admin.posts.show_post(42)
61
+ client.admin.posts.update_post(42, name="Updated Title")
62
+ client.admin.posts.delete_post(42)
63
+ summary = client.admin.posts.get_post_summary(42)
64
+ ```
65
+
66
+ ## Events
67
+
68
+ ```python
69
+ events = client.admin.events.list_events(space_id=2)
70
+ event = client.admin.events.create_event(space_id=2, name="Meetup", status="published",
71
+ event_setting_attributes={"starts_at": "2024-06-15T09:00:00Z", "location_type": "virtual"})
72
+ attendees = client.admin.events.list_event_attendees(event_id=1)
73
+ ```
74
+
75
+ ## Courses
76
+
77
+ ```python
78
+ sections = client.admin.courses.list_course_sections(space_id=3)
79
+ lesson = client.admin.courses.create_course_lesson(name="Intro", section_id=1)
80
+ client.admin.courses.update_course_lesson_progress(lesson_id=1, member_email="user@example.com", status="completed")
81
+ ```
82
+
83
+ ## Tags
84
+
85
+ ```python
86
+ tags = client.admin.tags.list_member_tags()
87
+ tag = client.admin.tags.create_member_tag(name="VIP", color="#FF0000")
88
+ client.admin.tags.create_tagged_member(member_tag_id=1, user_email="user@example.com")
89
+ ```
90
+
91
+ ## Forms, Segments, and More
92
+
93
+ ```python
94
+ forms = client.admin.misc.list_forms()
95
+ segments = client.admin.misc.list_community_segments()
96
+ results = client.admin.misc.advanced_search(query="python")
97
+ leaderboard = client.admin.misc.get_leaderboard()
98
+ ```
@@ -0,0 +1,38 @@
1
+ # Headless Auth API
2
+
3
+ Token management for headless integrations. Uses your admin API token to generate member access tokens.
4
+
5
+ ## Endpoints
6
+
7
+ ### Create Auth Token
8
+
9
+ ```python
10
+ token = client.auth.create_auth_token(email="member@example.com")
11
+ # or by SSO user ID
12
+ token = client.auth.create_auth_token(sso_user_id="abc123")
13
+ # or by community member ID
14
+ token = client.auth.create_auth_token(community_member_id=42)
15
+
16
+ print(token.access_token)
17
+ print(token.refresh_token)
18
+ print(token.community_member_id)
19
+ ```
20
+
21
+ ### Refresh Access Token
22
+
23
+ ```python
24
+ refreshed = client.auth.refresh_access_token(refresh_token="...")
25
+ print(refreshed.access_token)
26
+ ```
27
+
28
+ ### Revoke Access Token
29
+
30
+ ```python
31
+ client.auth.revoke_access_token(access_token="...")
32
+ ```
33
+
34
+ ### Revoke Refresh Token
35
+
36
+ ```python
37
+ client.auth.revoke_refresh_token(refresh_token="...")
38
+ ```
@@ -0,0 +1,103 @@
1
+ # Headless Client API V1
2
+
3
+ Member-facing operations. Requires a member access token from the Headless Auth API.
4
+
5
+ ## Setup
6
+
7
+ ```python
8
+ from circle import CircleClient
9
+
10
+ # Get member token first
11
+ admin = CircleClient(api_token="ADMIN_TOKEN")
12
+ token = admin.auth.create_auth_token(email="member@example.com")
13
+
14
+ # Create headless client with member token
15
+ client = CircleClient(api_token=token.access_token, community_url="https://your.circle.so")
16
+ ```
17
+
18
+ ## Sub-clients
19
+
20
+ | Namespace | Description |
21
+ |---|---|
22
+ | `client.headless.spaces_posts` | Spaces, posts, comments, replies, likes |
23
+ | `client.headless.chat_notif_members` | Chat, notifications, members, events |
24
+ | `client.headless.misc` | Courses, search, bookmarks, uploads, notification prefs |
25
+
26
+ ## Spaces
27
+
28
+ ```python
29
+ spaces = client.headless.list_spaces()
30
+ space = client.headless.spaces_posts.get_space(1)
31
+ client.headless.spaces_posts.join_space(1)
32
+ client.headless.spaces_posts.leave_space(1)
33
+ ```
34
+
35
+ ## Posts
36
+
37
+ ```python
38
+ posts = client.headless.list_posts(1, per_page=20)
39
+ post = client.headless.spaces_posts.get_post(1, 42)
40
+ new_post = client.headless.spaces_posts.create_post(1, name="My Post", body="Content")
41
+ client.headless.spaces_posts.like_post(42)
42
+ client.headless.spaces_posts.follow_post(42)
43
+ home = client.headless.spaces_posts.get_home_posts()
44
+ ```
45
+
46
+ ## Comments and Replies
47
+
48
+ ```python
49
+ comments = client.headless.spaces_posts.list_comments(42)
50
+ comment = client.headless.spaces_posts.create_comment(42, body="Nice post!")
51
+ replies = client.headless.spaces_posts.list_replies(comment.id)
52
+ client.headless.spaces_posts.create_reply(comment.id, body="Thanks!")
53
+ ```
54
+
55
+ ## Chat
56
+
57
+ ```python
58
+ rooms = client.headless.chat_notif_members.list_chat_rooms()
59
+ room = client.headless.chat_notif_members.create_chat_room(kind="direct", community_member_ids=["2"])
60
+ messages = client.headless.chat_notif_members.list_chat_messages("room-uuid")
61
+ client.headless.chat_notif_members.create_chat_message("room-uuid", rich_text_body={...})
62
+ ```
63
+
64
+ ## Notifications
65
+
66
+ ```python
67
+ notifs = client.headless.chat_notif_members.list_notifications()
68
+ client.headless.chat_notif_members.mark_notification_read(1)
69
+ client.headless.chat_notif_members.mark_all_notifications_read()
70
+ count = client.headless.chat_notif_members.get_new_notifications_count()
71
+ ```
72
+
73
+ ## Members
74
+
75
+ ```python
76
+ members = client.headless.chat_notif_members.list_community_members()
77
+ me = client.headless.chat_notif_members.get_current_member()
78
+ profile = client.headless.chat_notif_members.get_public_profile(2)
79
+ client.headless.chat_notif_members.update_profile(headline="New headline")
80
+ ```
81
+
82
+ ## Courses
83
+
84
+ ```python
85
+ sections = client.headless.misc.list_course_sections(course_id=1)
86
+ lesson = client.headless.misc.get_lesson(course_id=1, lesson_id=2)
87
+ client.headless.misc.update_lesson_progress(1, 2, status="completed")
88
+ ```
89
+
90
+ ## Search
91
+
92
+ ```python
93
+ results = client.headless.misc.search(search_text="python")
94
+ advanced = client.headless.misc.advanced_search(query="python", type="posts")
95
+ ```
96
+
97
+ ## Bookmarks
98
+
99
+ ```python
100
+ bookmarks = client.headless.misc.list_bookmarks()
101
+ bm = client.headless.misc.create_bookmark(record_id=42, bookmark_type="post")
102
+ client.headless.misc.delete_bookmark(bm.id)
103
+ ```
@@ -0,0 +1,40 @@
1
+ # Models Reference
2
+
3
+ All response models use Pydantic V2 with `extra="allow"` so new API fields won't break the SDK.
4
+
5
+ ## Base
6
+
7
+ - `CircleModel` -- base for all models, allows extra fields
8
+ - `PaginatedResponse[T]` -- generic paginated list with `page`, `per_page`, `has_next_page`, `count`, `records`
9
+ - `ErrorResponse` -- `success`, `message`, `error_details`
10
+
11
+ ## Auth Models (`circle.models.auth`)
12
+
13
+ - `HeadlessAuthToken` -- `access_token`, `refresh_token`, expiry timestamps, `community_member_id`, `community_id`
14
+ - `RefreshedAccessToken` -- `access_token`, `access_token_expires_at`
15
+
16
+ ## Admin Models (`circle.models.admin`)
17
+
18
+ | Module | Key Models |
19
+ |---|---|
20
+ | `community` | `Community`, `CommunitySetting`, `CommunityPrefs`, `ChatPreferences` |
21
+ | `members` | `CommunityMember`, `CommunityMemberList`, `CommunityMemberCreated` |
22
+ | `spaces` | `Space`, `SpaceGroup`, `SpaceMember`, `SpaceGroupMember`, `SpaceAISummary` |
23
+ | `posts` | `BasicPost`, `ImagePost`, `Comment`, `Topic` + created/updated/deleted responses |
24
+ | `events` | `Event`, `EventAttendee` |
25
+ | `courses` | `CourseSection`, `CourseLesson` |
26
+ | `tags` | `MemberTag`, `TaggedMember`, `ProfileField` |
27
+ | `misc` | `AccessGroup`, `Form`, `FormSubmission`, `CommunitySegment`, `InvitationLink`, `Embed`, `DirectUpload`, `LiveRoom`, `FlaggedContent`, `LeaderboardMember`, `AdvancedSearchResults` |
28
+
29
+ ## Headless Models (`circle.models.headless`)
30
+
31
+ | Module | Key Models |
32
+ |---|---|
33
+ | `spaces` | `HeadlessSpace`, `SpaceNotificationDetail`, `SpaceBookmark` |
34
+ | `posts` | `HeadlessPost`, `HeadlessImagePost`, `HeadlessEventPost`, `SharedCommunityMember` |
35
+ | `comments` | `HeadlessComment`, `UserLike` |
36
+ | `chat` | `ChatRoom`, `ChatRoomMessage`, `ChatRoomMessages`, `ChatThread`, `ChatRoomParticipant` |
37
+ | `notifications` | `Notification`, `NewNotificationsCount`, `MediumNotificationPreferences` |
38
+ | `members` | `CurrentCommunityMember`, `PublicProfile`, `BasicCommunityMember`, `SearchedMember` |
39
+ | `courses` | `Section`, `Lesson`, `LessonFile`, `QuizAttempt` |
40
+ | `misc` | `Bookmark`, `HeadlessEventAttendee`, `RecurringEvent`, `SearchResults`, `CommunityLink`, `HeadlessDirectUpload` |
@@ -0,0 +1,75 @@
1
+ # Quickstart
2
+
3
+ ## Installation
4
+
5
+ ```bash
6
+ pip install circle-so-python-sdk
7
+ ```
8
+
9
+ ## Authentication
10
+
11
+ Circle.so uses different auth schemes per API:
12
+
13
+ - Admin API V2: Uses `Token AUTH_TOKEN` header (server-side admin token)
14
+ - Headless Auth: Uses `Bearer AUTH_TOKEN` header (admin token to generate member tokens)
15
+ - Headless Client V1: Uses `Bearer ACCESS_TOKEN` header (member access token)
16
+
17
+ ## Basic Usage
18
+
19
+ ```python
20
+ from circle import CircleClient
21
+
22
+ # Create client with your admin API token
23
+ client = CircleClient(api_token="YOUR_ADMIN_TOKEN")
24
+
25
+ # Admin API -- manage your community
26
+ community = client.admin.get_community()
27
+ members = client.admin.list_community_members(per_page=20)
28
+
29
+ # Headless Auth -- get a member access token
30
+ token = client.auth.create_auth_token(email="member@example.com")
31
+
32
+ # Headless Client -- act as a member
33
+ member_client = CircleClient(
34
+ api_token=token.access_token,
35
+ community_url="https://your-community.circle.so"
36
+ )
37
+ spaces = member_client.headless.list_spaces()
38
+ ```
39
+
40
+ ## Async Usage
41
+
42
+ ```python
43
+ from circle import AsyncCircleClient
44
+
45
+ async with AsyncCircleClient(api_token="YOUR_TOKEN") as client:
46
+ community = await client.admin.get_community()
47
+ members = await client.admin.list_community_members()
48
+ ```
49
+
50
+ ## Auto-Pagination
51
+
52
+ ```python
53
+ from circle import CircleClient
54
+ from circle.pagination import paginate
55
+
56
+ client = CircleClient(api_token="YOUR_TOKEN")
57
+
58
+ # Iterate all members across all pages
59
+ for member in paginate(client.admin.community.list_community_members, per_page=100):
60
+ print(member.name)
61
+ ```
62
+
63
+ ## Error Handling
64
+
65
+ ```python
66
+ from circle import CircleClient, AuthenticationError, NotFoundError
67
+
68
+ client = CircleClient(api_token="YOUR_TOKEN")
69
+ try:
70
+ member = client.admin.community.show_community_member(99999)
71
+ except NotFoundError as e:
72
+ print(f"Not found: {e}")
73
+ except AuthenticationError as e:
74
+ print(f"Auth failed: {e}")
75
+ ```