chub-dev 0.1.0 → 0.1.2-beta.0

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 (139) hide show
  1. package/README.md +55 -0
  2. package/bin/chub-mcp +2 -0
  3. package/dist/airtable/docs/database/javascript/DOC.md +1437 -0
  4. package/dist/airtable/docs/database/python/DOC.md +1735 -0
  5. package/dist/amplitude/docs/analytics/javascript/DOC.md +1282 -0
  6. package/dist/amplitude/docs/analytics/python/DOC.md +1199 -0
  7. package/dist/anthropic/docs/claude-api/javascript/DOC.md +503 -0
  8. package/dist/anthropic/docs/claude-api/python/DOC.md +389 -0
  9. package/dist/asana/docs/tasks/DOC.md +1396 -0
  10. package/dist/assemblyai/docs/transcription/DOC.md +1043 -0
  11. package/dist/atlassian/docs/confluence/javascript/DOC.md +1347 -0
  12. package/dist/atlassian/docs/confluence/python/DOC.md +1604 -0
  13. package/dist/auth0/docs/identity/javascript/DOC.md +968 -0
  14. package/dist/auth0/docs/identity/python/DOC.md +1199 -0
  15. package/dist/aws/docs/s3/javascript/DOC.md +1773 -0
  16. package/dist/aws/docs/s3/python/DOC.md +1807 -0
  17. package/dist/binance/docs/trading/javascript/DOC.md +1315 -0
  18. package/dist/binance/docs/trading/python/DOC.md +1454 -0
  19. package/dist/braintree/docs/gateway/javascript/DOC.md +1278 -0
  20. package/dist/braintree/docs/gateway/python/DOC.md +1179 -0
  21. package/dist/chromadb/docs/embeddings-db/javascript/DOC.md +1263 -0
  22. package/dist/chromadb/docs/embeddings-db/python/DOC.md +1707 -0
  23. package/dist/clerk/docs/auth/javascript/DOC.md +1220 -0
  24. package/dist/clerk/docs/auth/python/DOC.md +274 -0
  25. package/dist/cloudflare/docs/workers/javascript/DOC.md +918 -0
  26. package/dist/cloudflare/docs/workers/python/DOC.md +994 -0
  27. package/dist/cockroachdb/docs/distributed-db/DOC.md +1500 -0
  28. package/dist/cohere/docs/llm/DOC.md +1335 -0
  29. package/dist/datadog/docs/monitoring/javascript/DOC.md +1740 -0
  30. package/dist/datadog/docs/monitoring/python/DOC.md +1815 -0
  31. package/dist/deepgram/docs/speech/javascript/DOC.md +885 -0
  32. package/dist/deepgram/docs/speech/python/DOC.md +685 -0
  33. package/dist/deepl/docs/translation/javascript/DOC.md +887 -0
  34. package/dist/deepl/docs/translation/python/DOC.md +944 -0
  35. package/dist/deepseek/docs/llm/DOC.md +1220 -0
  36. package/dist/directus/docs/headless-cms/javascript/DOC.md +1128 -0
  37. package/dist/directus/docs/headless-cms/python/DOC.md +1276 -0
  38. package/dist/discord/docs/bot/javascript/DOC.md +1090 -0
  39. package/dist/discord/docs/bot/python/DOC.md +1130 -0
  40. package/dist/elasticsearch/docs/search/DOC.md +1634 -0
  41. package/dist/elevenlabs/docs/text-to-speech/javascript/DOC.md +336 -0
  42. package/dist/elevenlabs/docs/text-to-speech/python/DOC.md +552 -0
  43. package/dist/firebase/docs/auth/DOC.md +1015 -0
  44. package/dist/gemini/docs/genai/javascript/DOC.md +691 -0
  45. package/dist/gemini/docs/genai/python/DOC.md +555 -0
  46. package/dist/github/docs/octokit/DOC.md +1560 -0
  47. package/dist/google/docs/bigquery/javascript/DOC.md +1688 -0
  48. package/dist/google/docs/bigquery/python/DOC.md +1503 -0
  49. package/dist/hubspot/docs/crm/javascript/DOC.md +1805 -0
  50. package/dist/hubspot/docs/crm/python/DOC.md +2033 -0
  51. package/dist/huggingface/docs/transformers/DOC.md +948 -0
  52. package/dist/intercom/docs/messaging/javascript/DOC.md +1844 -0
  53. package/dist/intercom/docs/messaging/python/DOC.md +1797 -0
  54. package/dist/jira/docs/issues/javascript/DOC.md +1420 -0
  55. package/dist/jira/docs/issues/python/DOC.md +1492 -0
  56. package/dist/kafka/docs/streaming/javascript/DOC.md +1671 -0
  57. package/dist/kafka/docs/streaming/python/DOC.md +1464 -0
  58. package/dist/landingai-ade/docs/api/DOC.md +620 -0
  59. package/dist/landingai-ade/docs/sdk/python/DOC.md +489 -0
  60. package/dist/landingai-ade/docs/sdk/typescript/DOC.md +542 -0
  61. package/dist/landingai-ade/skills/SKILL.md +489 -0
  62. package/dist/launchdarkly/docs/feature-flags/javascript/DOC.md +1191 -0
  63. package/dist/launchdarkly/docs/feature-flags/python/DOC.md +1671 -0
  64. package/dist/linear/docs/tracker/DOC.md +1554 -0
  65. package/dist/livekit/docs/realtime/javascript/DOC.md +303 -0
  66. package/dist/livekit/docs/realtime/python/DOC.md +163 -0
  67. package/dist/mailchimp/docs/marketing/DOC.md +1420 -0
  68. package/dist/meilisearch/docs/search/DOC.md +1241 -0
  69. package/dist/microsoft/docs/onedrive/javascript/DOC.md +1421 -0
  70. package/dist/microsoft/docs/onedrive/python/DOC.md +1549 -0
  71. package/dist/mongodb/docs/atlas/DOC.md +2041 -0
  72. package/dist/notion/docs/workspace-api/javascript/DOC.md +1435 -0
  73. package/dist/notion/docs/workspace-api/python/DOC.md +1400 -0
  74. package/dist/okta/docs/identity/javascript/DOC.md +1171 -0
  75. package/dist/okta/docs/identity/python/DOC.md +1401 -0
  76. package/dist/openai/docs/chat/javascript/DOC.md +407 -0
  77. package/dist/openai/docs/chat/python/DOC.md +568 -0
  78. package/dist/paypal/docs/checkout/DOC.md +278 -0
  79. package/dist/pinecone/docs/sdk/javascript/DOC.md +984 -0
  80. package/dist/pinecone/docs/sdk/python/DOC.md +1395 -0
  81. package/dist/plaid/docs/banking/javascript/DOC.md +1163 -0
  82. package/dist/plaid/docs/banking/python/DOC.md +1203 -0
  83. package/dist/playwright-community/skills/login-flows/SKILL.md +108 -0
  84. package/dist/postmark/docs/transactional-email/DOC.md +1168 -0
  85. package/dist/prisma/docs/orm/javascript/DOC.md +1419 -0
  86. package/dist/prisma/docs/orm/python/DOC.md +1317 -0
  87. package/dist/qdrant/docs/vector-search/javascript/DOC.md +1221 -0
  88. package/dist/qdrant/docs/vector-search/python/DOC.md +1653 -0
  89. package/dist/rabbitmq/docs/message-queue/javascript/DOC.md +1193 -0
  90. package/dist/rabbitmq/docs/message-queue/python/DOC.md +1243 -0
  91. package/dist/razorpay/docs/payments/javascript/DOC.md +1219 -0
  92. package/dist/razorpay/docs/payments/python/DOC.md +1330 -0
  93. package/dist/redis/docs/key-value/javascript/DOC.md +1851 -0
  94. package/dist/redis/docs/key-value/python/DOC.md +2054 -0
  95. package/dist/registry.json +2817 -0
  96. package/dist/replicate/docs/model-hosting/DOC.md +1318 -0
  97. package/dist/resend/docs/email/DOC.md +1271 -0
  98. package/dist/salesforce/docs/crm/javascript/DOC.md +1241 -0
  99. package/dist/salesforce/docs/crm/python/DOC.md +1183 -0
  100. package/dist/search-index.json +1 -0
  101. package/dist/sendgrid/docs/email-api/javascript/DOC.md +371 -0
  102. package/dist/sendgrid/docs/email-api/python/DOC.md +656 -0
  103. package/dist/sentry/docs/error-tracking/javascript/DOC.md +1073 -0
  104. package/dist/sentry/docs/error-tracking/python/DOC.md +1309 -0
  105. package/dist/shopify/docs/storefront/DOC.md +457 -0
  106. package/dist/slack/docs/workspace/javascript/DOC.md +933 -0
  107. package/dist/slack/docs/workspace/python/DOC.md +271 -0
  108. package/dist/square/docs/payments/javascript/DOC.md +1855 -0
  109. package/dist/square/docs/payments/python/DOC.md +1728 -0
  110. package/dist/stripe/docs/api/DOC.md +1727 -0
  111. package/dist/stripe/docs/payments/DOC.md +1726 -0
  112. package/dist/stytch/docs/auth/javascript/DOC.md +1813 -0
  113. package/dist/stytch/docs/auth/python/DOC.md +1962 -0
  114. package/dist/supabase/docs/client/DOC.md +1606 -0
  115. package/dist/twilio/docs/messaging/python/DOC.md +469 -0
  116. package/dist/twilio/docs/messaging/typescript/DOC.md +946 -0
  117. package/dist/vercel/docs/platform/DOC.md +1940 -0
  118. package/dist/weaviate/docs/vector-db/javascript/DOC.md +1268 -0
  119. package/dist/weaviate/docs/vector-db/python/DOC.md +1388 -0
  120. package/dist/zendesk/docs/support/javascript/DOC.md +2150 -0
  121. package/dist/zendesk/docs/support/python/DOC.md +2297 -0
  122. package/package.json +22 -6
  123. package/skills/get-api-docs/SKILL.md +84 -0
  124. package/src/commands/annotate.js +83 -0
  125. package/src/commands/build.js +12 -1
  126. package/src/commands/feedback.js +150 -0
  127. package/src/commands/get.js +83 -42
  128. package/src/commands/search.js +7 -0
  129. package/src/index.js +43 -17
  130. package/src/lib/analytics.js +90 -0
  131. package/src/lib/annotations.js +57 -0
  132. package/src/lib/bm25.js +170 -0
  133. package/src/lib/cache.js +69 -6
  134. package/src/lib/config.js +8 -3
  135. package/src/lib/identity.js +99 -0
  136. package/src/lib/registry.js +103 -20
  137. package/src/lib/telemetry.js +86 -0
  138. package/src/mcp/server.js +177 -0
  139. package/src/mcp/tools.js +251 -0
