ingestr 0.13.75__py3-none-any.whl → 0.14.98__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.

Potentially problematic release.


This version of ingestr might be problematic. Click here for more details.

Files changed (79) hide show
  1. ingestr/main.py +22 -3
  2. ingestr/src/adjust/__init__.py +4 -4
  3. ingestr/src/allium/__init__.py +128 -0
  4. ingestr/src/anthropic/__init__.py +277 -0
  5. ingestr/src/anthropic/helpers.py +525 -0
  6. ingestr/src/appstore/__init__.py +1 -0
  7. ingestr/src/asana_source/__init__.py +1 -1
  8. ingestr/src/buildinfo.py +1 -1
  9. ingestr/src/chess/__init__.py +1 -1
  10. ingestr/src/couchbase_source/__init__.py +118 -0
  11. ingestr/src/couchbase_source/helpers.py +135 -0
  12. ingestr/src/cursor/__init__.py +83 -0
  13. ingestr/src/cursor/helpers.py +188 -0
  14. ingestr/src/destinations.py +169 -1
  15. ingestr/src/docebo/__init__.py +589 -0
  16. ingestr/src/docebo/client.py +435 -0
  17. ingestr/src/docebo/helpers.py +97 -0
  18. ingestr/src/elasticsearch/helpers.py +138 -0
  19. ingestr/src/errors.py +8 -0
  20. ingestr/src/facebook_ads/__init__.py +26 -23
  21. ingestr/src/facebook_ads/helpers.py +47 -1
  22. ingestr/src/factory.py +48 -0
  23. ingestr/src/filesystem/__init__.py +8 -3
  24. ingestr/src/filters.py +9 -0
  25. ingestr/src/fluxx/__init__.py +9906 -0
  26. ingestr/src/fluxx/helpers.py +209 -0
  27. ingestr/src/frankfurter/__init__.py +157 -163
  28. ingestr/src/frankfurter/helpers.py +3 -3
  29. ingestr/src/freshdesk/__init__.py +25 -8
  30. ingestr/src/freshdesk/freshdesk_client.py +40 -5
  31. ingestr/src/fundraiseup/__init__.py +49 -0
  32. ingestr/src/fundraiseup/client.py +81 -0
  33. ingestr/src/github/__init__.py +6 -4
  34. ingestr/src/google_analytics/__init__.py +1 -1
  35. ingestr/src/hostaway/__init__.py +302 -0
  36. ingestr/src/hostaway/client.py +288 -0
  37. ingestr/src/http/__init__.py +35 -0
  38. ingestr/src/http/readers.py +114 -0
  39. ingestr/src/hubspot/__init__.py +6 -12
  40. ingestr/src/influxdb/__init__.py +1 -0
  41. ingestr/src/intercom/__init__.py +142 -0
  42. ingestr/src/intercom/helpers.py +674 -0
  43. ingestr/src/intercom/settings.py +279 -0
  44. ingestr/src/jira_source/__init__.py +340 -0
  45. ingestr/src/jira_source/helpers.py +439 -0
  46. ingestr/src/jira_source/settings.py +170 -0
  47. ingestr/src/klaviyo/__init__.py +5 -5
  48. ingestr/src/linear/__init__.py +553 -116
  49. ingestr/src/linear/helpers.py +77 -38
  50. ingestr/src/mailchimp/__init__.py +126 -0
  51. ingestr/src/mailchimp/helpers.py +226 -0
  52. ingestr/src/mailchimp/settings.py +164 -0
  53. ingestr/src/masking.py +344 -0
  54. ingestr/src/monday/__init__.py +246 -0
  55. ingestr/src/monday/helpers.py +392 -0
  56. ingestr/src/monday/settings.py +328 -0
  57. ingestr/src/mongodb/__init__.py +5 -2
  58. ingestr/src/mongodb/helpers.py +384 -10
  59. ingestr/src/plusvibeai/__init__.py +335 -0
  60. ingestr/src/plusvibeai/helpers.py +544 -0
  61. ingestr/src/plusvibeai/settings.py +252 -0
  62. ingestr/src/revenuecat/__init__.py +83 -0
  63. ingestr/src/revenuecat/helpers.py +237 -0
  64. ingestr/src/salesforce/__init__.py +15 -8
  65. ingestr/src/shopify/__init__.py +1 -1
  66. ingestr/src/smartsheets/__init__.py +33 -5
  67. ingestr/src/socrata_source/__init__.py +83 -0
  68. ingestr/src/socrata_source/helpers.py +85 -0
  69. ingestr/src/socrata_source/settings.py +8 -0
  70. ingestr/src/sources.py +1418 -54
  71. ingestr/src/stripe_analytics/__init__.py +2 -19
  72. ingestr/src/wise/__init__.py +68 -0
  73. ingestr/src/wise/client.py +63 -0
  74. ingestr/tests/unit/test_smartsheets.py +6 -9
  75. {ingestr-0.13.75.dist-info → ingestr-0.14.98.dist-info}/METADATA +24 -12
  76. {ingestr-0.13.75.dist-info → ingestr-0.14.98.dist-info}/RECORD +79 -37
  77. {ingestr-0.13.75.dist-info → ingestr-0.14.98.dist-info}/WHEEL +0 -0
  78. {ingestr-0.13.75.dist-info → ingestr-0.14.98.dist-info}/entry_points.txt +0 -0
  79. {ingestr-0.13.75.dist-info → ingestr-0.14.98.dist-info}/licenses/LICENSE.md +0 -0
