devrev-Python-SDK 1.0.0__py3-none-any.whl

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 (45) hide show
  1. devrev/__init__.py +47 -0
  2. devrev/client.py +343 -0
  3. devrev/config.py +180 -0
  4. devrev/exceptions.py +205 -0
  5. devrev/models/__init__.py +499 -0
  6. devrev/models/accounts.py +187 -0
  7. devrev/models/articles.py +109 -0
  8. devrev/models/base.py +147 -0
  9. devrev/models/code_changes.py +103 -0
  10. devrev/models/conversations.py +115 -0
  11. devrev/models/dev_users.py +258 -0
  12. devrev/models/groups.py +140 -0
  13. devrev/models/links.py +107 -0
  14. devrev/models/parts.py +110 -0
  15. devrev/models/rev_users.py +177 -0
  16. devrev/models/slas.py +112 -0
  17. devrev/models/tags.py +90 -0
  18. devrev/models/timeline_entries.py +100 -0
  19. devrev/models/webhooks.py +109 -0
  20. devrev/models/works.py +280 -0
  21. devrev/py.typed +1 -0
  22. devrev/services/__init__.py +74 -0
  23. devrev/services/accounts.py +325 -0
  24. devrev/services/articles.py +80 -0
  25. devrev/services/base.py +234 -0
  26. devrev/services/code_changes.py +80 -0
  27. devrev/services/conversations.py +98 -0
  28. devrev/services/dev_users.py +401 -0
  29. devrev/services/groups.py +103 -0
  30. devrev/services/links.py +68 -0
  31. devrev/services/parts.py +100 -0
  32. devrev/services/rev_users.py +235 -0
  33. devrev/services/slas.py +82 -0
  34. devrev/services/tags.py +80 -0
  35. devrev/services/timeline_entries.py +80 -0
  36. devrev/services/webhooks.py +80 -0
  37. devrev/services/works.py +363 -0
  38. devrev/utils/__init__.py +14 -0
  39. devrev/utils/deprecation.py +49 -0
  40. devrev/utils/http.py +521 -0
  41. devrev/utils/logging.py +139 -0
  42. devrev/utils/pagination.py +155 -0
  43. devrev_python_sdk-1.0.0.dist-info/METADATA +774 -0
  44. devrev_python_sdk-1.0.0.dist-info/RECORD +45 -0
  45. devrev_python_sdk-1.0.0.dist-info/WHEEL +4 -0