@@ -0,0 +1,1728 @@
1
+ ---
2
+ name: payments
3
+ description: "Square Python SDK coding guide for payments, POS, and commerce checkout"
4
+ metadata:
5
+ languages: "python"
6
+ versions: "43.2.0"
7
+ updated-on: "2026-03-02"
8
+ source: maintainer
9
+ tags: "square,payments,pos,commerce,checkout"
10
+ ---
11
+
12
+ # Square Python SDK Coding Guide
13
+
14
+ ## 1. Golden Rule
15
+
16
+ **Always use the official Square Python SDK package:**
17
+ - Package name: `squareup` (Python library for Square API)
18
+ - Official repository: https://github.com/square/square-python-sdk
19
+
20
+ **Never use deprecated libraries:**
21
+ - `squareconnect` (DEPRECATED - replaced by `squareup`)
22
+ - `squareup_legacy` (legacy version for migration purposes only)
23
+
24
+ **Current SDK Version:** v43.2.0
25
+
26
+ **API Versioning:** Square uses date-based API versioning (e.g., 2025-08-20). Your account is automatically pinned to an API version. You can override this when initializing the client.
27
+
28
+ ## 2. Installation
29
+
30
+ ```bash
31
+ pip install squareup
32
+ ```
33
+
34
+ ```bash
35
+ poetry add squareup
36
+ ```
37
+
38
+ ```bash
39
+ uv add squareup
40
+ ```
41
+
42
+ **Requirements:** Python 3.8+ (Python 3.10+ recommended for production)
43
+
44
+ ### Environment Variables
45
+
46
+ ```bash
47
+ # Required
48
+ SQUARE_TOKEN=EAAAl... # Your Square access token
49
+ SQUARE_ENVIRONMENT=sandbox # or "production"
50
+
51
+ # Optional
52
+ SQUARE_LOCATION_ID=L88917... # Default location ID for operations
53
+ ```
54
+
55
+ **CRITICAL:** Never commit access tokens to version control. Use environment variables or secure secret management systems. Use sandbox tokens for development and testing.
56
+
57
+ ## 3. Initialization
58
+
59
+ ### Basic Initialization
60
+
61
+ ```python
62
+ import os
63
+ from square import Square
64
+
65
+ client = Square(
66
+ token=os.environ.get("SQUARE_TOKEN"),
67
+ )
68
+ ```
69
+
70
+ ### With Environment Specification
71
+
72
+ ```python
73
+ import os
74
+ from square import Square
75
+ from square.environment import Environment
76
+
77
+ client = Square(
78
+ environment=Environment.SANDBOX,
79
+ token=os.environ.get("SQUARE_TOKEN"),
80
+ )
81
+ ```
82
+
83
+ ### Advanced Configuration
84
+
85
+ ```python
86
+ import os
87
+ from square import Square
88
+ from square.environment import Environment
89
+
90
+ client = Square(
91
+ environment=Environment.PRODUCTION,
92
+ token=os.environ.get("SQUARE_TOKEN"),
93
+ timeout=60, # 60 second timeout
94
+ max_retries=3, # Maximum retry attempts
95
+ square_version="2025-08-20", # Override API version
96
+ user_agent_detail="MyApp/1.0.0",
97
+ )
98
+ ```
99
+
100
+ ### Async Client Initialization
101
+
102
+ ```python
103
+ import os
104
+ from square import AsyncSquare
105
+ from square.environment import Environment
106
+
107
+ async_client = AsyncSquare(
108
+ environment=Environment.SANDBOX,
109
+ token=os.environ.get("SQUARE_TOKEN"),
110
+ )
111
+ ```
112
+
113
+ ### Error Handling Setup
114
+
115
+ ```python
116
+ from square import Square
117
+ from square.core.api_error import ApiError
118
+
119
+ client = Square(
120
+ token=os.environ.get("SQUARE_TOKEN"),
121
+ )
122
+
123
+ try:
124
+ # Make API calls here
125
+ pass
126
+ except ApiError as e:
127
+ for error in e.errors:
128
+ print(f"Category: {error.category}")
129
+ print(f"Code: {error.code}")
130
+ print(f"Detail: {error.detail}")
131
+ except Exception as e:
132
+ print(f"Unexpected error: {e}")
133
+ ```
134
+
135
+ ## 4. Core API Surfaces
136
+
137
+ ### Locations API
138
+
139
+ Get information about business locations.
140
+
141
+ **List All Locations:**
142
+
143
+ ```python
144
+ try:
145
+ response = client.locations.list()
146
+ locations = response.locations
147
+
148
+ for location in locations:
149
+ print(f"{location.id}: {location.name}")
150
+ print(f"Address: {location.address.address_line_1}")
151
+ print(f"City: {location.address.locality}")
152
+
153
+ except ApiError as e:
154
+ print("Error listing locations:", e.errors)
155
+ ```
156
+
157
+ **Retrieve Single Location:**
158
+
159
+ ```python
160
+ def get_location(location_id: str):
161
+ try:
162
+ response = client.locations.retrieve(location_id)
163
+ return response.location
164
+ except ApiError as e:
165
+ print("Error retrieving location:", e.errors)
166
+ raise
167
+ ```
168
+
169
+ **Async List Locations:**
170
+
171
+ ```python
172
+ import asyncio
173
+
174
+ async def list_locations_async():
175
+ try:
176
+ response = await async_client.locations.list()
177
+ return response.locations
178
+ except ApiError as e:
179
+ print("Error listing locations:", e.errors)
180
+ raise
181
+
182
+ # Usage
183
+ locations = asyncio.run(list_locations_async())
184
+ ```
185
+
186
+ ### Payments API
187
+
188
+ Process and manage payments.
189
+
190
+ **Create Payment (Minimal):**
191
+
192
+ ```python
193
+ import uuid
194
+
195
+ def create_payment(source_id: str, amount: int, location_id: str):
196
+ try:
197
+ response = client.payments.create(
198
+ source_id=source_id,
199
+ idempotency_key=str(uuid.uuid4()),
200
+ amount_money={
201
+ "amount": amount,
202
+ "currency": "USD",
203
+ },
204
+ location_id=location_id,
205
+ )
206
+ return response.payment
207
+ except ApiError as e:
208
+ print("Payment error:", e.errors)
209
+ raise
210
+ ```
211
+
212
+ **Create Payment (Advanced):**
213
+
214
+ ```python
215
+ import uuid
216
+
217
+ def create_advanced_payment(payment_data: dict):
218
+ try:
219
+ response = client.payments.create(
220
+ source_id=payment_data["source_id"],
221
+ idempotency_key=str(uuid.uuid4()),
222
+ amount_money={
223
+ "amount": payment_data["amount"],
224
+ "currency": payment_data.get("currency", "USD"),
225
+ },
226
+ location_id=payment_data["location_id"],
227
+ customer_id=payment_data.get("customer_id"),
228
+ reference_id=payment_data.get("reference_id"),
229
+ note=payment_data.get("note"),
230
+ autocomplete=True,
231
+ buyer_email_address=payment_data.get("email"),
232
+ billing_address={
233
+ "address_line_1": payment_data.get("address_line_1"),
234
+ "locality": payment_data.get("city"),
235
+ "administrative_district_level_1": payment_data.get("state"),
236
+ "postal_code": payment_data.get("postal_code"),
237
+ "country": payment_data.get("country", "US"),
238
+ },
239
+ )
240
+ return response.payment
241
+ except ApiError as e:
242
+ print("Payment creation failed:", e.errors)
243
+ raise
244
+ ```
245
+
246
+ **List Payments:**
247
+
248
+ ```python
249
+ def list_payments(location_id: str, begin_time: str, end_time: str):
250
+ try:
251
+ response = client.payments.list(
252
+ location_id=location_id,
253
+ begin_time=begin_time,
254
+ end_time=end_time,
255
+ sort_order="DESC",
256
+ limit=100,
257
+ )
258
+ return response.payments
259
+ except ApiError as e:
260
+ print("Error listing payments:", e.errors)
261
+ raise
262
+ ```
263
+
264
+ **Get Payment:**
265
+
266
+ ```python
267
+ def get_payment(payment_id: str):
268
+ try:
269
+ response = client.payments.retrieve(payment_id)
270
+ return response.payment
271
+ except ApiError as e:
272
+ print("Error retrieving payment:", e.errors)
273
+ raise
274
+ ```
275
+
276
+ **Complete Payment:**
277
+
278
+ ```python
279
+ def complete_payment(payment_id: str):
280
+ try:
281
+ response = client.payments.complete(payment_id)
282
+ return response.payment
283
+ except ApiError as e:
284
+ print("Error completing payment:", e.errors)
285
+ raise
286
+ ```
287
+
288
+ **Cancel Payment:**
289
+
290
+ ```python
291
+ def cancel_payment(payment_id: str):
292
+ try:
293
+ response = client.payments.cancel(payment_id)
294
+ return response.payment
295
+ except ApiError as e:
296
+ print("Error canceling payment:", e.errors)
297
+ raise
298
+ ```
299
+
300
+ **Async Create Payment:**
301
+
302
+ ```python
303
+ import asyncio
304
+ import uuid
305
+
306
+ async def create_payment_async(source_id: str, amount: int, location_id: str):
307
+ try:
308
+ response = await async_client.payments.create(
309
+ source_id=source_id,
310
+ idempotency_key=str(uuid.uuid4()),
311
+ amount_money={
312
+ "amount": amount,
313
+ "currency": "USD",
314
+ },
315
+ location_id=location_id,
316
+ )
317
+ return response.payment
318
+ except ApiError as e:
319
+ print("Payment error:", e.errors)
320
+ raise
321
+ ```
322
+
323
+ ### Refunds API
324
+
325
+ Manage payment refunds.
326
+
327
+ **Create Refund (Minimal):**
328
+
329
+ ```python
330
+ import uuid
331
+
332
+ def create_refund(payment_id: str, amount: int, currency: str = "USD"):
333
+ try:
334
+ response = client.refunds.create(
335
+ idempotency_key=str(uuid.uuid4()),
336
+ payment_id=payment_id,
337
+ amount_money={
338
+ "amount": amount,
339
+ "currency": currency,
340
+ },
341
+ )
342
+ return response.refund
343
+ except ApiError as e:
344
+ print("Refund error:", e.errors)
345
+ raise
346
+ ```
347
+
348
+ **Create Refund (Advanced):**
349
+
350
+ ```python
351
+ import uuid
352
+
353
+ def create_advanced_refund(refund_data: dict):
354
+ try:
355
+ response = client.refunds.create(
356
+ idempotency_key=str(uuid.uuid4()),
357
+ payment_id=refund_data["payment_id"],
358
+ amount_money={
359
+ "amount": refund_data["amount"],
360
+ "currency": refund_data.get("currency", "USD"),
361
+ },
362
+ reason=refund_data.get("reason"),
363
+ location_id=refund_data.get("location_id"),
364
+ )
365
+ return response.refund
366
+ except ApiError as e:
367
+ print("Refund creation failed:", e.errors)
368
+ raise
369
+ ```
370
+
371
+ **Get Refund:**
372
+
373
+ ```python
374
+ def get_refund(refund_id: str):
375
+ try:
376
+ response = client.refunds.retrieve(refund_id)
377
+ return response.refund
378
+ except ApiError as e:
379
+ print("Error retrieving refund:", e.errors)
380
+ raise
381
+ ```
382
+
383
+ **List Refunds:**
384
+
385
+ ```python
386
+ def list_refunds(location_id: str, begin_time: str, end_time: str):
387
+ try:
388
+ response = client.refunds.list(
389
+ location_id=location_id,
390
+ begin_time=begin_time,
391
+ end_time=end_time,
392
+ sort_order="DESC",
393
+ )
394
+ return response.refunds
395
+ except ApiError as e:
396
+ print("Error listing refunds:", e.errors)
397
+ raise
398
+ ```
399
+
400
+ ### Orders API
401
+
402
+ Create and manage orders.
403
+
404
+ **Create Order (Minimal):**
405
+
406
+ ```python
407
+ import uuid
408
+
409
+ def create_order(location_id: str):
410
+ try:
411
+ response = client.orders.create(
412
+ idempotency_key=str(uuid.uuid4()),
413
+ order={
414
+ "location_id": location_id,
415
+ "line_items": [
416
+ {
417
+ "name": "Item Name",
418
+ "quantity": "1",
419
+ "base_price_money": {
420
+ "amount": 1000,
421
+ "currency": "USD",
422
+ },
423
+ },
424
+ ],
425
+ },
426
+ )
427
+ return response.order
428
+ except ApiError as e:
429
+ print("Order creation error:", e.errors)
430
+ raise
431
+ ```
432
+
433
+ **Create Order (Advanced):**
434
+
435
+ ```python
436
+ import uuid
437
+
438
+ def create_advanced_order(order_data: dict):
439
+ try:
440
+ line_items = [
441
+ {
442
+ "name": item["name"],
443
+ "quantity": str(item["quantity"]),
444
+ "base_price_money": {
445
+ "amount": item["price"],
446
+ "currency": item.get("currency", "USD"),
447
+ },
448
+ "note": item.get("note"),
449
+ }
450
+ for item in order_data["line_items"]
451
+ ]
452
+
453
+ taxes = [
454
+ {
455
+ "name": "Sales Tax",
456
+ "percentage": "8.5",
457
+ "scope": "ORDER",
458
+ }
459
+ ]
460
+
461
+ discounts = [
462
+ {
463
+ "name": discount["name"],
464
+ "percentage": discount["percentage"],
465
+ "scope": "ORDER",
466
+ }
467
+ for discount in order_data.get("discounts", [])
468
+ ]
469
+
470
+ response = client.orders.create(
471
+ idempotency_key=str(uuid.uuid4()),
472
+ order={
473
+ "location_id": order_data["location_id"],
474
+ "reference_id": order_data.get("reference_id"),
475
+ "customer_id": order_data.get("customer_id"),
476
+ "line_items": line_items,
477
+ "taxes": taxes,
478
+ "discounts": discounts,
479
+ },
480
+ )
481
+ return response.order
482
+ except ApiError as e:
483
+ print("Order creation failed:", e.errors)
484
+ raise
485
+ ```
486
+
487
+ **Retrieve Order:**
488
+
489
+ ```python
490
+ def retrieve_order(order_id: str):
491
+ try:
492
+ response = client.orders.retrieve(order_id)
493
+ return response.order
494
+ except ApiError as e:
495
+ print("Error retrieving order:", e.errors)
496
+ raise
497
+ ```
498
+
499
+ **Update Order:**
500
+
501
+ ```python
502
+ def update_order(order_id: str, updates: dict):
503
+ try:
504
+ response = client.orders.update(
505
+ order_id=order_id,
506
+ order=updates,
507
+ )
508
+ return response.order
509
+ except ApiError as e:
510
+ print("Error updating order:", e.errors)
511
+ raise
512
+ ```
513
+
514
+ **Search Orders:**
515
+
516
+ ```python
517
+ def search_orders(location_ids: list, query: dict):
518
+ try:
519
+ search_query = {
520
+ "filter": {
521
+ "state_filter": {
522
+ "states": ["OPEN", "COMPLETED"],
523
+ },
524
+ },
525
+ "sort": {
526
+ "sort_field": "CREATED_AT",
527
+ "sort_order": "DESC",
528
+ },
529
+ }
530
+
531
+ if query.get("date_time_filter"):
532
+ search_query["filter"]["date_time_filter"] = query["date_time_filter"]
533
+
534
+ if query.get("customer_id"):
535
+ search_query["filter"]["customer_filter"] = {
536
+ "customer_ids": [query["customer_id"]],
537
+ }
538
+
539
+ response = client.orders.search(
540
+ location_ids=location_ids,
541
+ query=search_query,
542
+ limit=query.get("limit", 100),
543
+ )
544
+ return response.orders
545
+ except ApiError as e:
546
+ print("Error searching orders:", e.errors)
547
+ raise
548
+ ```
549
+
550
+ ### Customers API
551
+
552
+ Manage customer profiles.
553
+
554
+ **Create Customer (Minimal):**
555
+
556
+ ```python
557
+ import uuid
558
+
559
+ def create_customer(email: str, given_name: str, family_name: str):
560
+ try:
561
+ response = client.customers.create(
562
+ idempotency_key=str(uuid.uuid4()),
563
+ email_address=email,
564
+ given_name=given_name,
565
+ family_name=family_name,
566
+ )
567
+ return response.customer
568
+ except ApiError as e:
569
+ print("Customer creation error:", e.errors)
570
+ raise
571
+ ```
572
+
573
+ **Create Customer (Advanced):**
574
+
575
+ ```python
576
+ import uuid
577
+
578
+ def create_advanced_customer(customer_data: dict):
579
+ try:
580
+ response = client.customers.create(
581
+ idempotency_key=str(uuid.uuid4()),
582
+ given_name=customer_data["given_name"],
583
+ family_name=customer_data["family_name"],
584
+ email_address=customer_data.get("email_address"),
585
+ phone_number=customer_data.get("phone_number"),
586
+ address={
587
+ "address_line_1": customer_data.get("address_line_1"),
588
+ "address_line_2": customer_data.get("address_line_2"),
589
+ "locality": customer_data.get("city"),
590
+ "administrative_district_level_1": customer_data.get("state"),
591
+ "postal_code": customer_data.get("postal_code"),
592
+ "country": customer_data.get("country", "US"),
593
+ },
594
+ reference_id=customer_data.get("reference_id"),
595
+ note=customer_data.get("note"),
596
+ birthday=customer_data.get("birthday"),
597
+ company_name=customer_data.get("company_name"),
598
+ )
599
+ return response.customer
600
+ except ApiError as e:
601
+ print("Customer creation failed:", e.errors)
602
+ raise
603
+ ```
604
+
605
+ **List Customers with Pagination:**
606
+
607
+ ```python
608
+ def list_customers(cursor: str = None, limit: int = 100):
609
+ try:
610
+ response = client.customers.list(
611
+ cursor=cursor,
612
+ limit=limit,
613
+ sort_field="CREATED_AT",
614
+ sort_order="DESC",
615
+ )
616
+ return {
617
+ "customers": response.customers,
618
+ "cursor": response.cursor,
619
+ }
620
+ except ApiError as e:
621
+ print("Error listing customers:", e.errors)
622
+ raise
623
+ ```
624
+
625
+ **List All Customers with Auto-Pagination:**
626
+
627
+ ```python
628
+ def list_all_customers():
629
+ try:
630
+ all_customers = []
631
+ response = client.customers.list(limit=100)
632
+
633
+ # Auto-pagination: iterate over all pages
634
+ for customer in response:
635
+ all_customers.append(customer)
636
+
637
+ return all_customers
638
+ except ApiError as e:
639
+ print("Error listing customers:", e.errors)
640
+ raise
641
+ ```
642
+
643
+ **Retrieve Customer:**
644
+
645
+ ```python
646
+ def retrieve_customer(customer_id: str):
647
+ try:
648
+ response = client.customers.retrieve(customer_id)
649
+ return response.customer
650
+ except ApiError as e:
651
+ print("Error retrieving customer:", e.errors)
652
+ raise
653
+ ```
654
+
655
+ **Update Customer:**
656
+
657
+ ```python
658
+ def update_customer(customer_id: str, updates: dict):
659
+ try:
660
+ response = client.customers.update(
661
+ customer_id=customer_id,
662
+ **updates
663
+ )
664
+ return response.customer
665
+ except ApiError as e:
666
+ print("Error updating customer:", e.errors)
667
+ raise
668
+ ```
669
+
670
+ **Delete Customer:**
671
+
672
+ ```python
673
+ def delete_customer(customer_id: str):
674
+ try:
675
+ response = client.customers.delete(customer_id)
676
+ return response
677
+ except ApiError as e:
678
+ print("Error deleting customer:", e.errors)
679
+ raise
680
+ ```
681
+
682
+ **Search Customers:**
683
+
684
+ ```python
685
+ def search_customers(query: dict):
686
+ try:
687
+ search_query = {
688
+ "filter": {},
689
+ }
690
+
691
+ if query.get("email"):
692
+ search_query["filter"]["email_address"] = {
693
+ "exact": query["email"],
694
+ }
695
+
696
+ if query.get("phone"):
697
+ search_query["filter"]["phone_number"] = {
698
+ "exact": query["phone"],
699
+ }
700
+
701
+ if query.get("created_at"):
702
+ search_query["filter"]["created_at"] = query["created_at"]
703
+
704
+ response = client.customers.search(
705
+ query=search_query,
706
+ limit=query.get("limit", 100),
707
+ )
708
+ return response.customers
709
+ except ApiError as e:
710
+ print("Error searching customers:", e.errors)
711
+ raise
712
+ ```
713
+
714
+ ### Catalog API
715
+
716
+ Manage items, categories, taxes, and modifiers.
717
+
718
+ **Create Catalog Item (Minimal):**
719
+
720
+ ```python
721
+ import uuid
722
+
723
+ def create_catalog_item(name: str, price: int):
724
+ try:
725
+ item_id = f"#{name.replace(' ', '_')}"
726
+
727
+ response = client.catalog.upsert_catalog_object(
728
+ idempotency_key=str(uuid.uuid4()),
729
+ object={
730
+ "type": "ITEM",
731
+ "id": item_id,
732
+ "item_data": {
733
+ "name": name,
734
+ "variations": [
735
+ {
736
+ "type": "ITEM_VARIATION",
737
+ "id": f"{item_id}_variation",
738
+ "item_variation_data": {
739
+ "name": "Regular",
740
+ "pricing_type": "FIXED_PRICING",
741
+ "price_money": {
742
+ "amount": price,
743
+ "currency": "USD",
744
+ },
745
+ },
746
+ },
747
+ ],
748
+ },
749
+ },
750
+ )
751
+ return response.catalog_object
752
+ except ApiError as e:
753
+ print("Catalog item creation error:", e.errors)
754
+ raise
755
+ ```
756
+
757
+ **Create Catalog Item (Advanced):**
758
+
759
+ ```python
760
+ import uuid
761
+
762
+ def create_advanced_catalog_item(item_data: dict):
763
+ try:
764
+ item_id = f"#{item_data['name'].replace(' ', '_')}"
765
+
766
+ variations = [
767
+ {
768
+ "type": "ITEM_VARIATION",
769
+ "id": f"{item_id}_var_{i}",
770
+ "item_variation_data": {
771
+ "name": var["name"],
772
+ "sku": var.get("sku"),
773
+ "pricing_type": "FIXED_PRICING",
774
+ "price_money": {
775
+ "amount": var["price"],
776
+ "currency": var.get("currency", "USD"),
777
+ },
778
+ "track_inventory": var.get("track_inventory", False),
779
+ },
780
+ }
781
+ for i, var in enumerate(item_data["variations"])
782
+ ]
783
+
784
+ response = client.catalog.upsert_catalog_object(
785
+ idempotency_key=str(uuid.uuid4()),
786
+ object={
787
+ "type": "ITEM",
788
+ "id": item_id,
789
+ "item_data": {
790
+ "name": item_data["name"],
791
+ "description": item_data.get("description"),
792
+ "category_id": item_data.get("category_id"),
793
+ "tax_ids": item_data.get("tax_ids"),
794
+ "variations": variations,
795
+ },
796
+ },
797
+ )
798
+ return response.catalog_object
799
+ except ApiError as e:
800
+ print("Catalog item creation failed:", e.errors)
801
+ raise
802
+ ```
803
+
804
+ **List Catalog:**
805
+
806
+ ```python
807
+ def list_catalog(types: list = None, cursor: str = None):
808
+ try:
809
+ if types is None:
810
+ types = ["ITEM"]
811
+
812
+ response = client.catalog.list(
813
+ cursor=cursor,
814
+ types=",".join(types),
815
+ )
816
+ return {
817
+ "objects": response.objects,
818
+ "cursor": response.cursor,
819
+ }
820
+ except ApiError as e:
821
+ print("Error listing catalog:", e.errors)
822
+ raise
823
+ ```
824
+
825
+ **Retrieve Catalog Object:**
826
+
827
+ ```python
828
+ def retrieve_catalog_object(object_id: str):
829
+ try:
830
+ response = client.catalog.retrieve(
831
+ object_id=object_id,
832
+ include_related_objects=True,
833
+ )
834
+ return response.object
835
+ except ApiError as e:
836
+ print("Error retrieving catalog object:", e.errors)
837
+ raise
838
+ ```
839
+
840
+ **Search Catalog Items:**
841
+
842
+ ```python
843
+ def search_catalog_items(query: dict):
844
+ try:
845
+ response = client.catalog.search_catalog_items(
846
+ text_filter=query.get("text"),
847
+ category_ids=query.get("category_ids"),
848
+ stock_levels=query.get("stock_levels"),
849
+ enabled_location_ids=query.get("location_ids"),
850
+ limit=query.get("limit", 100),
851
+ )
852
+ return response.items
853
+ except ApiError as e:
854
+ print("Error searching catalog:", e.errors)
855
+ raise
856
+ ```
857
+
858
+ **Delete Catalog Object:**
859
+
860
+ ```python
861
+ def delete_catalog_object(object_id: str):
862
+ try:
863
+ response = client.catalog.delete_catalog_object(object_id)
864
+ return response
865
+ except ApiError as e:
866
+ print("Error deleting catalog object:", e.errors)
867
+ raise
868
+ ```
869
+
870
+ **Batch Upsert Catalog Objects:**
871
+
872
+ ```python
873
+ import uuid
874
+
875
+ def batch_upsert_catalog_objects(objects: list):
876
+ try:
877
+ response = client.catalog.batch_upsert_catalog_objects(
878
+ idempotency_key=str(uuid.uuid4()),
879
+ batches=[
880
+ {
881
+ "objects": objects,
882
+ },
883
+ ],
884
+ )
885
+ return response.objects
886
+ except ApiError as e:
887
+ print("Batch upsert error:", e.errors)
888
+ raise
889
+ ```
890
+
891
+ ### Inventory API
892
+
893
+ Track and manage inventory.
894
+
895
+ **Retrieve Inventory Count:**
896
+
897
+ ```python
898
+ def retrieve_inventory_count(catalog_object_id: str, location_ids: list):
899
+ try:
900
+ response = client.inventory.retrieve_inventory_count(
901
+ catalog_object_id=catalog_object_id,
902
+ location_ids=",".join(location_ids),
903
+ )
904
+ return response.counts
905
+ except ApiError as e:
906
+ print("Error retrieving inventory:", e.errors)
907
+ raise
908
+ ```
909
+
910
+ **Batch Retrieve Inventory Counts:**
911
+
912
+ ```python
913
+ def batch_retrieve_inventory_counts(catalog_object_ids: list, location_ids: list):
914
+ try:
915
+ response = client.inventory.batch_retrieve_inventory_counts(
916
+ catalog_object_ids=catalog_object_ids,
917
+ location_ids=location_ids,
918
+ )
919
+ return response.counts
920
+ except ApiError as e:
921
+ print("Error retrieving inventory counts:", e.errors)
922
+ raise
923
+ ```
924
+
925
+ **Adjust Inventory:**
926
+
927
+ ```python
928
+ import uuid
929
+ from datetime import datetime
930
+
931
+ def adjust_inventory(catalog_object_id: str, location_id: str, adjustment: dict):
932
+ try:
933
+ response = client.inventory.batch_change_inventory(
934
+ idempotency_key=str(uuid.uuid4()),
935
+ changes=[
936
+ {
937
+ "type": "ADJUSTMENT",
938
+ "adjustment": {
939
+ "catalog_object_id": catalog_object_id,
940
+ "location_id": location_id,
941
+ "quantity": str(adjustment["quantity"]),
942
+ "from_state": "IN_STOCK",
943
+ "to_state": "IN_STOCK",
944
+ "occurred_at": datetime.utcnow().isoformat(),
945
+ },
946
+ },
947
+ ],
948
+ )
949
+ return response.counts
950
+ except ApiError as e:
951
+ print("Error adjusting inventory:", e.errors)
952
+ raise
953
+ ```
954
+
955
+ ### Invoices API
956
+
957
+ Create and manage invoices.
958
+
959
+ **Create Invoice (Minimal):**
960
+
961
+ ```python
962
+ import uuid
963
+ from datetime import datetime, timedelta
964
+
965
+ def create_invoice(location_id: str, customer_id: str, order_id: str):
966
+ try:
967
+ due_date = (datetime.now() + timedelta(days=7)).strftime("%Y-%m-%d")
968
+
969
+ response = client.invoices.create(
970
+ invoice={
971
+ "location_id": location_id,
972
+ "order_id": order_id,
973
+ "primary_recipient": {
974
+ "customer_id": customer_id,
975
+ },
976
+ "payment_requests": [
977
+ {
978
+ "request_type": "BALANCE",
979
+ "due_date": due_date,
980
+ },
981
+ ],
982
+ },
983
+ idempotency_key=str(uuid.uuid4()),
984
+ )
985
+ return response.invoice
986
+ except ApiError as e:
987
+ print("Invoice creation error:", e.errors)
988
+ raise
989
+ ```
990
+
991
+ **Create Invoice (Advanced):**
992
+
993
+ ```python
994
+ import uuid
995
+
996
+ def create_advanced_invoice(invoice_data: dict):
997
+ try:
998
+ payment_requests = [
999
+ {
1000
+ "request_type": "BALANCE",
1001
+ "due_date": invoice_data["due_date"],
1002
+ "reminders": [
1003
+ {
1004
+ "relative_scheduled_days": -1,
1005
+ "message": "Payment reminder",
1006
+ },
1007
+ ],
1008
+ }
1009
+ ]
1010
+
1011
+ if invoice_data.get("fixed_amount"):
1012
+ payment_requests[0]["fixed_amount_requested_money"] = {
1013
+ "amount": invoice_data["fixed_amount"],
1014
+ "currency": invoice_data.get("currency", "USD"),
1015
+ }
1016
+
1017
+ response = client.invoices.create(
1018
+ invoice={
1019
+ "location_id": invoice_data["location_id"],
1020
+ "order_id": invoice_data["order_id"],
1021
+ "primary_recipient": {
1022
+ "customer_id": invoice_data["customer_id"],
1023
+ "given_name": invoice_data.get("given_name"),
1024
+ "family_name": invoice_data.get("family_name"),
1025
+ "email_address": invoice_data.get("email_address"),
1026
+ },
1027
+ "payment_requests": payment_requests,
1028
+ "delivery_method": "EMAIL",
1029
+ "invoice_number": invoice_data.get("invoice_number"),
1030
+ "title": invoice_data.get("title"),
1031
+ "description": invoice_data.get("description"),
1032
+ },
1033
+ idempotency_key=str(uuid.uuid4()),
1034
+ )
1035
+ return response.invoice
1036
+ except ApiError as e:
1037
+ print("Invoice creation failed:", e.errors)
1038
+ raise
1039
+ ```
1040
+
1041
+ **Publish Invoice:**
1042
+
1043
+ ```python
1044
+ def publish_invoice(invoice_id: str):
1045
+ try:
1046
+ response = client.invoices.publish(
1047
+ invoice_id=invoice_id,
1048
+ version=0,
1049
+ )
1050
+ return response.invoice
1051
+ except ApiError as e:
1052
+ print("Error publishing invoice:", e.errors)
1053
+ raise
1054
+ ```
1055
+
1056
+ **Get Invoice:**
1057
+
1058
+ ```python
1059
+ def get_invoice(invoice_id: str):
1060
+ try:
1061
+ response = client.invoices.retrieve(invoice_id)
1062
+ return response.invoice
1063
+ except ApiError as e:
1064
+ print("Error retrieving invoice:", e.errors)
1065
+ raise
1066
+ ```
1067
+
1068
+ **Search Invoices:**
1069
+
1070
+ ```python
1071
+ def search_invoices(location_ids: list, query: dict):
1072
+ try:
1073
+ search_query = {
1074
+ "location_ids": location_ids,
1075
+ "filter": {},
1076
+ "sort": {
1077
+ "field": "INVOICE_SORT_DATE",
1078
+ "order": "DESC",
1079
+ },
1080
+ }
1081
+
1082
+ if query.get("customer_ids"):
1083
+ search_query["filter"]["customer_ids"] = query["customer_ids"]
1084
+
1085
+ if query.get("states"):
1086
+ search_query["filter"]["state_filter"] = query["states"]
1087
+
1088
+ response = client.invoices.search(
1089
+ query=search_query,
1090
+ limit=query.get("limit", 100),
1091
+ )
1092
+ return response.invoices
1093
+ except ApiError as e:
1094
+ print("Error searching invoices:", e.errors)
1095
+ raise
1096
+ ```
1097
+
1098
+ ### Subscriptions API
1099
+
1100
+ Manage recurring payments and subscriptions.
1101
+
1102
+ **Create Subscription (Minimal):**
1103
+
1104
+ ```python
1105
+ import uuid
1106
+
1107
+ def create_subscription(location_id: str, customer_id: str, plan_id: str):
1108
+ try:
1109
+ response = client.subscriptions.create(
1110
+ idempotency_key=str(uuid.uuid4()),
1111
+ location_id=location_id,
1112
+ plan_id=plan_id,
1113
+ customer_id=customer_id,
1114
+ )
1115
+ return response.subscription
1116
+ except ApiError as e:
1117
+ print("Subscription creation error:", e.errors)
1118
+ raise
1119
+ ```
1120
+
1121
+ **Create Subscription (Advanced):**
1122
+
1123
+ ```python
1124
+ import uuid
1125
+
1126
+ def create_advanced_subscription(subscription_data: dict):
1127
+ try:
1128
+ price_override = None
1129
+ if subscription_data.get("price_override"):
1130
+ price_override = {
1131
+ "amount": subscription_data["price_override"],
1132
+ "currency": subscription_data.get("currency", "USD"),
1133
+ }
1134
+
1135
+ response = client.subscriptions.create(
1136
+ idempotency_key=str(uuid.uuid4()),
1137
+ location_id=subscription_data["location_id"],
1138
+ plan_id=subscription_data["plan_id"],
1139
+ customer_id=subscription_data["customer_id"],
1140
+ start_date=subscription_data.get("start_date"),
1141
+ tax_percentage=subscription_data.get("tax_percentage"),
1142
+ price_override_money=price_override,
1143
+ card_id=subscription_data.get("card_id"),
1144
+ )
1145
+ return response.subscription
1146
+ except ApiError as e:
1147
+ print("Subscription creation failed:", e.errors)
1148
+ raise
1149
+ ```
1150
+
1151
+ **Retrieve Subscription:**
1152
+
1153
+ ```python
1154
+ def retrieve_subscription(subscription_id: str):
1155
+ try:
1156
+ response = client.subscriptions.retrieve(
1157
+ subscription_id=subscription_id,
1158
+ include="actions",
1159
+ )
1160
+ return response.subscription
1161
+ except ApiError as e:
1162
+ print("Error retrieving subscription:", e.errors)
1163
+ raise
1164
+ ```
1165
+
1166
+ **Cancel Subscription:**
1167
+
1168
+ ```python
1169
+ def cancel_subscription(subscription_id: str):
1170
+ try:
1171
+ response = client.subscriptions.cancel(subscription_id)
1172
+ return response.subscription
1173
+ except ApiError as e:
1174
+ print("Error canceling subscription:", e.errors)
1175
+ raise
1176
+ ```
1177
+
1178
+ **Search Subscriptions:**
1179
+
1180
+ ```python
1181
+ def search_subscriptions(query: dict):
1182
+ try:
1183
+ search_query = {
1184
+ "filter": {},
1185
+ }
1186
+
1187
+ if query.get("customer_ids"):
1188
+ search_query["filter"]["customer_ids"] = query["customer_ids"]
1189
+
1190
+ if query.get("location_ids"):
1191
+ search_query["filter"]["location_ids"] = query["location_ids"]
1192
+
1193
+ response = client.subscriptions.search(
1194
+ query=search_query,
1195
+ limit=query.get("limit", 100),
1196
+ )
1197
+ return response.subscriptions
1198
+ except ApiError as e:
1199
+ print("Error searching subscriptions:", e.errors)
1200
+ raise
1201
+ ```
1202
+
1203
+ ### Checkout API
1204
+
1205
+ Create hosted checkout pages.
1206
+
1207
+ **Create Checkout (Minimal):**
1208
+
1209
+ ```python
1210
+ import uuid
1211
+
1212
+ def create_checkout(location_id: str, order_id: str):
1213
+ try:
1214
+ response = client.checkout.create(
1215
+ location_id=location_id,
1216
+ idempotency_key=str(uuid.uuid4()),
1217
+ order={
1218
+ "order_id": order_id,
1219
+ },
1220
+ )
1221
+ return response.checkout.checkout_page_url
1222
+ except ApiError as e:
1223
+ print("Checkout creation error:", e.errors)
1224
+ raise
1225
+ ```
1226
+
1227
+ **Create Checkout (Advanced):**
1228
+
1229
+ ```python
1230
+ import uuid
1231
+
1232
+ def create_advanced_checkout(location_id: str, checkout_data: dict):
1233
+ try:
1234
+ response = client.checkout.create(
1235
+ location_id=location_id,
1236
+ idempotency_key=str(uuid.uuid4()),
1237
+ order={
1238
+ "order_id": checkout_data["order_id"],
1239
+ "location_id": location_id,
1240
+ },
1241
+ ask_for_shipping_address=checkout_data.get("ask_for_shipping_address", False),
1242
+ merchant_support_email=checkout_data.get("merchant_email"),
1243
+ pre_populate_buyer_email=checkout_data.get("buyer_email"),
1244
+ redirect_url=checkout_data.get("redirect_url"),
1245
+ additional_recipients=checkout_data.get("additional_recipients"),
1246
+ )
1247
+ return response.checkout
1248
+ except ApiError as e:
1249
+ print("Checkout creation failed:", e.errors)
1250
+ raise
1251
+ ```
1252
+
1253
+ ### Bookings API
1254
+
1255
+ Manage appointments and bookings.
1256
+
1257
+ **Create Booking (Minimal):**
1258
+
1259
+ ```python
1260
+ import uuid
1261
+
1262
+ def create_booking(location_id: str, customer_id: str, start_at: str,
1263
+ service_variation_id: str, team_member_id: str):
1264
+ try:
1265
+ response = client.bookings.create(
1266
+ idempotency_key=str(uuid.uuid4()),
1267
+ booking={
1268
+ "location_id": location_id,
1269
+ "customer_id": customer_id,
1270
+ "start_at": start_at,
1271
+ "appointment_segments": [
1272
+ {
1273
+ "duration_minutes": 60,
1274
+ "service_variation_id": service_variation_id,
1275
+ "team_member_id": team_member_id,
1276
+ },
1277
+ ],
1278
+ },
1279
+ )
1280
+ return response.booking
1281
+ except ApiError as e:
1282
+ print("Booking creation error:", e.errors)
1283
+ raise
1284
+ ```
1285
+
1286
+ **Create Booking (Advanced):**
1287
+
1288
+ ```python
1289
+ import uuid
1290
+
1291
+ def create_advanced_booking(booking_data: dict):
1292
+ try:
1293
+ appointment_segments = [
1294
+ {
1295
+ "duration_minutes": segment["duration_minutes"],
1296
+ "service_variation_id": segment["service_variation_id"],
1297
+ "team_member_id": segment["team_member_id"],
1298
+ }
1299
+ for segment in booking_data["appointment_segments"]
1300
+ ]
1301
+
1302
+ response = client.bookings.create(
1303
+ idempotency_key=str(uuid.uuid4()),
1304
+ booking={
1305
+ "location_id": booking_data["location_id"],
1306
+ "customer_id": booking_data["customer_id"],
1307
+ "customer_note": booking_data.get("customer_note"),
1308
+ "seller_note": booking_data.get("seller_note"),
1309
+ "start_at": booking_data["start_at"],
1310
+ "appointment_segments": appointment_segments,
1311
+ },
1312
+ )
1313
+ return response.booking
1314
+ except ApiError as e:
1315
+ print("Booking creation failed:", e.errors)
1316
+ raise
1317
+ ```
1318
+
1319
+ **List Bookings:**
1320
+
1321
+ ```python
1322
+ def list_bookings(location_id: str, start_at_min: str, start_at_max: str):
1323
+ try:
1324
+ response = client.bookings.list(
1325
+ location_id=location_id,
1326
+ start_at_min=start_at_min,
1327
+ start_at_max=start_at_max,
1328
+ limit=100,
1329
+ )
1330
+ return response.bookings
1331
+ except ApiError as e:
1332
+ print("Error listing bookings:", e.errors)
1333
+ raise
1334
+ ```
1335
+
1336
+ **Retrieve Booking:**
1337
+
1338
+ ```python
1339
+ def retrieve_booking(booking_id: str):
1340
+ try:
1341
+ response = client.bookings.retrieve(booking_id)
1342
+ return response.booking
1343
+ except ApiError as e:
1344
+ print("Error retrieving booking:", e.errors)
1345
+ raise
1346
+ ```
1347
+
1348
+ **Cancel Booking:**
1349
+
1350
+ ```python
1351
+ import uuid
1352
+
1353
+ def cancel_booking(booking_id: str):
1354
+ try:
1355
+ response = client.bookings.cancel(
1356
+ booking_id=booking_id,
1357
+ idempotency_key=str(uuid.uuid4()),
1358
+ )
1359
+ return response.booking
1360
+ except ApiError as e:
1361
+ print("Error canceling booking:", e.errors)
1362
+ raise
1363
+ ```
1364
+
1365
+ ### Terminal API
1366
+
1367
+ Create checkouts for Square Terminal devices.
1368
+
1369
+ **Create Terminal Checkout:**
1370
+
1371
+ ```python
1372
+ import uuid
1373
+
1374
+ def create_terminal_checkout(device_id: str, amount: int, location_id: str):
1375
+ try:
1376
+ response = client.terminal.create_terminal_checkout(
1377
+ idempotency_key=str(uuid.uuid4()),
1378
+ checkout={
1379
+ "amount_money": {
1380
+ "amount": amount,
1381
+ "currency": "USD",
1382
+ },
1383
+ "device_options": {
1384
+ "device_id": device_id,
1385
+ },
1386
+ },
1387
+ )
1388
+ return response.checkout
1389
+ except ApiError as e:
1390
+ print("Terminal checkout error:", e.errors)
1391
+ raise
1392
+ ```
1393
+
1394
+ **Get Terminal Checkout:**
1395
+
1396
+ ```python
1397
+ def get_terminal_checkout(checkout_id: str):
1398
+ try:
1399
+ response = client.terminal.get_terminal_checkout(checkout_id)
1400
+ return response.checkout
1401
+ except ApiError as e:
1402
+ print("Error retrieving terminal checkout:", e.errors)
1403
+ raise
1404
+ ```
1405
+
1406
+ **Cancel Terminal Checkout:**
1407
+
1408
+ ```python
1409
+ def cancel_terminal_checkout(checkout_id: str):
1410
+ try:
1411
+ response = client.terminal.cancel_terminal_checkout(checkout_id)
1412
+ return response.checkout
1413
+ except ApiError as e:
1414
+ print("Error canceling terminal checkout:", e.errors)
1415
+ raise
1416
+ ```
1417
+
1418
+ ### Webhooks
1419
+
1420
+ Handle webhook notifications from Square.
1421
+
1422
+ **Create Webhook Subscription:**
1423
+
1424
+ ```python
1425
+ def create_webhook_subscription(notification_url: str, event_types: list):
1426
+ try:
1427
+ response = client.webhook_subscriptions.create(
1428
+ subscription={
1429
+ "name": "My Webhook",
1430
+ "notification_url": notification_url,
1431
+ "event_types": event_types,
1432
+ },
1433
+ )
1434
+ return response.subscription
1435
+ except ApiError as e:
1436
+ print("Webhook creation error:", e.errors)
1437
+ raise
1438
+ ```
1439
+
1440
+ **List Webhook Subscriptions:**
1441
+
1442
+ ```python
1443
+ def list_webhook_subscriptions():
1444
+ try:
1445
+ response = client.webhook_subscriptions.list()
1446
+ return response.subscriptions
1447
+ except ApiError as e:
1448
+ print("Error listing webhooks:", e.errors)
1449
+ raise
1450
+ ```
1451
+
1452
+ **Verify Webhook Signature:**
1453
+
1454
+ ```python
1455
+ import hmac
1456
+ import hashlib
1457
+
1458
+ def verify_webhook_signature(body: str, signature: str, signature_key: str, notification_url: str) -> bool:
1459
+ message = notification_url + body
1460
+ hmac_obj = hmac.new(
1461
+ signature_key.encode('utf-8'),
1462
+ message.encode('utf-8'),
1463
+ hashlib.sha256
1464
+ )
1465
+ expected_signature = hmac_obj.digest().hex()
1466
+
1467
+ return hmac.compare_digest(expected_signature, signature)
1468
+ ```
1469
+
1470
+ **Handle Webhook (Flask):**
1471
+
1472
+ ```python
1473
+ from flask import Flask, request
1474
+
1475
+ app = Flask(__name__)
1476
+
1477
+ @app.route('/webhooks/square', methods=['POST'])
1478
+ def handle_square_webhook():
1479
+ signature = request.headers.get('x-square-hmacsha256-signature')
1480
+ body = request.get_data(as_text=True)
1481
+
1482
+ is_valid = verify_webhook_signature(
1483
+ body,
1484
+ signature,
1485
+ os.environ.get('SQUARE_WEBHOOK_SECRET'),
1486
+ 'https://yourdomain.com/webhooks/square'
1487
+ )
1488
+
1489
+ if not is_valid:
1490
+ return 'Invalid signature', 400
1491
+
1492
+ event = request.json
1493
+
1494
+ if event['type'] == 'payment.created':
1495
+ print('Payment created:', event['data']['object']['payment'])
1496
+ elif event['type'] == 'order.created':
1497
+ print('Order created:', event['data']['object']['order'])
1498
+ elif event['type'] == 'customer.created':
1499
+ print('Customer created:', event['data']['object']['customer'])
1500
+ else:
1501
+ print('Unhandled event type:', event['type'])
1502
+
1503
+ return 'OK', 200
1504
+ ```
1505
+
1506
+ ### Common Webhook Events
1507
+
1508
+ ```python
1509
+ # Payment events
1510
+ PAYMENT_CREATED = "payment.created"
1511
+ PAYMENT_UPDATED = "payment.updated"
1512
+
1513
+ # Order events
1514
+ ORDER_CREATED = "order.created"
1515
+ ORDER_UPDATED = "order.updated"
1516
+ ORDER_FULFILLMENT_UPDATED = "order.fulfillment.updated"
1517
+
1518
+ # Customer events
1519
+ CUSTOMER_CREATED = "customer.created"
1520
+ CUSTOMER_UPDATED = "customer.updated"
1521
+ CUSTOMER_DELETED = "customer.deleted"
1522
+
1523
+ # Invoice events
1524
+ INVOICE_CREATED = "invoice.created"
1525
+ INVOICE_PUBLISHED = "invoice.published"
1526
+ INVOICE_PAYMENT_MADE = "invoice.payment_made"
1527
+
1528
+ # Subscription events
1529
+ SUBSCRIPTION_CREATED = "subscription.created"
1530
+ SUBSCRIPTION_STARTED = "subscription.started"
1531
+ SUBSCRIPTION_CANCELED = "subscription.canceled"
1532
+
1533
+ # Booking events
1534
+ BOOKING_CREATED = "booking.created"
1535
+ BOOKING_UPDATED = "booking.updated"
1536
+
1537
+ # Inventory events
1538
+ INVENTORY_COUNT_UPDATED = "inventory.count.updated"
1539
+
1540
+ # Catalog events
1541
+ CATALOG_VERSION_UPDATED = "catalog.version.updated"
1542
+ ```
1543
+
1544
+ ### Pagination
1545
+
1546
+ Handle paginated results with auto-pagination.
1547
+
1548
+ ```python
1549
+ def get_all_customers():
1550
+ try:
1551
+ all_customers = []
1552
+ response = client.customers.list(limit=100)
1553
+
1554
+ # Auto-pagination using iterator
1555
+ for customer in response:
1556
+ all_customers.append(customer)
1557
+
1558
+ return all_customers
1559
+ except ApiError as e:
1560
+ print("Error fetching customers:", e.errors)
1561
+ raise
1562
+ ```
1563
+
1564
+ ### Manual Pagination
1565
+
1566
+ ```python
1567
+ def get_all_customers_manual():
1568
+ all_customers = []
1569
+ cursor = None
1570
+
1571
+ while True:
1572
+ try:
1573
+ response = client.customers.list(
1574
+ cursor=cursor,
1575
+ limit=100,
1576
+ )
1577
+
1578
+ if response.customers:
1579
+ all_customers.extend(response.customers)
1580
+
1581
+ cursor = response.cursor
1582
+ if not cursor:
1583
+ break
1584
+
1585
+ except ApiError as e:
1586
+ print("Error fetching customers:", e.errors)
1587
+ raise
1588
+
1589
+ return all_customers
1590
+ ```
1591
+
1592
+ ### Idempotency
1593
+
1594
+ Use idempotency keys to prevent duplicate operations.
1595
+
1596
+ ```python
1597
+ import uuid
1598
+
1599
+ def idempotent_payment(source_id: str, amount: int, location_id: str):
1600
+ idempotency_key = str(uuid.uuid4())
1601
+
1602
+ try:
1603
+ response = client.payments.create(
1604
+ source_id=source_id,
1605
+ idempotency_key=idempotency_key,
1606
+ amount_money={
1607
+ "amount": amount,
1608
+ "currency": "USD",
1609
+ },
1610
+ location_id=location_id,
1611
+ )
1612
+ return response.payment
1613
+ except ApiError as e:
1614
+ print("Payment failed:", e.errors)
1615
+ raise
1616
+ ```
1617
+
1618
+ ### Testing with Sandbox
1619
+
1620
+ ```python
1621
+ import os
1622
+ from square import Square
1623
+ from square.environment import Environment
1624
+
1625
+ # Always use sandbox for development
1626
+ client = Square(
1627
+ environment=Environment.SANDBOX,
1628
+ token=os.environ.get("SQUARE_SANDBOX_TOKEN"),
1629
+ )
1630
+
1631
+ # Test payment source IDs for sandbox:
1632
+ # cnon:card-nonce-ok - successful charge
1633
+ # cnon:card-nonce-declined - declined charge
1634
+ # cnon:card-nonce-dishonoured - card verification failed
1635
+ ```
1636
+
1637
+ ### Complete Example: Process Payment with Customer
1638
+
1639
+ ```python
1640
+ import os
1641
+ import uuid
1642
+ from square import Square
1643
+ from square.core.api_error import ApiError
1644
+ from square.environment import Environment
1645
+
1646
+ client = Square(
1647
+ environment=Environment.SANDBOX,
1648
+ token=os.environ.get("SQUARE_TOKEN"),
1649
+ )
1650
+
1651
+ def process_payment_with_customer(payment_details: dict):
1652
+ try:
1653
+ # 1. Create or retrieve customer
1654
+ customer = None
1655
+ try:
1656
+ customer_response = client.customers.create(
1657
+ idempotency_key=str(uuid.uuid4()),
1658
+ given_name=payment_details["given_name"],
1659
+ family_name=payment_details["family_name"],
1660
+ email_address=payment_details["email_address"],
1661
+ )
1662
+ customer = customer_response.customer
1663
+ except ApiError:
1664
+ print("Customer already exists, using existing")
1665
+
1666
+ # 2. Create order
1667
+ order_response = client.orders.create(
1668
+ idempotency_key=str(uuid.uuid4()),
1669
+ order={
1670
+ "location_id": payment_details["location_id"],
1671
+ "customer_id": customer.id if customer else None,
1672
+ "line_items": [
1673
+ {
1674
+ "name": payment_details["item_name"],
1675
+ "quantity": "1",
1676
+ "base_price_money": {
1677
+ "amount": payment_details["amount"],
1678
+ "currency": "USD",
1679
+ },
1680
+ },
1681
+ ],
1682
+ },
1683
+ )
1684
+
1685
+ # 3. Create payment
1686
+ payment_response = client.payments.create(
1687
+ source_id=payment_details["source_id"],
1688
+ idempotency_key=str(uuid.uuid4()),
1689
+ amount_money={
1690
+ "amount": payment_details["amount"],
1691
+ "currency": "USD",
1692
+ },
1693
+ order_id=order_response.order.id,
1694
+ customer_id=customer.id if customer else None,
1695
+ location_id=payment_details["location_id"],
1696
+ autocomplete=True,
1697
+ )
1698
+
1699
+ return {
1700
+ "payment": payment_response.payment,
1701
+ "order": order_response.order,
1702
+ "customer": customer,
1703
+ }
1704
+
1705
+ except ApiError as e:
1706
+ print("Transaction failed:")
1707
+ for error in e.errors:
1708
+ print(f" {error.category}: {error.code}")
1709
+ print(f" {error.detail}")
1710
+ raise
1711
+
1712
+ # Usage
1713
+ result = process_payment_with_customer({
1714
+ "source_id": "cnon:card-nonce-ok",
1715
+ "amount": 1000,
1716
+ "location_id": "L88917AVBK2S5",
1717
+ "given_name": "John",
1718
+ "family_name": "Doe",
1719
+ "email_address": "john.doe@example.com",
1720
+ "item_name": "Premium Service",
1721
+ })
1722
+
1723
+ print("Payment successful!")
1724
+ print(f"Payment ID: {result['payment'].id}")
1725
+ print(f"Order ID: {result['order'].id}")
1726
+ if result['customer']:
1727
+ print(f"Customer ID: {result['customer'].id}")
1728
+ ```