@@ -4,9 +4,14 @@ import logging
4
4
  import time
5
5
  from typing import Any, Dict, Iterable, Optional
6
6
 
7
+ import pendulum
7
8
  from dlt.common.typing import TDataItem
8
9
  from dlt.sources.helpers import requests
9
10
 
11
+ from ingestr.src.errors import HTTPError
12
+
13
+ TICKETS_QUERY_MAX_PAGE = 10
14
+
10
15
 
11
16
  class FreshdeskClient:
12
17
  """
@@ -61,13 +66,15 @@ class FreshdeskClient:
61
66
  else:
62
67
  # If the error is not a rate limit (429), raise the exception to be
63
68
  # handled elsewhere or stop execution
64
- raise
69
+ raise HTTPError(e) from e
65
70
 
66
71
  def paginated_response(
67
72
  self,
68
73
  endpoint: str,
69
74
  per_page: int,
70
- updated_at: Optional[str] = None,
75
+ start_date: pendulum.DateTime,
76
+ end_date: pendulum.DateTime,
77
+ query: Optional[str] = None,
71
78
  ) -> Iterable[TDataItem]:
72
79
  """
73
80
  Fetches a paginated response from a specified endpoint.
@@ -77,6 +84,11 @@ class FreshdeskClient:
77
84
  updated at the specified timestamp.