devrev/models/works.py ADDED
@@ -0,0 +1,280 @@
1
+ """Work models for DevRev SDK.
2
+
3
+ This module contains Pydantic models for Work-related API operations.
4
+ Works include issues, tickets, tasks, and opportunities.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from datetime import datetime
10
+ from enum import Enum
11
+ from typing import Any
12
+
13
+ from pydantic import Field
14
+
15
+ from devrev.models.base import (
16
+ CustomSchemaSpec,
17
+ DateFilter,
18
+ DevRevBaseModel,
19
+ DevRevResponseModel,
20
+ PaginatedResponse,
21
+ SetTagWithValue,
22
+ StageInfo,
23
+ StageUpdate,
24
+ TagWithValue,
25
+ UserSummary,
26
+ )
27
+
28
+
29
+ class WorkType(str, Enum):
30
+ """Work item type enumeration."""
31
+
32
+ ISSUE = "issue"
33
+ TICKET = "ticket"
34
+ TASK = "task"
35
+ OPPORTUNITY = "opportunity"
36
+
37
+
38
+ class IssuePriority(str, Enum):
39
+ """Issue priority enumeration."""
40
+
41
+ P0 = "p0"
42
+ P1 = "p1"
43
+ P2 = "p2"
44
+ P3 = "p3"
45
+
46
+
47
+ class TicketSeverity(str, Enum):
48
+ """Ticket severity enumeration."""
49
+
50
+ BLOCKER = "blocker"
51
+ HIGH = "high"
52
+ LOW = "low"
53
+ MEDIUM = "medium"
54
+
55
+
56
+ class TicketChannels(str, Enum):
57
+ """Ticket channel enumeration."""
58
+
59
+ EMAIL = "email"
60
+ PLUG = "plug"
61
+ SLACK = "slack"
62
+ OTHER = "other"
63
+
64
+
65
+ class Work(DevRevResponseModel):
66
+ """DevRev Work item model.
67
+
68
+ Represents a work item (issue, ticket, task, or opportunity).
69
+ """
70
+
71
+ id: str = Field(..., description="Work item ID")
72
+ type: WorkType = Field(..., description="Work item type")
73
+ display_id: str | None = Field(default=None, description="Human-readable display ID")
74
+ title: str | None = Field(default=None, description="Work item title")
75
+ body: str | None = Field(default=None, description="Work item body/description")
76
+ created_date: datetime | None = Field(default=None, description="Creation timestamp")
77
+ modified_date: datetime | None = Field(default=None, description="Last modification timestamp")
78
+ created_by: UserSummary | None = Field(default=None, description="User who created the work")
79
+ modified_by: UserSummary | None = Field(
80
+ default=None, description="User who last modified the work"
81
+ )
82
+ owned_by: list[UserSummary] | None = Field(default=None, description="Work owners")
83
+ reported_by: list[UserSummary] | None = Field(
84
+ default=None, description="Users who reported this work"
85
+ )
86
+ applies_to_part: str | None = Field(default=None, description="Part this work applies to")
87
+ stage: StageInfo | None = Field(default=None, description="Work stage")
88
+ tags: list[TagWithValue] | None = Field(default=None, description="Work tags")
89
+ priority: str | None = Field(default=None, description="Issue priority")
90
+ severity: str | None = Field(default=None, description="Ticket severity")
91
+ target_close_date: datetime | None = Field(default=None, description="Target close date")
92
+ actual_close_date: datetime | None = Field(default=None, description="Actual close date")
93
+ custom_fields: dict[str, Any] | None = Field(default=None, description="Custom fields")
94
+ external_ref: str | None = Field(default=None, description="External reference")
95
+
96
+
97
+ class WorkSummary(DevRevResponseModel):
98
+ """Summary of a Work item for list/reference operations."""
99
+
100
+ id: str = Field(..., description="Work item ID")
101
+ type: WorkType = Field(..., description="Work item type")
102
+ display_id: str | None = Field(default=None, description="Human-readable display ID")
103
+ title: str | None = Field(default=None, description="Work item title")
104
+
105
+
106
+ # Request Models
107
+
108
+
109
+ class WorksCreateRequestIssue(DevRevBaseModel):
110
+ """Issue-specific fields for work creation."""
111
+
112
+ priority: IssuePriority | None = Field(default=None, description="Issue priority")
113
+ priority_v2: int | None = Field(default=None, description="Priority enum ID")
114
+ target_start_date: datetime | None = Field(default=None, description="Target start date")
115
+ developed_with: list[str] | None = Field(
116
+ default=None, description="Part IDs associated with issue"
117
+ )
118
+
119
+
120
+ class WorksCreateRequestTicket(DevRevBaseModel):
121
+ """Ticket-specific fields for work creation."""
122
+
123
+ account: str | None = Field(default=None, description="Associated account ID")
124
+ channels: list[TicketChannels] | None = Field(default=None, description="Ticket channels")
125
+ rev_org: str | None = Field(default=None, description="Rev organization ID")
126
+ severity: TicketSeverity | None = Field(default=None, description="Ticket severity")
127
+ is_spam: bool | None = Field(default=None, description="Whether the ticket is spam")
128
+ needs_response: bool | None = Field(default=None, description="Whether response is needed")
129
+
130
+
131
+ class WorksCreateRequest(DevRevBaseModel):
132
+ """Request to create a work item."""
133
+
134
+ type: WorkType = Field(..., description="Work item type")
135
+ title: str = Field(..., description="Work title", min_length=1, max_length=256)
136
+ applies_to_part: str = Field(..., description="Part ID this work applies to")
137
+ owned_by: list[str] | None = Field(default=None, description="Owner user IDs")
138
+ body: str | None = Field(default=None, description="Work body", max_length=65536)
139
+ artifacts: list[str] | None = Field(default=None, description="Artifact IDs")
140
+ external_ref: str | None = Field(default=None, description="External reference")
141
+ target_close_date: datetime | None = Field(default=None, description="Target close date")
142
+ custom_fields: dict[str, Any] | None = Field(default=None, description="Custom fields")
143
+ custom_schema_spec: CustomSchemaSpec | None = Field(
144
+ default=None, description="Custom schema spec"
145
+ )
146
+ # Issue-specific
147
+ priority: IssuePriority | None = Field(default=None, description="Issue priority (for issues)")
148
+ # Ticket-specific
149
+ severity: TicketSeverity | None = Field(
150
+ default=None, description="Ticket severity (for tickets)"
151
+ )
152
+
153
+
154
+ class WorksGetRequest(DevRevBaseModel):
155
+ """Request to get a work item by ID."""
156
+
157
+ id: str = Field(..., description="Work item ID")
158
+
159
+
160
+ class WorksListRequest(DevRevBaseModel):
161
+ """Request to list work items."""
162
+
163
+ type: list[WorkType] | None = Field(default=None, description="Filter by work types")
164
+ applies_to_part: list[str] | None = Field(default=None, description="Filter by part IDs")
165
+ created_by: list[str] | None = Field(default=None, description="Filter by creator user IDs")
166
+ created_date: DateFilter | None = Field(default=None, description="Filter by creation date")
167
+ cursor: str | None = Field(default=None, description="Pagination cursor")
168
+ external_ref: list[str] | None = Field(default=None, description="Filter by external refs")
169
+ limit: int | None = Field(default=None, ge=1, le=100, description="Max results to return")
170
+ modified_date: DateFilter | None = Field(
171
+ default=None, description="Filter by modification date"
172
+ )
173
+ owned_by: list[str] | None = Field(default=None, description="Filter by owner user IDs")
174
+ sort_by: list[str] | None = Field(default=None, description="Sort order")
175
+ stage_name: list[str] | None = Field(default=None, description="Filter by stage names")
176
+ target_close_date: DateFilter | None = Field(
177
+ default=None, description="Filter by target close date"
178
+ )
179
+
180
+
181
+ class WorksUpdateRequestOwnedBy(DevRevBaseModel):
182
+ """Owned by update for work items."""
183
+
184
+ set: list[str] | None = Field(default=None, description="Set owner IDs")
185
+
186
+
187
+ class WorksUpdateRequestTags(DevRevBaseModel):
188
+ """Tags update for work items."""
189
+
190
+ set: list[SetTagWithValue] | None = Field(default=None, description="Set tags")
191
+
192
+
193
+ class WorksUpdateRequest(DevRevBaseModel):
194
+ """Request to update a work item."""
195
+
196
+ id: str = Field(..., description="Work item ID")
197
+ title: str | None = Field(default=None, description="New title")
198
+ body: str | None = Field(default=None, description="New body")
199
+ applies_to_part: str | None = Field(default=None, description="New part ID")
200
+ owned_by: WorksUpdateRequestOwnedBy | None = Field(default=None, description="New owners")
201
+ stage: StageUpdate | None = Field(default=None, description="New stage")
202
+ tags: WorksUpdateRequestTags | None = Field(default=None, description="New tags")
203
+ target_close_date: datetime | None = Field(default=None, description="New target close date")
204
+ custom_fields: dict[str, Any] | None = Field(
205
+ default=None, description="Custom fields to update"
206
+ )
207
+ # Issue-specific
208
+ priority: IssuePriority | None = Field(default=None, description="New priority")
209
+ # Ticket-specific
210
+ severity: TicketSeverity | None = Field(default=None, description="New severity")
211
+
212
+
213
+ class WorksDeleteRequest(DevRevBaseModel):
214
+ """Request to delete a work item."""
215
+
216
+ id: str = Field(..., description="Work item ID to delete")
217
+
218
+
219
+ class WorksExportRequest(DevRevBaseModel):
220
+ """Request to export work items."""
221
+
222
+ type: list[WorkType] | None = Field(default=None, description="Filter by work types")
223
+ applies_to_part: list[str] | None = Field(default=None, description="Filter by part IDs")
224
+ created_by: list[str] | None = Field(default=None, description="Filter by creator user IDs")
225
+ created_date: DateFilter | None = Field(default=None, description="Filter by creation date")
226
+ first: int | None = Field(default=None, ge=1, le=10000, description="Max results")
227
+
228
+
229
+ class WorksCountRequest(DevRevBaseModel):
230
+ """Request to count work items."""
231
+
232
+ type: list[WorkType] | None = Field(default=None, description="Filter by work types")
233
+ applies_to_part: list[str] | None = Field(default=None, description="Filter by part IDs")
234
+ created_by: list[str] | None = Field(default=None, description="Filter by creator user IDs")
235
+ owned_by: list[str] | None = Field(default=None, description="Filter by owner user IDs")
236
+
237
+
238
+ # Response Models
239
+
240
+
241
+ class WorksCreateResponse(DevRevResponseModel):
242
+ """Response from creating a work item."""
243
+
244
+ work: Work = Field(..., description="Created work item")
245
+
246
+
247
+ class WorksGetResponse(DevRevResponseModel):
248
+ """Response from getting a work item."""
249
+
250
+ work: Work = Field(..., description="Retrieved work item")
251
+
252
+
253
+ class WorksListResponse(PaginatedResponse):
254
+ """Response from listing work items."""
255
+
256
+ works: list[Work] = Field(..., description="List of work items")
257
+
258
+
259
+ class WorksUpdateResponse(DevRevResponseModel):
260
+ """Response from updating a work item."""
261
+
262
+ work: Work = Field(..., description="Updated work item")
263
+
264
+
265
+ class WorksDeleteResponse(DevRevResponseModel):
266
+ """Response from deleting a work item."""
267
+
268
+ pass # Empty response body
269
+
270
+
271
+ class WorksExportResponse(DevRevResponseModel):
272
+ """Response from exporting work items."""
273
+
274
+ works: list[Work] = Field(..., description="Exported work items")
275
+
276
+
277
+ class WorksCountResponse(DevRevResponseModel):
278
+ """Response from counting work items."""
279
+
280
+ count: int = Field(..., description="Number of matching work items")
devrev/py.typed ADDED
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,74 @@
1
+ """DevRev SDK Service Classes.
2
+
3
+ This module contains service classes for interacting with DevRev API endpoints.
4
+ """
5
+
6
+ from devrev.services.accounts import AccountsService, AsyncAccountsService
7
+ from devrev.services.articles import ArticlesService, AsyncArticlesService
8
+ from devrev.services.base import AsyncBaseService, BaseService
9
+ from devrev.services.code_changes import AsyncCodeChangesService, CodeChangesService
10
+ from devrev.services.conversations import (
11
+ AsyncConversationsService,
12
+ ConversationsService,
13
+ )
14
+ from devrev.services.dev_users import AsyncDevUsersService, DevUsersService
15
+ from devrev.services.groups import AsyncGroupsService, GroupsService
16
+ from devrev.services.links import AsyncLinksService, LinksService
17
+ from devrev.services.parts import AsyncPartsService, PartsService
18
+ from devrev.services.rev_users import AsyncRevUsersService, RevUsersService
19
+ from devrev.services.slas import AsyncSlasService, SlasService
20
+ from devrev.services.tags import AsyncTagsService, TagsService
21
+ from devrev.services.timeline_entries import (
22
+ AsyncTimelineEntriesService,
23
+ TimelineEntriesService,
24
+ )
25
+ from devrev.services.webhooks import AsyncWebhooksService, WebhooksService
26
+ from devrev.services.works import AsyncWorksService, WorksService
27
+
28
+ __all__ = [
29
+ # Base
30
+ "BaseService",
31
+ "AsyncBaseService",
32
+ # Accounts
33
+ "AccountsService",
34
+ "AsyncAccountsService",
35
+ # Articles
36
+ "ArticlesService",
37
+ "AsyncArticlesService",
38
+ # Code Changes
39
+ "CodeChangesService",
40
+ "AsyncCodeChangesService",
41
+ # Conversations
42
+ "ConversationsService",
43
+ "AsyncConversationsService",
44
+ # Dev Users
45
+ "DevUsersService",
46
+ "AsyncDevUsersService",
47
+ # Groups
48
+ "GroupsService",
49
+ "AsyncGroupsService",
50
+ # Links
51
+ "LinksService",
52
+ "AsyncLinksService",
53
+ # Parts
54
+ "PartsService",
55
+ "AsyncPartsService",
56
+ # Rev Users
57
+ "RevUsersService",
58
+ "AsyncRevUsersService",
59
+ # SLAs
60
+ "SlasService",
61
+ "AsyncSlasService",
62
+ # Tags
63
+ "TagsService",
64
+ "AsyncTagsService",
65
+ # Timeline Entries
66
+ "TimelineEntriesService",
67
+ "AsyncTimelineEntriesService",
68
+ # Webhooks
69
+ "WebhooksService",
70
+ "AsyncWebhooksService",
71
+ # Works
72
+ "WorksService",
73
+ "AsyncWorksService",
74
+ ]
@@ -0,0 +1,325 @@
1
+ """Accounts service for DevRev SDK.
2
+
3
+ This module provides the AccountsService for managing DevRev accounts.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from collections.abc import Sequence
9
+ from typing import TYPE_CHECKING, Any
10
+
11
+ from devrev.models.accounts import (
12
+ Account,
13
+ AccountsCreateRequest,
14
+ AccountsCreateResponse,
15
+ AccountsDeleteRequest,
16
+ AccountsDeleteResponse,
17
+ AccountsExportRequest,
18
+ AccountsExportResponse,
19
+ AccountsGetRequest,
20
+ AccountsGetResponse,
21
+ AccountsListRequest,
22
+ AccountsListResponse,
23
+ AccountsMergeRequest,
24
+ AccountsMergeResponse,
25
+ AccountsUpdateRequest,
26
+ AccountsUpdateResponse,
27
+ )
28
+ from devrev.services.base import AsyncBaseService, BaseService
29
+
30
+ if TYPE_CHECKING:
31
+ from devrev.utils.http import AsyncHTTPClient, HTTPClient
32
+
33
+
34
+ class AccountsService(BaseService):
35
+ """Synchronous service for managing DevRev accounts.
36
+
37
+ Provides methods for creating, reading, updating, and deleting accounts.
38
+
39
+ Example:
40
+ ```python
41
+ from devrev import DevRevClient
42
+
43
+ client = DevRevClient()
44
+ accounts = client.accounts.list()
45
+ ```
46
+ """
47
+
48
+ def __init__(self, http_client: HTTPClient) -> None:
49
+ """Initialize the AccountsService."""
50
+ super().__init__(http_client)
51
+
52
+ def create(
53
+ self,
54
+ display_name: str,
55
+ *,
56
+ description: str | None = None,
57
+ domains: list[str] | None = None,
58
+ external_refs: list[str] | None = None,
59
+ owned_by: list[str] | None = None,
60
+ tier: str | None = None,
61
+ custom_fields: dict[str, Any] | None = None,
62
+ ) -> Account:
63
+ """Create a new account.
64
+
65
+ Args:
66
+ display_name: Account display name
67
+ description: Account description
68
+ domains: Associated domains
69
+ external_refs: External references
70
+ owned_by: Owner user IDs
71
+ tier: Account tier
72
+ custom_fields: Custom fields
73
+
74
+ Returns:
75
+ The created Account
76
+ """
77
+ request = AccountsCreateRequest(
78
+ display_name=display_name,
79
+ description=description,
80
+ domains=domains,
81
+ external_refs=external_refs,
82
+ owned_by=owned_by,
83
+ tier=tier,
84
+ custom_fields=custom_fields,
85
+ )
86
+ response = self._post("/accounts.create", request, AccountsCreateResponse)
87
+ return response.account
88
+
89
+ def get(self, id: str) -> Account:
90
+ """Get an account by ID.
91
+
92
+ Args:
93
+ id: Account ID
94
+
95
+ Returns:
96
+ The Account
97
+ """
98
+ request = AccountsGetRequest(id=id)
99
+ response = self._post("/accounts.get", request, AccountsGetResponse)
100
+ return response.account
101
+
102
+ def list(
103
+ self,
104
+ *,
105
+ cursor: str | None = None,
106
+ limit: int | None = None,
107
+ display_name: list[str] | None = None,
108
+ domains: list[str] | None = None,
109
+ owned_by: list[str] | None = None,
110
+ ) -> AccountsListResponse:
111
+ """List accounts.
112
+
113
+ Args:
114
+ cursor: Pagination cursor
115
+ limit: Maximum number of results
116
+ display_name: Filter by display names
117
+ domains: Filter by domains
118
+ owned_by: Filter by owner user IDs
119
+
120
+ Returns:
121
+ Paginated list of accounts
122
+ """
123
+ request = AccountsListRequest(
124
+ cursor=cursor,
125
+ limit=limit,
126
+ display_name=display_name,
127
+ domains=domains,
128
+ owned_by=owned_by,
129
+ )
130
+ return self._post("/accounts.list", request, AccountsListResponse)
131
+
132
+ def update(
133
+ self,
134
+ id: str,
135
+ *,
136
+ display_name: str | None = None,
137
+ description: str | None = None,
138
+ tier: str | None = None,
139
+ custom_fields: dict[str, Any] | None = None,
140
+ ) -> Account:
141
+ """Update an account.
142
+
143
+ Args:
144
+ id: Account ID
145
+ display_name: New display name
146
+ description: New description
147
+ tier: New tier
148
+ custom_fields: Custom fields to update
149
+
150
+ Returns:
151
+ The updated Account
152
+ """
153
+ request = AccountsUpdateRequest(
154
+ id=id,
155
+ display_name=display_name,
156
+ description=description,
157
+ tier=tier,
158
+ custom_fields=custom_fields,
159
+ )
160
+ response = self._post("/accounts.update", request, AccountsUpdateResponse)
161
+ return response.account
162
+
163
+ def delete(self, id: str) -> None:
164
+ """Delete an account.
165
+
166
+ Args:
167
+ id: Account ID to delete
168
+ """
169
+ request = AccountsDeleteRequest(id=id)
170
+ self._post("/accounts.delete", request, AccountsDeleteResponse)
171
+
172
+ def merge(self, primary_account: str, secondary_account: str) -> Account:
173
+ """Merge two accounts.
174
+
175
+ Args:
176
+ primary_account: Primary account ID (will be retained)
177
+ secondary_account: Secondary account ID (will be merged)
178
+
179
+ Returns:
180
+ The merged Account
181
+ """
182
+ request = AccountsMergeRequest(
183
+ primary_account=primary_account,
184
+ secondary_account=secondary_account,
185
+ )
186
+ response = self._post("/accounts.merge", request, AccountsMergeResponse)
187
+ return response.account
188
+
189
+ def export(
190
+ self,
191
+ *,
192
+ created_by: Sequence[str] | None = None,
193
+ first: int | None = None,
194
+ ) -> Sequence[Account]:
195
+ """Export accounts.
196
+
197
+ Args:
198
+ created_by: Filter by creator user IDs
199
+ first: Maximum number of results
200
+
201
+ Returns:
202
+ List of exported accounts
203
+ """
204
+ request = AccountsExportRequest(
205
+ created_by=created_by,
206
+ first=first,
207
+ )
208
+ response = self._post("/accounts.export", request, AccountsExportResponse)
209
+ return response.accounts
210
+
211
+
212
+ class AsyncAccountsService(AsyncBaseService):
213
+ """Asynchronous service for managing DevRev accounts.
214
+
215
+ Provides async methods for creating, reading, updating, and deleting accounts.
216
+
217
+ Example:
218
+ ```python
219
+ from devrev import AsyncDevRevClient
220
+
221
+ async with AsyncDevRevClient() as client:
222
+ accounts = await client.accounts.list()
223
+ ```
224
+ """
225
+
226
+ def __init__(self, http_client: AsyncHTTPClient) -> None:
227
+ """Initialize the AsyncAccountsService."""
228
+ super().__init__(http_client)
229
+
230
+ async def create(
231
+ self,
232
+ display_name: str,
233
+ *,
234
+ description: str | None = None,
235
+ domains: list[str] | None = None,
236
+ external_refs: list[str] | None = None,
237
+ owned_by: list[str] | None = None,
238
+ tier: str | None = None,
239
+ custom_fields: dict[str, Any] | None = None,
240
+ ) -> Account:
241
+ """Create a new account."""
242
+ request = AccountsCreateRequest(
243
+ display_name=display_name,
244
+ description=description,
245
+ domains=domains,
246
+ external_refs=external_refs,
247
+ owned_by=owned_by,
248
+ tier=tier,
249
+ custom_fields=custom_fields,
250
+ )
251
+ response = await self._post("/accounts.create", request, AccountsCreateResponse)
252
+ return response.account
253
+
254
+ async def get(self, id: str) -> Account:
255
+ """Get an account by ID."""
256
+ request = AccountsGetRequest(id=id)
257
+ response = await self._post("/accounts.get", request, AccountsGetResponse)
258
+ return response.account
259
+
260
+ async def list(
261
+ self,
262
+ *,
263
+ cursor: str | None = None,
264
+ limit: int | None = None,
265
+ display_name: list[str] | None = None,
266
+ domains: list[str] | None = None,
267
+ owned_by: list[str] | None = None,
268
+ ) -> AccountsListResponse:
269
+ """List accounts."""
270
+ request = AccountsListRequest(
271
+ cursor=cursor,
272
+ limit=limit,
273
+ display_name=display_name,
274
+ domains=domains,
275
+ owned_by=owned_by,
276
+ )
277
+ return await self._post("/accounts.list", request, AccountsListResponse)
278
+
279
+ async def update(
280
+ self,
281
+ id: str,
282
+ *,
283
+ display_name: str | None = None,
284
+ description: str | None = None,
285
+ tier: str | None = None,
286
+ custom_fields: dict[str, Any] | None = None,
287
+ ) -> Account:
288
+ """Update an account."""
289
+ request = AccountsUpdateRequest(
290
+ id=id,
291
+ display_name=display_name,
292
+ description=description,
293
+ tier=tier,
294
+ custom_fields=custom_fields,
295
+ )
296
+ response = await self._post("/accounts.update", request, AccountsUpdateResponse)
297
+ return response.account
298
+
299
+ async def delete(self, id: str) -> None:
300
+ """Delete an account."""
301
+ request = AccountsDeleteRequest(id=id)
302
+ await self._post("/accounts.delete", request, AccountsDeleteResponse)
303
+
304
+ async def merge(self, primary_account: str, secondary_account: str) -> Account:
305
+ """Merge two accounts."""
306
+ request = AccountsMergeRequest(
307
+ primary_account=primary_account,
308
+ secondary_account=secondary_account,
309
+ )
310
+ response = await self._post("/accounts.merge", request, AccountsMergeResponse)
311
+ return response.account
312
+
313
+ async def export(
314
+ self,
315
+ *,
316
+ created_by: Sequence[str] | None = None,
317
+ first: int | None = None,
318
+ ) -> Sequence[Account]:
319
+ """Export accounts."""
320
+ request = AccountsExportRequest(
321
+ created_by=created_by,
322
+ first=first,
323
+ )
324
+ response = await self._post("/accounts.export", request, AccountsExportResponse)
325
+ return response.accounts