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.
- package/README.md +55 -0
- package/bin/chub-mcp +2 -0
- package/dist/airtable/docs/database/javascript/DOC.md +1437 -0
- package/dist/airtable/docs/database/python/DOC.md +1735 -0
- package/dist/amplitude/docs/analytics/javascript/DOC.md +1282 -0
- package/dist/amplitude/docs/analytics/python/DOC.md +1199 -0
- package/dist/anthropic/docs/claude-api/javascript/DOC.md +503 -0
- package/dist/anthropic/docs/claude-api/python/DOC.md +389 -0
- package/dist/asana/docs/tasks/DOC.md +1396 -0
- package/dist/assemblyai/docs/transcription/DOC.md +1043 -0
- package/dist/atlassian/docs/confluence/javascript/DOC.md +1347 -0
- package/dist/atlassian/docs/confluence/python/DOC.md +1604 -0
- package/dist/auth0/docs/identity/javascript/DOC.md +968 -0
- package/dist/auth0/docs/identity/python/DOC.md +1199 -0
- package/dist/aws/docs/s3/javascript/DOC.md +1773 -0
- package/dist/aws/docs/s3/python/DOC.md +1807 -0
- package/dist/binance/docs/trading/javascript/DOC.md +1315 -0
- package/dist/binance/docs/trading/python/DOC.md +1454 -0
- package/dist/braintree/docs/gateway/javascript/DOC.md +1278 -0
- package/dist/braintree/docs/gateway/python/DOC.md +1179 -0
- package/dist/chromadb/docs/embeddings-db/javascript/DOC.md +1263 -0
- package/dist/chromadb/docs/embeddings-db/python/DOC.md +1707 -0
- package/dist/clerk/docs/auth/javascript/DOC.md +1220 -0
- package/dist/clerk/docs/auth/python/DOC.md +274 -0
- package/dist/cloudflare/docs/workers/javascript/DOC.md +918 -0
- package/dist/cloudflare/docs/workers/python/DOC.md +994 -0
- package/dist/cockroachdb/docs/distributed-db/DOC.md +1500 -0
- package/dist/cohere/docs/llm/DOC.md +1335 -0
- package/dist/datadog/docs/monitoring/javascript/DOC.md +1740 -0
- package/dist/datadog/docs/monitoring/python/DOC.md +1815 -0
- package/dist/deepgram/docs/speech/javascript/DOC.md +885 -0
- package/dist/deepgram/docs/speech/python/DOC.md +685 -0
- package/dist/deepl/docs/translation/javascript/DOC.md +887 -0
- package/dist/deepl/docs/translation/python/DOC.md +944 -0
- package/dist/deepseek/docs/llm/DOC.md +1220 -0
- package/dist/directus/docs/headless-cms/javascript/DOC.md +1128 -0
- package/dist/directus/docs/headless-cms/python/DOC.md +1276 -0
- package/dist/discord/docs/bot/javascript/DOC.md +1090 -0
- package/dist/discord/docs/bot/python/DOC.md +1130 -0
- package/dist/elasticsearch/docs/search/DOC.md +1634 -0
- package/dist/elevenlabs/docs/text-to-speech/javascript/DOC.md +336 -0
- package/dist/elevenlabs/docs/text-to-speech/python/DOC.md +552 -0
- package/dist/firebase/docs/auth/DOC.md +1015 -0
- package/dist/gemini/docs/genai/javascript/DOC.md +691 -0
- package/dist/gemini/docs/genai/python/DOC.md +555 -0
- package/dist/github/docs/octokit/DOC.md +1560 -0
- package/dist/google/docs/bigquery/javascript/DOC.md +1688 -0
- package/dist/google/docs/bigquery/python/DOC.md +1503 -0
- package/dist/hubspot/docs/crm/javascript/DOC.md +1805 -0
- package/dist/hubspot/docs/crm/python/DOC.md +2033 -0
- package/dist/huggingface/docs/transformers/DOC.md +948 -0
- package/dist/intercom/docs/messaging/javascript/DOC.md +1844 -0
- package/dist/intercom/docs/messaging/python/DOC.md +1797 -0
- package/dist/jira/docs/issues/javascript/DOC.md +1420 -0
- package/dist/jira/docs/issues/python/DOC.md +1492 -0
- package/dist/kafka/docs/streaming/javascript/DOC.md +1671 -0
- package/dist/kafka/docs/streaming/python/DOC.md +1464 -0
- package/dist/landingai-ade/docs/api/DOC.md +620 -0
- package/dist/landingai-ade/docs/sdk/python/DOC.md +489 -0
- package/dist/landingai-ade/docs/sdk/typescript/DOC.md +542 -0
- package/dist/landingai-ade/skills/SKILL.md +489 -0
- package/dist/launchdarkly/docs/feature-flags/javascript/DOC.md +1191 -0
- package/dist/launchdarkly/docs/feature-flags/python/DOC.md +1671 -0
- package/dist/linear/docs/tracker/DOC.md +1554 -0
- package/dist/livekit/docs/realtime/javascript/DOC.md +303 -0
- package/dist/livekit/docs/realtime/python/DOC.md +163 -0
- package/dist/mailchimp/docs/marketing/DOC.md +1420 -0
- package/dist/meilisearch/docs/search/DOC.md +1241 -0
- package/dist/microsoft/docs/onedrive/javascript/DOC.md +1421 -0
- package/dist/microsoft/docs/onedrive/python/DOC.md +1549 -0
- package/dist/mongodb/docs/atlas/DOC.md +2041 -0
- package/dist/notion/docs/workspace-api/javascript/DOC.md +1435 -0
- package/dist/notion/docs/workspace-api/python/DOC.md +1400 -0
- package/dist/okta/docs/identity/javascript/DOC.md +1171 -0
- package/dist/okta/docs/identity/python/DOC.md +1401 -0
- package/dist/openai/docs/chat/javascript/DOC.md +407 -0
- package/dist/openai/docs/chat/python/DOC.md +568 -0
- package/dist/paypal/docs/checkout/DOC.md +278 -0
- package/dist/pinecone/docs/sdk/javascript/DOC.md +984 -0
- package/dist/pinecone/docs/sdk/python/DOC.md +1395 -0
- package/dist/plaid/docs/banking/javascript/DOC.md +1163 -0
- package/dist/plaid/docs/banking/python/DOC.md +1203 -0
- package/dist/playwright-community/skills/login-flows/SKILL.md +108 -0
- package/dist/postmark/docs/transactional-email/DOC.md +1168 -0
- package/dist/prisma/docs/orm/javascript/DOC.md +1419 -0
- package/dist/prisma/docs/orm/python/DOC.md +1317 -0
- package/dist/qdrant/docs/vector-search/javascript/DOC.md +1221 -0
- package/dist/qdrant/docs/vector-search/python/DOC.md +1653 -0
- package/dist/rabbitmq/docs/message-queue/javascript/DOC.md +1193 -0
- package/dist/rabbitmq/docs/message-queue/python/DOC.md +1243 -0
- package/dist/razorpay/docs/payments/javascript/DOC.md +1219 -0
- package/dist/razorpay/docs/payments/python/DOC.md +1330 -0
- package/dist/redis/docs/key-value/javascript/DOC.md +1851 -0
- package/dist/redis/docs/key-value/python/DOC.md +2054 -0
- package/dist/registry.json +2817 -0
- package/dist/replicate/docs/model-hosting/DOC.md +1318 -0
- package/dist/resend/docs/email/DOC.md +1271 -0
- package/dist/salesforce/docs/crm/javascript/DOC.md +1241 -0
- package/dist/salesforce/docs/crm/python/DOC.md +1183 -0
- package/dist/search-index.json +1 -0
- package/dist/sendgrid/docs/email-api/javascript/DOC.md +371 -0
- package/dist/sendgrid/docs/email-api/python/DOC.md +656 -0
- package/dist/sentry/docs/error-tracking/javascript/DOC.md +1073 -0
- package/dist/sentry/docs/error-tracking/python/DOC.md +1309 -0
- package/dist/shopify/docs/storefront/DOC.md +457 -0
- package/dist/slack/docs/workspace/javascript/DOC.md +933 -0
- package/dist/slack/docs/workspace/python/DOC.md +271 -0
- package/dist/square/docs/payments/javascript/DOC.md +1855 -0
- package/dist/square/docs/payments/python/DOC.md +1728 -0
- package/dist/stripe/docs/api/DOC.md +1727 -0
- package/dist/stripe/docs/payments/DOC.md +1726 -0
- package/dist/stytch/docs/auth/javascript/DOC.md +1813 -0
- package/dist/stytch/docs/auth/python/DOC.md +1962 -0
- package/dist/supabase/docs/client/DOC.md +1606 -0
- package/dist/twilio/docs/messaging/python/DOC.md +469 -0
- package/dist/twilio/docs/messaging/typescript/DOC.md +946 -0
- package/dist/vercel/docs/platform/DOC.md +1940 -0
- package/dist/weaviate/docs/vector-db/javascript/DOC.md +1268 -0
- package/dist/weaviate/docs/vector-db/python/DOC.md +1388 -0
- package/dist/zendesk/docs/support/javascript/DOC.md +2150 -0
- package/dist/zendesk/docs/support/python/DOC.md +2297 -0
- package/package.json +22 -6
- package/skills/get-api-docs/SKILL.md +84 -0
- package/src/commands/annotate.js +83 -0
- package/src/commands/build.js +12 -1
- package/src/commands/feedback.js +150 -0
- package/src/commands/get.js +83 -42
- package/src/commands/search.js +7 -0
- package/src/index.js +43 -17
- package/src/lib/analytics.js +90 -0
- package/src/lib/annotations.js +57 -0
- package/src/lib/bm25.js +170 -0
- package/src/lib/cache.js +69 -6
- package/src/lib/config.js +8 -3
- package/src/lib/identity.js +99 -0
- package/src/lib/registry.js +103 -20
- package/src/lib/telemetry.js +86 -0
- package/src/mcp/server.js +177 -0
- 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
|
+
```
|