78
85
  """
79
86
  page = 1
87
+ if query is not None:
88
+ query = query.replace('"', "").strip()
89
+
90
+ is_tickets_query = query and endpoint == "tickets"
91
+
80
92
  while True:
81
93
  # Construct the URL for the specific endpoint
82
94
  url = f"{self.base_url}/{endpoint}"
@@ -88,15 +100,38 @@ class FreshdeskClient:
88
100
  param_key = (
89
101
  "updated_since" if endpoint == "tickets" else "_updated_since"
90
102
  )
91
- if updated_at:
92
- params[param_key] = updated_at
103
+
104
+ params[param_key] = start_date.to_iso8601_string()
105
+
106
+ if is_tickets_query:
107
+ url = f"{self.base_url}/search/tickets"
108
+ params = {
109
+ "query": f'"{query}"',
110
+ "page": page,
111
+ }
93
112
 
94
113
  # Handle requests with rate-limiting
95
114
  # A maximum of 300 pages (30000 tickets) will be returned.
96
115
  response = self._request_with_rate_limit(url, params=params)
97
116
  data = response.json()
98
117
 
118
+ if query and endpoint == "tickets":
119
+ data = data["results"]
120
+
99
121
  if not data:
100
122
  break # Stop if no data or max page limit reached
101
- yield data
123
+
124
+ filtered_data = [
125
+ item
126
+ for item in data
127
+ if "updated_at" in item
128
+ and pendulum.parse(item["updated_at"]) <= end_date
129
+ ]
130
+ if not filtered_data:
131
+ break
132
+ yield filtered_data
102
133
  page += 1
134
+
135
+ # https://developers.freshdesk.com/api/#filter_tickets
136
+ if is_tickets_query and page > TICKETS_QUERY_MAX_PAGE:
137
+ break
@@ -0,0 +1,49 @@
1
+ """Fundraiseup source for ingesting donations, events, fundraisers, recurring plans, and supporters."""
2
+
3
+ from typing import Any, Dict, Generator, Iterable
4
+
5
+ import dlt
6
+ from dlt.sources import DltResource
7
+
8
+ from .client import FundraiseupClient
9
+
10
+
11
+ @dlt.source(name="fundraiseup", max_table_nesting=0)
12
+ def fundraiseup_source(api_key: str) -> Iterable[DltResource]:
13
+ """
14
+ Return resources for Fundraiseup API.
15
+
16
+ Args:
17
+ api_key: API key for authentication
18
+
19
+ Returns:
20
+ Iterable of DLT resources
21
+ """
22
+ client = FundraiseupClient(api_key=api_key)
23
+
24
+ # Define available resources and their configurations
25
+ resources = {
26
+ "donations": {"write_disposition": "replace", "primary_key": "id"},
27
+ "events": {"write_disposition": "replace", "primary_key": "id"},
28
+ "fundraisers": {"write_disposition": "replace", "primary_key": "id"},
29
+ "recurring_plans": {"write_disposition": "replace", "primary_key": "id"},
30
+ "supporters": {"write_disposition": "replace", "primary_key": "id"},
31
+ }
32
+
33
+ def create_resource(resource_name: str, config: Dict[str, Any]) -> DltResource:
34
+ """Create a DLT resource dynamically."""
35
+
36
+ @dlt.resource(
37
+ name=resource_name,
38
+ write_disposition=config["write_disposition"],
39
+ primary_key=config["primary_key"],
40
+ )
41
+ def generic_resource() -> Generator[Dict[str, Any], None, None]:
42
+ """Generic resource that yields batches directly."""
43
+ for batch in client.get_paginated_data(resource_name):
44
+ yield batch # type: ignore[misc]
45
+
46
+ return generic_resource()
47
+
48
+ # Return all resources
49
+ return [create_resource(name, config) for name, config in resources.items()]
@@ -0,0 +1,81 @@
1
+ """Fundraiseup API Client for handling authentication and paginated requests."""
2
+
3
+ from typing import Any, Dict, Iterator, Optional
4
+
5
+ from ingestr.src.http_client import create_client
6
+
7
+
8
+ class FundraiseupClient:
9
+ """Client for interacting with Fundraiseup API v1."""
10
+
11
+ def __init__(self, api_key: str):
12
+ """
13
+ Initialize Fundraiseup API client.
14
+
15
+ Args:
16
+ api_key: API key for authentication
17
+ """
18
+ self.api_key = api_key
19
+ self.base_url = "https://api.fundraiseup.com/v1"
20
+ # Use shared HTTP client with retry logic for rate limiting
21
+ self.client = create_client(retry_status_codes=[429, 500, 502, 503, 504])
22
+
23
+ def get_paginated_data(
24
+ self,
25
+ endpoint: str,
26
+ params: Optional[Dict[str, Any]] = None,
27
+ page_size: int = 100,
28
+ ) -> Iterator[list[Dict[str, Any]]]:
29
+ """
30
+ Fetch paginated data from a Fundraiseup API endpoint using cursor-based pagination.
31
+
32
+ Args:
33
+ endpoint: API endpoint path (e.g., "donations")
34
+ params: Additional query parameters
35
+ page_size: Number of items per page (default 100)
36
+
37
+ Yields:
38
+ Batches of items from the API
39
+ """
40
+ url = f"{self.base_url}/{endpoint}"
41
+ headers = {
42
+ "Authorization": f"Bearer {self.api_key}",
43
+ "Content-Type": "application/json",
44
+ }
45
+
46
+ if params is None:
47
+ params = {}
48
+
49
+ params["limit"] = page_size
50
+ starting_after = None
51
+
52
+ while True:
53
+ # Add cursor for pagination if not first page
54
+ if starting_after:
55
+ params["starting_after"] = starting_after
56
+
57
+ response = self.client.get(url=url, headers=headers, params=params)
58
+ response.raise_for_status()
59
+
60
+ data = response.json()
61
+
62
+ # Handle both list response and object with data array
63
+ if isinstance(data, list):
64
+ items = data
65
+ has_more = len(items) == page_size
66
+ else:
67
+ items = data.get("data", [])
68
+ has_more = data.get("has_more", False)
69
+
70
+ if not items:
71
+ break
72
+
73
+ yield items
74
+
75
+ # Set cursor for next page
76
+ if has_more and items:
77
+ starting_after = items[-1].get("id")
78
+ if not starting_after:
79
+ break
80
+ else:
81
+ break
@@ -72,7 +72,7 @@ def github_repo_events(
72
72
  name: str,
73
73
  access_token: str,
74
74
  start_date: pendulum.DateTime,
75
- end_date: pendulum.DateTime,
75
+ end_date: Optional[pendulum.DateTime] = None,
76
76
  ) -> DltResource:
77
77
  """Gets events for repository `name` with owner `owner` incrementally.
78
78
 
@@ -91,12 +91,14 @@ def github_repo_events(
91
91
  """
92
92
 
93
93
  # use naming function in table name to generate separate tables for each event
94
- @dlt.resource(primary_key="id", table_name=lambda i: i["type"])
94
+ @dlt.resource(
95
+ primary_key="id", table_name=lambda i: i["type"], write_disposition="merge"
96
+ )
95
97
  def repo_events(
96
98
  last_created_at: dlt.sources.incremental[str] = dlt.sources.incremental(
97
99
  "created_at",
98
100
  initial_value=start_date.isoformat(),
99
- end_value=end_date.isoformat(),
101
+ end_value=end_date.isoformat() if end_date else None,
100
102
  last_value_func=max,
101
103
  range_end="closed",
102
104
  range_start="closed",
@@ -113,7 +115,7 @@ def github_repo_events(
113
115
  end_filter = (
114
116
  pendulum.parse(last_created_at.end_value)
115
117
  if last_created_at.end_value
116
- else None
118
+ else pendulum.now()
117
119
  )
118
120
 
119
121
  for page in get_rest_pages(access_token, repos_path + "?per_page=100"):
@@ -7,7 +7,7 @@ from typing import Iterator, List, Optional, Union
7
7
  import dlt
8
8
  from dlt.common import pendulum
9
9
  from dlt.common.typing import DictStrAny, TDataItem
10
- from dlt.extract import DltResource
10
+ from dlt.sources import DltResource
11
11
  from dlt.sources.credentials import GcpOAuthCredentials, GcpServiceAccountCredentials
12
12
  from google.analytics.data_v1beta import BetaAnalyticsDataClient
13
13
  from google.analytics.data_v1beta.types import (
@@ -0,0 +1,302 @@
1
+ from typing import Iterable
2
+
3
+ import dlt
4
+ import pendulum
5
+ from dlt.common.typing import TDataItem
6
+ from dlt.sources import DltResource
7
+
8
+ from .client import HostawayClient
9
+
10
+
11
+ @dlt.source(max_table_nesting=0)
12
+ def hostaway_source(
13
+ api_key: str,
14
+ start_date: pendulum.DateTime,
15
+ end_date: pendulum.DateTime | None = None,
16
+ ) -> Iterable[DltResource]:
17
+ """
18
+ Hostaway API source for fetching listings and fee settings data.
19
+
20
+ Args:
21
+ api_key: Hostaway API key for Bearer token authentication
22
+ start_date: Start date for incremental loading
23
+ end_date: End date for incremental loading (defaults to current time)
24
+
25
+ Returns:
26
+ Iterable[DltResource]: DLT resources for listings and/or fee settings
27
+ """
28
+
29
+ client = HostawayClient(api_key)
30
+
31
+ @dlt.resource(
32
+ write_disposition="merge",
33
+ name="listings",
34
+ primary_key="id",
35
+ )
36
+ def listings(
37
+ datetime=dlt.sources.incremental(
38
+ "latestActivityOn",
39
+ initial_value=start_date,
40
+ end_value=end_date,
41
+ range_end="closed",
42
+ range_start="closed",
43
+ ),
44
+ ) -> Iterable[TDataItem]:
45
+ """
46
+ Fetch listings from Hostaway API with incremental loading.
47
+ Uses latestActivityOn field as the incremental cursor.
48
+ """
49
+ start_dt = datetime.last_value
50
+ end_dt = (
51
+ datetime.end_value
52
+ if datetime.end_value is not None
53
+ else pendulum.now(tz="UTC")
54
+ )
55
+
56
+ yield from client.fetch_listings(start_dt, end_dt)
57
+
58
+ @dlt.resource(
59
+ write_disposition="merge",
60
+ name="listing_fee_settings",
61
+ primary_key="id",
62
+ )
63
+ def listing_fee_settings(
64
+ datetime=dlt.sources.incremental(
65
+ "updatedOn",
66
+ initial_value=start_date,
67
+ end_value=end_date,
68
+ range_end="closed",
69
+ range_start="closed",
70
+ ),
71
+ ) -> Iterable[TDataItem]:
72
+ """
73
+ Fetch listing fee settings from Hostaway API with incremental loading.
74
+ Uses updatedOn field as the incremental cursor.
75
+ """
76
+ start_dt = datetime.last_value
77
+ end_dt = (
78
+ datetime.end_value
79
+ if datetime.end_value is not None
80
+ else pendulum.now(tz="UTC")
81
+ )
82
+
83
+ yield from client.fetch_all_listing_fee_settings(start_dt, end_dt)
84
+
85
+ @dlt.resource(
86
+ write_disposition="replace",
87
+ name="listing_agreements",
88
+ )
89
+ def listing_agreements() -> Iterable[TDataItem]:
90
+ """
91
+ Fetch listing agreements from Hostaway API.
92
+
93
+ Note: Uses replace mode, so no incremental loading.
94
+ """
95
+ very_old_date = pendulum.datetime(1970, 1, 1, tz="UTC")
96
+ now = pendulum.now(tz="UTC")
97
+ yield from client.fetch_all_listing_agreements(very_old_date, now)
98
+
99
+ @dlt.resource(
100
+ write_disposition="replace",
101
+ name="listing_pricing_settings",
102
+ )
103
+ def listing_pricing_settings() -> Iterable[TDataItem]:
104
+ """
105
+ Fetch listing pricing settings from Hostaway API.
106
+
107
+ Note: Uses replace mode, so no incremental loading.
108
+ """
109
+ very_old_date = pendulum.datetime(1970, 1, 1, tz="UTC")
110
+ now = pendulum.now(tz="UTC")
111
+ yield from client.fetch_all_listing_pricing_settings(very_old_date, now)
112
+
113
+ @dlt.resource(
114
+ write_disposition="replace",
115
+ name="cancellation_policies",
116
+ )
117
+ def cancellation_policies() -> Iterable[TDataItem]:
118
+ yield from client.fetch_cancellation_policies()
119
+
120
+ @dlt.resource(
121
+ write_disposition="replace",
122
+ name="cancellation_policies_airbnb",
123
+ )
124
+ def cancellation_policies_airbnb() -> Iterable[TDataItem]:
125
+ yield from client.fetch_cancellation_policies_airbnb()
126
+
127
+ @dlt.resource(
128
+ write_disposition="replace",
129
+ name="cancellation_policies_marriott",
130
+ )
131
+ def cancellation_policies_marriott() -> Iterable[TDataItem]:
132
+ yield from client.fetch_cancellation_policies_marriott()
133
+
134
+ @dlt.resource(
135
+ write_disposition="replace",
136
+ name="cancellation_policies_vrbo",
137
+ )
138
+ def cancellation_policies_vrbo() -> Iterable[TDataItem]:
139
+ yield from client.fetch_cancellation_policies_vrbo()
140
+
141
+ @dlt.resource(
142
+ write_disposition="replace",
143
+ name="reservations",
144
+ selected=False,
145
+ )
146
+ def reservations() -> Iterable[TDataItem]:
147
+ yield from client.fetch_reservations()
148
+
149
+ @dlt.transformer(
150
+ data_from=reservations,
151
+ write_disposition="replace",
152
+ name="finance_fields",
153
+ )
154
+ def finance_fields(reservation_item: TDataItem) -> Iterable[TDataItem]:
155
+ @dlt.defer
156
+ def _get_finance_field(res_id):
157
+ return list(client.fetch_finance_field(res_id))
158
+
159
+ reservation_id_val = reservation_item.get("id")
160
+ if reservation_id_val:
161
+ yield _get_finance_field(reservation_id_val)
162
+
163
+ @dlt.resource(
164
+ write_disposition="replace",
165
+ name="reservation_payment_methods",
166
+ )
167
+ def reservation_payment_methods() -> Iterable[TDataItem]:
168
+ yield from client.fetch_reservation_payment_methods()
169
+
170
+ @dlt.transformer(
171
+ data_from=reservations,
172
+ write_disposition="replace",
173
+ name="reservation_rental_agreements",
174
+ )
175
+ def reservation_rental_agreements(
176
+ reservation_item: TDataItem,
177
+ ) -> Iterable[TDataItem]:
178
+ @dlt.defer
179
+ def _get_rental_agreement(res_id):
180
+ return list(client.fetch_reservation_rental_agreement(res_id))
181
+
182
+ reservation_id = reservation_item.get("id")
183
+ if reservation_id:
184
+ yield _get_rental_agreement(reservation_id)
185
+
186
+ @dlt.transformer(
187
+ data_from=listings,
188
+ write_disposition="replace",
189
+ name="listing_calendars",
190
+ )
191
+ def listing_calendars(listing_item: TDataItem) -> Iterable[TDataItem]:
192
+ @dlt.defer
193
+ def _get_calendar(lst_id):
194
+ return list(client.fetch_listing_calendar(lst_id))
195
+
196
+ listing_id_val = listing_item.get("id")
197
+ if listing_id_val:
198
+ yield _get_calendar(listing_id_val)
199
+
200
+ @dlt.resource(
201
+ write_disposition="replace",
202
+ name="conversations",
203
+ )
204
+ def conversations() -> Iterable[TDataItem]:
205
+ yield from client.fetch_conversations()
206
+
207
+ @dlt.resource(
208
+ write_disposition="replace",
209
+ name="message_templates",
210
+ )
211
+ def message_templates() -> Iterable[TDataItem]:
212
+ yield from client.fetch_message_templates()
213
+
214
+ @dlt.resource(
215
+ write_disposition="replace",
216
+ name="bed_types",
217
+ )
218
+ def bed_types() -> Iterable[TDataItem]:
219
+ yield from client.fetch_bed_types()
220
+
221
+ @dlt.resource(
222
+ write_disposition="replace",
223
+ name="property_types",
224
+ )
225
+ def property_types() -> Iterable[TDataItem]:
226
+ yield from client.fetch_property_types()
227
+
228
+ @dlt.resource(
229
+ write_disposition="replace",
230
+ name="countries",
231
+ )
232
+ def countries() -> Iterable[TDataItem]:
233
+ yield from client.fetch_countries()
234
+
235
+ @dlt.resource(
236
+ write_disposition="replace",
237
+ name="account_tax_settings",
238
+ )
239
+ def account_tax_settings() -> Iterable[TDataItem]:
240
+ yield from client.fetch_account_tax_settings()
241
+
242
+ @dlt.resource(
243
+ write_disposition="replace",
244
+ name="user_groups",
245
+ )
246
+ def user_groups() -> Iterable[TDataItem]:
247
+ yield from client.fetch_user_groups()
248
+
249
+ @dlt.resource(
250
+ write_disposition="replace",
251
+ name="guest_payment_charges",
252
+ )
253
+ def guest_payment_charges() -> Iterable[TDataItem]:
254
+ yield from client.fetch_guest_payment_charges()
255
+
256
+ @dlt.resource(
257
+ write_disposition="replace",
258
+ name="coupons",
259
+ )
260
+ def coupons() -> Iterable[TDataItem]:
261
+ yield from client.fetch_coupons()
262
+
263
+ @dlt.resource(
264
+ write_disposition="replace",
265
+ name="webhook_reservations",
266
+ )
267
+ def webhook_reservations() -> Iterable[TDataItem]:
268
+ yield from client.fetch_webhook_reservations()
269
+
270
+ @dlt.resource(
271
+ write_disposition="replace",
272
+ name="tasks",
273
+ )
274
+ def tasks() -> Iterable[TDataItem]:
275
+ yield from client.fetch_tasks()
276
+
277
+ return (
278
+ listings,
279
+ listing_fee_settings,
280
+ listing_agreements,
281
+ listing_pricing_settings,
282
+ cancellation_policies,
283
+ cancellation_policies_airbnb,
284
+ cancellation_policies_marriott,
285
+ cancellation_policies_vrbo,
286
+ reservations,
287
+ finance_fields,
288
+ reservation_payment_methods,
289
+ reservation_rental_agreements,
290
+ listing_calendars,
291
+ conversations,
292
+ message_templates,
293
+ bed_types,
294
+ property_types,
295
+ countries,
296
+ account_tax_settings,
297
+ user_groups,
298
+ guest_payment_charges,
299
+ coupons,
300
+ webhook_reservations,
301
+ tasks,
302
+ )