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,2033 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: crm
|
|
3
|
+
description: "HubSpot Python SDK for managing CRM contacts, companies, deals, and marketing automation via the HubSpot API."
|
|
4
|
+
metadata:
|
|
5
|
+
languages: "python"
|
|
6
|
+
versions: "12.0.0"
|
|
7
|
+
updated-on: "2026-03-01"
|
|
8
|
+
source: maintainer
|
|
9
|
+
tags: "hubspot,crm,marketing,contacts,automation"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# HubSpot Python SDK Coding Guidelines
|
|
13
|
+
|
|
14
|
+
You are a HubSpot API coding expert. Help me write code using the HubSpot API with the official Python SDK.
|
|
15
|
+
|
|
16
|
+
Official SDK documentation and code samples:
|
|
17
|
+
https://developers.hubspot.com/docs/api/overview
|
|
18
|
+
|
|
19
|
+
## Golden Rule: Use the Correct and Current SDK
|
|
20
|
+
|
|
21
|
+
Always use the official HubSpot Python SDK (`hubspot-api-client`), which is the standard library for all HubSpot API interactions. Do not use deprecated or unofficial packages.
|
|
22
|
+
|
|
23
|
+
- **Library Name:** HubSpot Python SDK
|
|
24
|
+
- **PyPI Package:** `hubspot-api-client`
|
|
25
|
+
- **Current Version:** 12.0.0
|
|
26
|
+
- **Deprecated Packages:** `hubspot-python`, `hubspot3` (do not use these)
|
|
27
|
+
|
|
28
|
+
**Installation:**
|
|
29
|
+
|
|
30
|
+
- **Correct:** `pip install hubspot-api-client`
|
|
31
|
+
- **Incorrect:** `pip install hubspot-python` or `pip install hubspot3`
|
|
32
|
+
|
|
33
|
+
**APIs and Usage:**
|
|
34
|
+
|
|
35
|
+
- **Correct:** `from hubspot import HubSpot`
|
|
36
|
+
- **Correct:** `api_client = HubSpot(access_token=token)`
|
|
37
|
+
- **Correct:** `api_client.crm.contacts.basic_api.create(...)`
|
|
38
|
+
- **Incorrect:** `HubspotClient` or `HubspotAPI`
|
|
39
|
+
- **Incorrect:** Legacy v2 API endpoints
|
|
40
|
+
- **Incorrect:** Using `hapikey` (removed after v5.1.0)
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
Install the SDK via pip:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install hubspot-api-client
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The SDK requires Python 3.9 or higher.
|
|
51
|
+
|
|
52
|
+
For development with additional dependencies:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install hubspot-api-client[dev]
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Authentication
|
|
59
|
+
|
|
60
|
+
HubSpot API uses access tokens for authentication. There are three types of access tokens:
|
|
61
|
+
|
|
62
|
+
1. **Private App Access Tokens** (recommended for server-side integrations)
|
|
63
|
+
2. **OAuth Access Tokens** (for public apps and integrations)
|
|
64
|
+
3. **Legacy API Keys** (deprecated, will be revoked November 19, 2025)
|
|
65
|
+
|
|
66
|
+
### Environment Variable Configuration
|
|
67
|
+
|
|
68
|
+
Set your access token as an environment variable:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# .env file
|
|
72
|
+
HUBSPOT_ACCESS_TOKEN=your_access_token_here
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Creating a Private App:**
|
|
76
|
+
|
|
77
|
+
1. Navigate to Settings > Integrations > Private Apps in your HubSpot account
|
|
78
|
+
2. Click "Create private app"
|
|
79
|
+
3. Configure the required scopes (permissions)
|
|
80
|
+
4. Click "Create app" and copy the access token
|
|
81
|
+
|
|
82
|
+
## Initialization
|
|
83
|
+
|
|
84
|
+
### Basic Initialization
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from hubspot import HubSpot
|
|
88
|
+
import os
|
|
89
|
+
|
|
90
|
+
# Initialize with access token from environment variable
|
|
91
|
+
api_client = HubSpot(access_token=os.getenv('HUBSPOT_ACCESS_TOKEN'))
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Initialization with OAuth
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from hubspot import HubSpot
|
|
98
|
+
|
|
99
|
+
api_client = HubSpot(access_token='YOUR_OAUTH_ACCESS_TOKEN')
|
|
100
|
+
|
|
101
|
+
# Update token when refreshed
|
|
102
|
+
api_client.access_token = 'NEW_ACCESS_TOKEN'
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Alternative Initialization Methods
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
from hubspot import HubSpot
|
|
109
|
+
|
|
110
|
+
# Option 1: Set token during initialization
|
|
111
|
+
api_client = HubSpot(access_token='your_access_token')
|
|
112
|
+
|
|
113
|
+
# Option 2: Set token after initialization
|
|
114
|
+
api_client = HubSpot()
|
|
115
|
+
api_client.access_token = 'your_access_token'
|
|
116
|
+
|
|
117
|
+
# Option 3: Using Client.create method
|
|
118
|
+
import hubspot
|
|
119
|
+
api_client = hubspot.Client.create(access_token='your_access_token')
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## CRM API - Contacts
|
|
123
|
+
|
|
124
|
+
### Create a Contact
|
|
125
|
+
|
|
126
|
+
**Basic Example:**
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from hubspot import HubSpot
|
|
130
|
+
from hubspot.crm.contacts import SimplePublicObjectInputForCreate, ApiException
|
|
131
|
+
import os
|
|
132
|
+
|
|
133
|
+
api_client = HubSpot(access_token=os.getenv('HUBSPOT_ACCESS_TOKEN'))
|
|
134
|
+
|
|
135
|
+
def create_contact():
|
|
136
|
+
properties = {
|
|
137
|
+
"email": "example@company.com",
|
|
138
|
+
"firstname": "John",
|
|
139
|
+
"lastname": "Doe",
|
|
140
|
+
"phone": "555-0100",
|
|
141
|
+
"company": "Example Company",
|
|
142
|
+
"website": "example.com"
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
simple_public_object_input_for_create = SimplePublicObjectInputForCreate(
|
|
146
|
+
properties=properties
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
try:
|
|
150
|
+
api_response = api_client.crm.contacts.basic_api.create(
|
|
151
|
+
simple_public_object_input_for_create=simple_public_object_input_for_create
|
|
152
|
+
)
|
|
153
|
+
print(f"Contact created with ID: {api_response.id}")
|
|
154
|
+
return api_response
|
|
155
|
+
except ApiException as e:
|
|
156
|
+
print(f"Exception when creating contact: {e}")
|
|
157
|
+
|
|
158
|
+
create_contact()
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Advanced Example with Custom Properties:**
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
from hubspot.crm.contacts import SimplePublicObjectInputForCreate, ApiException
|
|
165
|
+
|
|
166
|
+
def create_contact_advanced():
|
|
167
|
+
properties = {
|
|
168
|
+
"email": "jane@example.com",
|
|
169
|
+
"firstname": "Jane",
|
|
170
|
+
"lastname": "Smith",
|
|
171
|
+
"phone": "555-0200",
|
|
172
|
+
"company": "Tech Corp",
|
|
173
|
+
"jobtitle": "Software Engineer",
|
|
174
|
+
"lifecyclestage": "lead",
|
|
175
|
+
"hs_lead_status": "NEW",
|
|
176
|
+
# Custom properties
|
|
177
|
+
"custom_field": "custom_value",
|
|
178
|
+
"industry": "Technology"
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
simple_public_object_input = SimplePublicObjectInputForCreate(properties=properties)
|
|
182
|
+
|
|
183
|
+
try:
|
|
184
|
+
api_response = api_client.crm.contacts.basic_api.create(
|
|
185
|
+
simple_public_object_input_for_create=simple_public_object_input
|
|
186
|
+
)
|
|
187
|
+
print(f"Contact created with ID: {api_response.id}")
|
|
188
|
+
print(f"Properties: {api_response.properties}")
|
|
189
|
+
return api_response
|
|
190
|
+
except ApiException as e:
|
|
191
|
+
if e.status == 409:
|
|
192
|
+
print("Contact with this email already exists")
|
|
193
|
+
else:
|
|
194
|
+
print(f"Exception when creating contact: {e}")
|
|
195
|
+
|
|
196
|
+
create_contact_advanced()
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Get a Contact
|
|
200
|
+
|
|
201
|
+
**By ID:**
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
from hubspot.crm.contacts import ApiException
|
|
205
|
+
|
|
206
|
+
def get_contact(contact_id):
|
|
207
|
+
properties = ["email", "firstname", "lastname", "phone", "company"]
|
|
208
|
+
|
|
209
|
+
try:
|
|
210
|
+
api_response = api_client.crm.contacts.basic_api.get_by_id(
|
|
211
|
+
contact_id=contact_id,
|
|
212
|
+
properties=properties
|
|
213
|
+
)
|
|
214
|
+
print(f"Contact: {api_response.properties}")
|
|
215
|
+
return api_response
|
|
216
|
+
except ApiException as e:
|
|
217
|
+
print(f"Exception when fetching contact: {e}")
|
|
218
|
+
|
|
219
|
+
get_contact("12345")
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**By Email:**
|
|
223
|
+
|
|
224
|
+
```python
|
|
225
|
+
from hubspot.crm.contacts import PublicObjectSearchRequest, ApiException
|
|
226
|
+
|
|
227
|
+
def get_contact_by_email(email):
|
|
228
|
+
filter_obj = {
|
|
229
|
+
"propertyName": "email",
|
|
230
|
+
"operator": "EQ",
|
|
231
|
+
"value": email
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
filter_group = {
|
|
235
|
+
"filters": [filter_obj]
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
sort = {
|
|
239
|
+
"propertyName": "createdate",
|
|
240
|
+
"direction": "DESCENDING"
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
public_object_search_request = PublicObjectSearchRequest(
|
|
244
|
+
filter_groups=[filter_group],
|
|
245
|
+
sorts=[sort],
|
|
246
|
+
properties=["email", "firstname", "lastname"],
|
|
247
|
+
limit=1
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
try:
|
|
251
|
+
api_response = api_client.crm.contacts.search_api.do_search(
|
|
252
|
+
public_object_search_request=public_object_search_request
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
if api_response.total > 0:
|
|
256
|
+
return api_response.results[0]
|
|
257
|
+
return None
|
|
258
|
+
except ApiException as e:
|
|
259
|
+
print(f"Exception when searching contact: {e}")
|
|
260
|
+
|
|
261
|
+
get_contact_by_email("example@company.com")
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Update a Contact
|
|
265
|
+
|
|
266
|
+
```python
|
|
267
|
+
from hubspot.crm.contacts import SimplePublicObjectInput, ApiException
|
|
268
|
+
|
|
269
|
+
def update_contact(contact_id):
|
|
270
|
+
properties = {
|
|
271
|
+
"firstname": "Updated Name",
|
|
272
|
+
"phone": "555-9999",
|
|
273
|
+
"lifecyclestage": "opportunity"
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
simple_public_object_input = SimplePublicObjectInput(properties=properties)
|
|
277
|
+
|
|
278
|
+
try:
|
|
279
|
+
api_response = api_client.crm.contacts.basic_api.update(
|
|
280
|
+
contact_id=contact_id,
|
|
281
|
+
simple_public_object_input=simple_public_object_input
|
|
282
|
+
)
|
|
283
|
+
print(f"Contact updated: {api_response.id}")
|
|
284
|
+
return api_response
|
|
285
|
+
except ApiException as e:
|
|
286
|
+
print(f"Exception when updating contact: {e}")
|
|
287
|
+
|
|
288
|
+
update_contact("12345")
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### List Contacts
|
|
292
|
+
|
|
293
|
+
**Basic Pagination:**
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
from hubspot.crm.contacts import ApiException
|
|
297
|
+
|
|
298
|
+
def list_contacts():
|
|
299
|
+
limit = 10
|
|
300
|
+
properties = ["email", "firstname", "lastname", "company"]
|
|
301
|
+
|
|
302
|
+
try:
|
|
303
|
+
api_response = api_client.crm.contacts.basic_api.get_page(
|
|
304
|
+
limit=limit,
|
|
305
|
+
properties=properties
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
print(f"Found {len(api_response.results)} contacts")
|
|
309
|
+
for contact in api_response.results:
|
|
310
|
+
print(f"{contact.properties.get('firstname')} {contact.properties.get('lastname')}")
|
|
311
|
+
|
|
312
|
+
return api_response
|
|
313
|
+
except ApiException as e:
|
|
314
|
+
print(f"Exception when listing contacts: {e}")
|
|
315
|
+
|
|
316
|
+
list_contacts()
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**Get All Contacts (with pagination handling):**
|
|
320
|
+
|
|
321
|
+
```python
|
|
322
|
+
from hubspot.crm.contacts import ApiException
|
|
323
|
+
|
|
324
|
+
def get_all_contacts():
|
|
325
|
+
all_contacts = []
|
|
326
|
+
after = None
|
|
327
|
+
limit = 100
|
|
328
|
+
properties = ["email", "firstname", "lastname"]
|
|
329
|
+
|
|
330
|
+
try:
|
|
331
|
+
while True:
|
|
332
|
+
api_response = api_client.crm.contacts.basic_api.get_page(
|
|
333
|
+
limit=limit,
|
|
334
|
+
after=after,
|
|
335
|
+
properties=properties
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
all_contacts.extend(api_response.results)
|
|
339
|
+
|
|
340
|
+
if api_response.paging and api_response.paging.next:
|
|
341
|
+
after = api_response.paging.next.after
|
|
342
|
+
else:
|
|
343
|
+
break
|
|
344
|
+
|
|
345
|
+
print(f"Total contacts retrieved: {len(all_contacts)}")
|
|
346
|
+
return all_contacts
|
|
347
|
+
except ApiException as e:
|
|
348
|
+
print(f"Exception when getting all contacts: {e}")
|
|
349
|
+
|
|
350
|
+
get_all_contacts()
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
**Using get_all method:**
|
|
354
|
+
|
|
355
|
+
```python
|
|
356
|
+
from hubspot.crm.contacts import ApiException
|
|
357
|
+
|
|
358
|
+
def get_all_contacts_simple():
|
|
359
|
+
try:
|
|
360
|
+
# The get_all method handles pagination automatically
|
|
361
|
+
all_contacts = api_client.crm.contacts.get_all()
|
|
362
|
+
print(f"Total contacts: {len(all_contacts)}")
|
|
363
|
+
return all_contacts
|
|
364
|
+
except ApiException as e:
|
|
365
|
+
print(f"Exception when getting all contacts: {e}")
|
|
366
|
+
|
|
367
|
+
get_all_contacts_simple()
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### Delete a Contact
|
|
371
|
+
|
|
372
|
+
```python
|
|
373
|
+
from hubspot.crm.contacts import ApiException
|
|
374
|
+
|
|
375
|
+
def delete_contact(contact_id):
|
|
376
|
+
try:
|
|
377
|
+
api_client.crm.contacts.basic_api.archive(contact_id=contact_id)
|
|
378
|
+
print(f"Contact deleted: {contact_id}")
|
|
379
|
+
except ApiException as e:
|
|
380
|
+
print(f"Exception when deleting contact: {e}")
|
|
381
|
+
|
|
382
|
+
delete_contact("12345")
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## CRM API - Companies
|
|
386
|
+
|
|
387
|
+
### Create a Company
|
|
388
|
+
|
|
389
|
+
```python
|
|
390
|
+
from hubspot.crm.companies import SimplePublicObjectInputForCreate, ApiException
|
|
391
|
+
|
|
392
|
+
def create_company():
|
|
393
|
+
properties = {
|
|
394
|
+
"name": "Example Company",
|
|
395
|
+
"domain": "example.com",
|
|
396
|
+
"city": "San Francisco",
|
|
397
|
+
"state": "California",
|
|
398
|
+
"industry": "Technology",
|
|
399
|
+
"phone": "555-0100",
|
|
400
|
+
"numberofemployees": "50",
|
|
401
|
+
"description": "A technology company"
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
simple_public_object_input = SimplePublicObjectInputForCreate(properties=properties)
|
|
405
|
+
|
|
406
|
+
try:
|
|
407
|
+
api_response = api_client.crm.companies.basic_api.create(
|
|
408
|
+
simple_public_object_input_for_create=simple_public_object_input
|
|
409
|
+
)
|
|
410
|
+
print(f"Company created with ID: {api_response.id}")
|
|
411
|
+
return api_response
|
|
412
|
+
except ApiException as e:
|
|
413
|
+
print(f"Exception when creating company: {e}")
|
|
414
|
+
|
|
415
|
+
create_company()
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
### Get a Company
|
|
419
|
+
|
|
420
|
+
```python
|
|
421
|
+
from hubspot.crm.companies import ApiException
|
|
422
|
+
|
|
423
|
+
def get_company(company_id):
|
|
424
|
+
properties = ["name", "domain", "city", "industry", "phone"]
|
|
425
|
+
|
|
426
|
+
try:
|
|
427
|
+
api_response = api_client.crm.companies.basic_api.get_by_id(
|
|
428
|
+
company_id=company_id,
|
|
429
|
+
properties=properties
|
|
430
|
+
)
|
|
431
|
+
print(f"Company: {api_response.properties}")
|
|
432
|
+
return api_response
|
|
433
|
+
except ApiException as e:
|
|
434
|
+
print(f"Exception when fetching company: {e}")
|
|
435
|
+
|
|
436
|
+
get_company("12345")
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
### Update a Company
|
|
440
|
+
|
|
441
|
+
```python
|
|
442
|
+
from hubspot.crm.companies import SimplePublicObjectInput, ApiException
|
|
443
|
+
|
|
444
|
+
def update_company(company_id):
|
|
445
|
+
properties = {
|
|
446
|
+
"name": "Updated Company Name",
|
|
447
|
+
"numberofemployees": "100",
|
|
448
|
+
"annualrevenue": "1000000"
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
simple_public_object_input = SimplePublicObjectInput(properties=properties)
|
|
452
|
+
|
|
453
|
+
try:
|
|
454
|
+
api_response = api_client.crm.companies.basic_api.update(
|
|
455
|
+
company_id=company_id,
|
|
456
|
+
simple_public_object_input=simple_public_object_input
|
|
457
|
+
)
|
|
458
|
+
print(f"Company updated: {api_response.id}")
|
|
459
|
+
return api_response
|
|
460
|
+
except ApiException as e:
|
|
461
|
+
print(f"Exception when updating company: {e}")
|
|
462
|
+
|
|
463
|
+
update_company("12345")
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### List Companies
|
|
467
|
+
|
|
468
|
+
```python
|
|
469
|
+
from hubspot.crm.companies import ApiException
|
|
470
|
+
|
|
471
|
+
def list_companies():
|
|
472
|
+
limit = 10
|
|
473
|
+
properties = ["name", "domain", "city", "industry"]
|
|
474
|
+
|
|
475
|
+
try:
|
|
476
|
+
api_response = api_client.crm.companies.basic_api.get_page(
|
|
477
|
+
limit=limit,
|
|
478
|
+
properties=properties
|
|
479
|
+
)
|
|
480
|
+
|
|
481
|
+
print(f"Found {len(api_response.results)} companies")
|
|
482
|
+
return api_response
|
|
483
|
+
except ApiException as e:
|
|
484
|
+
print(f"Exception when listing companies: {e}")
|
|
485
|
+
|
|
486
|
+
list_companies()
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
## CRM API - Deals
|
|
490
|
+
|
|
491
|
+
### Create a Deal
|
|
492
|
+
|
|
493
|
+
```python
|
|
494
|
+
from hubspot.crm.deals import SimplePublicObjectInputForCreate, ApiException
|
|
495
|
+
|
|
496
|
+
def create_deal():
|
|
497
|
+
properties = {
|
|
498
|
+
"dealname": "New Deal",
|
|
499
|
+
"dealstage": "appointmentscheduled",
|
|
500
|
+
"amount": "10000",
|
|
501
|
+
"closedate": "2025-12-31",
|
|
502
|
+
"pipeline": "default",
|
|
503
|
+
"hubspot_owner_id": "12345"
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
simple_public_object_input = SimplePublicObjectInputForCreate(properties=properties)
|
|
507
|
+
|
|
508
|
+
try:
|
|
509
|
+
api_response = api_client.crm.deals.basic_api.create(
|
|
510
|
+
simple_public_object_input_for_create=simple_public_object_input
|
|
511
|
+
)
|
|
512
|
+
print(f"Deal created with ID: {api_response.id}")
|
|
513
|
+
return api_response
|
|
514
|
+
except ApiException as e:
|
|
515
|
+
print(f"Exception when creating deal: {e}")
|
|
516
|
+
|
|
517
|
+
create_deal()
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### Get a Deal
|
|
521
|
+
|
|
522
|
+
```python
|
|
523
|
+
from hubspot.crm.deals import ApiException
|
|
524
|
+
|
|
525
|
+
def get_deal(deal_id):
|
|
526
|
+
properties = ["dealname", "dealstage", "amount", "closedate"]
|
|
527
|
+
|
|
528
|
+
try:
|
|
529
|
+
api_response = api_client.crm.deals.basic_api.get_by_id(
|
|
530
|
+
deal_id=deal_id,
|
|
531
|
+
properties=properties
|
|
532
|
+
)
|
|
533
|
+
print(f"Deal: {api_response.properties}")
|
|
534
|
+
return api_response
|
|
535
|
+
except ApiException as e:
|
|
536
|
+
print(f"Exception when fetching deal: {e}")
|
|
537
|
+
|
|
538
|
+
get_deal("12345")
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
### Update a Deal
|
|
542
|
+
|
|
543
|
+
```python
|
|
544
|
+
from hubspot.crm.deals import SimplePublicObjectInput, ApiException
|
|
545
|
+
|
|
546
|
+
def update_deal(deal_id):
|
|
547
|
+
properties = {
|
|
548
|
+
"dealstage": "closedwon",
|
|
549
|
+
"amount": "15000",
|
|
550
|
+
"closedate": "2025-11-30"
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
simple_public_object_input = SimplePublicObjectInput(properties=properties)
|
|
554
|
+
|
|
555
|
+
try:
|
|
556
|
+
api_response = api_client.crm.deals.basic_api.update(
|
|
557
|
+
deal_id=deal_id,
|
|
558
|
+
simple_public_object_input=simple_public_object_input
|
|
559
|
+
)
|
|
560
|
+
print(f"Deal updated: {api_response.id}")
|
|
561
|
+
return api_response
|
|
562
|
+
except ApiException as e:
|
|
563
|
+
print(f"Exception when updating deal: {e}")
|
|
564
|
+
|
|
565
|
+
update_deal("12345")
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
### List Deals
|
|
569
|
+
|
|
570
|
+
```python
|
|
571
|
+
from hubspot.crm.deals import ApiException
|
|
572
|
+
|
|
573
|
+
def list_deals():
|
|
574
|
+
limit = 10
|
|
575
|
+
properties = ["dealname", "dealstage", "amount"]
|
|
576
|
+
|
|
577
|
+
try:
|
|
578
|
+
api_response = api_client.crm.deals.basic_api.get_page(
|
|
579
|
+
limit=limit,
|
|
580
|
+
properties=properties
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
print(f"Found {len(api_response.results)} deals")
|
|
584
|
+
return api_response
|
|
585
|
+
except ApiException as e:
|
|
586
|
+
print(f"Exception when listing deals: {e}")
|
|
587
|
+
|
|
588
|
+
list_deals()
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
## CRM API - Tickets
|
|
592
|
+
|
|
593
|
+
### Create a Ticket
|
|
594
|
+
|
|
595
|
+
```python
|
|
596
|
+
from hubspot.crm.tickets import SimplePublicObjectInputForCreate, ApiException
|
|
597
|
+
|
|
598
|
+
def create_ticket():
|
|
599
|
+
properties = {
|
|
600
|
+
"subject": "Customer Support Request",
|
|
601
|
+
"content": "Customer needs help with product setup",
|
|
602
|
+
"hs_pipeline": "0",
|
|
603
|
+
"hs_pipeline_stage": "1",
|
|
604
|
+
"hs_ticket_priority": "HIGH",
|
|
605
|
+
"hubspot_owner_id": "12345"
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
simple_public_object_input = SimplePublicObjectInputForCreate(properties=properties)
|
|
609
|
+
|
|
610
|
+
try:
|
|
611
|
+
api_response = api_client.crm.tickets.basic_api.create(
|
|
612
|
+
simple_public_object_input_for_create=simple_public_object_input
|
|
613
|
+
)
|
|
614
|
+
print(f"Ticket created with ID: {api_response.id}")
|
|
615
|
+
return api_response
|
|
616
|
+
except ApiException as e:
|
|
617
|
+
print(f"Exception when creating ticket: {e}")
|
|
618
|
+
|
|
619
|
+
create_ticket()
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### Get a Ticket
|
|
623
|
+
|
|
624
|
+
```python
|
|
625
|
+
from hubspot.crm.tickets import ApiException
|
|
626
|
+
|
|
627
|
+
def get_ticket(ticket_id):
|
|
628
|
+
properties = ["subject", "content", "hs_pipeline_stage", "hs_ticket_priority"]
|
|
629
|
+
|
|
630
|
+
try:
|
|
631
|
+
api_response = api_client.crm.tickets.basic_api.get_by_id(
|
|
632
|
+
ticket_id=ticket_id,
|
|
633
|
+
properties=properties
|
|
634
|
+
)
|
|
635
|
+
print(f"Ticket: {api_response.properties}")
|
|
636
|
+
return api_response
|
|
637
|
+
except ApiException as e:
|
|
638
|
+
print(f"Exception when fetching ticket: {e}")
|
|
639
|
+
|
|
640
|
+
get_ticket("12345")
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
### Update a Ticket
|
|
644
|
+
|
|
645
|
+
```python
|
|
646
|
+
from hubspot.crm.tickets import SimplePublicObjectInput, ApiException
|
|
647
|
+
|
|
648
|
+
def update_ticket(ticket_id):
|
|
649
|
+
properties = {
|
|
650
|
+
"hs_pipeline_stage": "4", # Closed
|
|
651
|
+
"hs_ticket_priority": "LOW"
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
simple_public_object_input = SimplePublicObjectInput(properties=properties)
|
|
655
|
+
|
|
656
|
+
try:
|
|
657
|
+
api_response = api_client.crm.tickets.basic_api.update(
|
|
658
|
+
ticket_id=ticket_id,
|
|
659
|
+
simple_public_object_input=simple_public_object_input
|
|
660
|
+
)
|
|
661
|
+
print(f"Ticket updated: {api_response.id}")
|
|
662
|
+
return api_response
|
|
663
|
+
except ApiException as e:
|
|
664
|
+
print(f"Exception when updating ticket: {e}")
|
|
665
|
+
|
|
666
|
+
update_ticket("12345")
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
## CRM API - Associations
|
|
670
|
+
|
|
671
|
+
Associations link objects together (e.g., contacts to companies, deals to contacts).
|
|
672
|
+
|
|
673
|
+
### Create Association
|
|
674
|
+
|
|
675
|
+
**Associate Contact with Company:**
|
|
676
|
+
|
|
677
|
+
```python
|
|
678
|
+
from hubspot.crm.associations import ApiException
|
|
679
|
+
|
|
680
|
+
def associate_contact_with_company(contact_id, company_id):
|
|
681
|
+
try:
|
|
682
|
+
api_response = api_client.crm.contacts.associations_api.create(
|
|
683
|
+
contact_id=contact_id,
|
|
684
|
+
to_object_type="companies",
|
|
685
|
+
to_object_id=company_id,
|
|
686
|
+
association_type="contact_to_company"
|
|
687
|
+
)
|
|
688
|
+
print("Association created")
|
|
689
|
+
return api_response
|
|
690
|
+
except ApiException as e:
|
|
691
|
+
print(f"Exception when creating association: {e}")
|
|
692
|
+
|
|
693
|
+
associate_contact_with_company("12345", "67890")
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
**Associate Deal with Contact:**
|
|
697
|
+
|
|
698
|
+
```python
|
|
699
|
+
from hubspot.crm.associations import ApiException
|
|
700
|
+
|
|
701
|
+
def associate_deal_with_contact(deal_id, contact_id):
|
|
702
|
+
try:
|
|
703
|
+
api_response = api_client.crm.deals.associations_api.create(
|
|
704
|
+
deal_id=deal_id,
|
|
705
|
+
to_object_type="contacts",
|
|
706
|
+
to_object_id=contact_id,
|
|
707
|
+
association_type="deal_to_contact"
|
|
708
|
+
)
|
|
709
|
+
print("Association created")
|
|
710
|
+
return api_response
|
|
711
|
+
except ApiException as e:
|
|
712
|
+
print(f"Exception when creating association: {e}")
|
|
713
|
+
|
|
714
|
+
associate_deal_with_contact("12345", "67890")
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
### Get Associations
|
|
718
|
+
|
|
719
|
+
```python
|
|
720
|
+
from hubspot.crm.associations import ApiException
|
|
721
|
+
|
|
722
|
+
def get_contact_associations(contact_id):
|
|
723
|
+
try:
|
|
724
|
+
# Get associated companies
|
|
725
|
+
companies = api_client.crm.contacts.associations_api.get_all(
|
|
726
|
+
contact_id=contact_id,
|
|
727
|
+
to_object_type="companies"
|
|
728
|
+
)
|
|
729
|
+
|
|
730
|
+
# Get associated deals
|
|
731
|
+
deals = api_client.crm.contacts.associations_api.get_all(
|
|
732
|
+
contact_id=contact_id,
|
|
733
|
+
to_object_type="deals"
|
|
734
|
+
)
|
|
735
|
+
|
|
736
|
+
print(f"Associated companies: {companies.results}")
|
|
737
|
+
print(f"Associated deals: {deals.results}")
|
|
738
|
+
|
|
739
|
+
return {"companies": companies, "deals": deals}
|
|
740
|
+
except ApiException as e:
|
|
741
|
+
print(f"Exception when fetching associations: {e}")
|
|
742
|
+
|
|
743
|
+
get_contact_associations("12345")
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
### Remove Association
|
|
747
|
+
|
|
748
|
+
```python
|
|
749
|
+
from hubspot.crm.associations import ApiException
|
|
750
|
+
|
|
751
|
+
def remove_association(contact_id, company_id):
|
|
752
|
+
try:
|
|
753
|
+
api_client.crm.contacts.associations_api.archive(
|
|
754
|
+
contact_id=contact_id,
|
|
755
|
+
to_object_type="companies",
|
|
756
|
+
to_object_id=company_id,
|
|
757
|
+
association_type="contact_to_company"
|
|
758
|
+
)
|
|
759
|
+
print("Association removed")
|
|
760
|
+
except ApiException as e:
|
|
761
|
+
print(f"Exception when removing association: {e}")
|
|
762
|
+
|
|
763
|
+
remove_association("12345", "67890")
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
## CRM API - Batch Operations
|
|
767
|
+
|
|
768
|
+
Batch operations allow you to create, update, or read up to 100 records in a single API call.
|
|
769
|
+
|
|
770
|
+
### Batch Create Contacts
|
|
771
|
+
|
|
772
|
+
```python
|
|
773
|
+
from hubspot.crm.contacts import BatchInputSimplePublicObjectInputForCreate, SimplePublicObjectInputForCreate, ApiException
|
|
774
|
+
|
|
775
|
+
def batch_create_contacts():
|
|
776
|
+
inputs = [
|
|
777
|
+
SimplePublicObjectInputForCreate(
|
|
778
|
+
properties={
|
|
779
|
+
"email": "contact1@example.com",
|
|
780
|
+
"firstname": "Contact",
|
|
781
|
+
"lastname": "One"
|
|
782
|
+
}
|
|
783
|
+
),
|
|
784
|
+
SimplePublicObjectInputForCreate(
|
|
785
|
+
properties={
|
|
786
|
+
"email": "contact2@example.com",
|
|
787
|
+
"firstname": "Contact",
|
|
788
|
+
"lastname": "Two"
|
|
789
|
+
}
|
|
790
|
+
),
|
|
791
|
+
SimplePublicObjectInputForCreate(
|
|
792
|
+
properties={
|
|
793
|
+
"email": "contact3@example.com",
|
|
794
|
+
"firstname": "Contact",
|
|
795
|
+
"lastname": "Three"
|
|
796
|
+
}
|
|
797
|
+
)
|
|
798
|
+
]
|
|
799
|
+
|
|
800
|
+
batch_input = BatchInputSimplePublicObjectInputForCreate(inputs=inputs)
|
|
801
|
+
|
|
802
|
+
try:
|
|
803
|
+
api_response = api_client.crm.contacts.batch_api.create(
|
|
804
|
+
batch_input_simple_public_object_input_for_create=batch_input
|
|
805
|
+
)
|
|
806
|
+
print(f"Created {len(api_response.results)} contacts")
|
|
807
|
+
return api_response
|
|
808
|
+
except ApiException as e:
|
|
809
|
+
print(f"Exception when batch creating contacts: {e}")
|
|
810
|
+
|
|
811
|
+
batch_create_contacts()
|
|
812
|
+
```
|
|
813
|
+
|
|
814
|
+
### Batch Update Contacts
|
|
815
|
+
|
|
816
|
+
```python
|
|
817
|
+
from hubspot.crm.contacts import BatchInputSimplePublicObjectBatchInput, SimplePublicObjectBatchInput, ApiException
|
|
818
|
+
|
|
819
|
+
def batch_update_contacts(contact_ids):
|
|
820
|
+
inputs = []
|
|
821
|
+
for contact_id in contact_ids:
|
|
822
|
+
inputs.append(
|
|
823
|
+
SimplePublicObjectBatchInput(
|
|
824
|
+
id=contact_id,
|
|
825
|
+
properties={
|
|
826
|
+
"lifecyclestage": "customer",
|
|
827
|
+
"hs_lead_status": "CONNECTED"
|
|
828
|
+
}
|
|
829
|
+
)
|
|
830
|
+
)
|
|
831
|
+
|
|
832
|
+
batch_input = BatchInputSimplePublicObjectBatchInput(inputs=inputs)
|
|
833
|
+
|
|
834
|
+
try:
|
|
835
|
+
api_response = api_client.crm.contacts.batch_api.update(
|
|
836
|
+
batch_input_simple_public_object_batch_input=batch_input
|
|
837
|
+
)
|
|
838
|
+
print(f"Updated {len(api_response.results)} contacts")
|
|
839
|
+
return api_response
|
|
840
|
+
except ApiException as e:
|
|
841
|
+
print(f"Exception when batch updating contacts: {e}")
|
|
842
|
+
|
|
843
|
+
batch_update_contacts(["12345", "67890", "11111"])
|
|
844
|
+
```
|
|
845
|
+
|
|
846
|
+
### Batch Read Contacts
|
|
847
|
+
|
|
848
|
+
```python
|
|
849
|
+
from hubspot.crm.contacts import BatchReadInputSimplePublicObjectId, SimplePublicObjectId, ApiException
|
|
850
|
+
|
|
851
|
+
def batch_read_contacts(contact_ids):
|
|
852
|
+
inputs = [SimplePublicObjectId(id=contact_id) for contact_id in contact_ids]
|
|
853
|
+
|
|
854
|
+
batch_input = BatchReadInputSimplePublicObjectId(
|
|
855
|
+
properties=["email", "firstname", "lastname", "phone"],
|
|
856
|
+
inputs=inputs
|
|
857
|
+
)
|
|
858
|
+
|
|
859
|
+
try:
|
|
860
|
+
api_response = api_client.crm.contacts.batch_api.read(
|
|
861
|
+
batch_read_input_simple_public_object_id=batch_input
|
|
862
|
+
)
|
|
863
|
+
print(f"Retrieved {len(api_response.results)} contacts")
|
|
864
|
+
return api_response
|
|
865
|
+
except ApiException as e:
|
|
866
|
+
print(f"Exception when batch reading contacts: {e}")
|
|
867
|
+
|
|
868
|
+
batch_read_contacts(["12345", "67890", "11111"])
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
### Batch Upsert Contacts
|
|
872
|
+
|
|
873
|
+
```python
|
|
874
|
+
from hubspot.crm.contacts import BatchInputSimplePublicObjectInputForCreate, SimplePublicObjectInputForCreate, ApiException
|
|
875
|
+
|
|
876
|
+
def batch_upsert_contacts():
|
|
877
|
+
inputs = [
|
|
878
|
+
SimplePublicObjectInputForCreate(
|
|
879
|
+
properties={
|
|
880
|
+
"email": "existing@example.com",
|
|
881
|
+
"firstname": "Updated",
|
|
882
|
+
"lastname": "Name"
|
|
883
|
+
},
|
|
884
|
+
id_property="email"
|
|
885
|
+
),
|
|
886
|
+
SimplePublicObjectInputForCreate(
|
|
887
|
+
properties={
|
|
888
|
+
"email": "new@example.com",
|
|
889
|
+
"firstname": "New",
|
|
890
|
+
"lastname": "Contact"
|
|
891
|
+
},
|
|
892
|
+
id_property="email"
|
|
893
|
+
)
|
|
894
|
+
]
|
|
895
|
+
|
|
896
|
+
batch_input = BatchInputSimplePublicObjectInputForCreate(inputs=inputs)
|
|
897
|
+
|
|
898
|
+
try:
|
|
899
|
+
api_response = api_client.crm.contacts.batch_api.upsert(
|
|
900
|
+
batch_input_simple_public_object_input_for_create=batch_input
|
|
901
|
+
)
|
|
902
|
+
print(f"Upserted {len(api_response.results)} contacts")
|
|
903
|
+
return api_response
|
|
904
|
+
except ApiException as e:
|
|
905
|
+
print(f"Exception when batch upserting contacts: {e}")
|
|
906
|
+
|
|
907
|
+
batch_upsert_contacts()
|
|
908
|
+
```
|
|
909
|
+
|
|
910
|
+
## CRM API - Search
|
|
911
|
+
|
|
912
|
+
The Search API allows you to filter, sort, and search across CRM objects.
|
|
913
|
+
|
|
914
|
+
### Basic Search
|
|
915
|
+
|
|
916
|
+
```python
|
|
917
|
+
from hubspot.crm.contacts import PublicObjectSearchRequest, ApiException
|
|
918
|
+
|
|
919
|
+
def search_contacts():
|
|
920
|
+
filter_obj = {
|
|
921
|
+
"propertyName": "lifecyclestage",
|
|
922
|
+
"operator": "EQ",
|
|
923
|
+
"value": "lead"
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
filter_group = {
|
|
927
|
+
"filters": [filter_obj]
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
public_object_search_request = PublicObjectSearchRequest(
|
|
931
|
+
filter_groups=[filter_group],
|
|
932
|
+
properties=["email", "firstname", "lastname", "lifecyclestage"],
|
|
933
|
+
limit=10
|
|
934
|
+
)
|
|
935
|
+
|
|
936
|
+
try:
|
|
937
|
+
api_response = api_client.crm.contacts.search_api.do_search(
|
|
938
|
+
public_object_search_request=public_object_search_request
|
|
939
|
+
)
|
|
940
|
+
print(f"Found {api_response.total} contacts")
|
|
941
|
+
print(f"Returned {len(api_response.results)} results")
|
|
942
|
+
return api_response
|
|
943
|
+
except ApiException as e:
|
|
944
|
+
print(f"Exception when searching contacts: {e}")
|
|
945
|
+
|
|
946
|
+
search_contacts()
|
|
947
|
+
```
|
|
948
|
+
|
|
949
|
+
### Advanced Search with Multiple Filters
|
|
950
|
+
|
|
951
|
+
```python
|
|
952
|
+
from hubspot.crm.contacts import PublicObjectSearchRequest, ApiException
|
|
953
|
+
|
|
954
|
+
def advanced_search_contacts():
|
|
955
|
+
filter_group = {
|
|
956
|
+
"filters": [
|
|
957
|
+
{
|
|
958
|
+
"propertyName": "lifecyclestage",
|
|
959
|
+
"operator": "EQ",
|
|
960
|
+
"value": "lead"
|
|
961
|
+
},
|
|
962
|
+
{
|
|
963
|
+
"propertyName": "createdate",
|
|
964
|
+
"operator": "GTE",
|
|
965
|
+
"value": "2025-01-01"
|
|
966
|
+
}
|
|
967
|
+
]
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
sort = {
|
|
971
|
+
"propertyName": "createdate",
|
|
972
|
+
"direction": "DESCENDING"
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
public_object_search_request = PublicObjectSearchRequest(
|
|
976
|
+
filter_groups=[filter_group],
|
|
977
|
+
sorts=[sort],
|
|
978
|
+
properties=["email", "firstname", "lastname", "createdate", "lifecyclestage"],
|
|
979
|
+
limit=100,
|
|
980
|
+
after=0
|
|
981
|
+
)
|
|
982
|
+
|
|
983
|
+
try:
|
|
984
|
+
api_response = api_client.crm.contacts.search_api.do_search(
|
|
985
|
+
public_object_search_request=public_object_search_request
|
|
986
|
+
)
|
|
987
|
+
print(f"Found {api_response.total} matching contacts")
|
|
988
|
+
return api_response
|
|
989
|
+
except ApiException as e:
|
|
990
|
+
print(f"Exception when searching contacts: {e}")
|
|
991
|
+
|
|
992
|
+
advanced_search_contacts()
|
|
993
|
+
```
|
|
994
|
+
|
|
995
|
+
### Search with Association Filters
|
|
996
|
+
|
|
997
|
+
```python
|
|
998
|
+
from hubspot.crm.contacts import PublicObjectSearchRequest, ApiException
|
|
999
|
+
|
|
1000
|
+
def search_contacts_by_company(company_id):
|
|
1001
|
+
filter_obj = {
|
|
1002
|
+
"propertyName": "associations.company",
|
|
1003
|
+
"operator": "EQ",
|
|
1004
|
+
"value": company_id
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
filter_group = {
|
|
1008
|
+
"filters": [filter_obj]
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
public_object_search_request = PublicObjectSearchRequest(
|
|
1012
|
+
filter_groups=[filter_group],
|
|
1013
|
+
properties=["email", "firstname", "lastname"],
|
|
1014
|
+
limit=100
|
|
1015
|
+
)
|
|
1016
|
+
|
|
1017
|
+
try:
|
|
1018
|
+
api_response = api_client.crm.contacts.search_api.do_search(
|
|
1019
|
+
public_object_search_request=public_object_search_request
|
|
1020
|
+
)
|
|
1021
|
+
print(f"Found {len(api_response.results)} contacts for company")
|
|
1022
|
+
return api_response
|
|
1023
|
+
except ApiException as e:
|
|
1024
|
+
print(f"Exception when searching contacts by company: {e}")
|
|
1025
|
+
|
|
1026
|
+
search_contacts_by_company("12345")
|
|
1027
|
+
```
|
|
1028
|
+
|
|
1029
|
+
### Search Operators
|
|
1030
|
+
|
|
1031
|
+
Available operators for search filters:
|
|
1032
|
+
|
|
1033
|
+
- `EQ` - Equal to
|
|
1034
|
+
- `NEQ` - Not equal to
|
|
1035
|
+
- `LT` - Less than
|
|
1036
|
+
- `LTE` - Less than or equal to
|
|
1037
|
+
- `GT` - Greater than
|
|
1038
|
+
- `GTE` - Greater than or equal to
|
|
1039
|
+
- `IN` - In list of values
|
|
1040
|
+
- `NOT_IN` - Not in list of values
|
|
1041
|
+
- `HAS_PROPERTY` - Has property value set
|
|
1042
|
+
- `NOT_HAS_PROPERTY` - Does not have property value set
|
|
1043
|
+
- `CONTAINS_TOKEN` - Contains token (for text)
|
|
1044
|
+
- `NOT_CONTAINS_TOKEN` - Does not contain token
|
|
1045
|
+
|
|
1046
|
+
## CRM API - Properties
|
|
1047
|
+
|
|
1048
|
+
### Get All Contact Properties
|
|
1049
|
+
|
|
1050
|
+
```python
|
|
1051
|
+
from hubspot.crm.properties import ApiException
|
|
1052
|
+
|
|
1053
|
+
def get_all_contact_properties():
|
|
1054
|
+
try:
|
|
1055
|
+
api_response = api_client.crm.properties.core_api.get_all(
|
|
1056
|
+
object_type="contacts"
|
|
1057
|
+
)
|
|
1058
|
+
print(f"Found {len(api_response.results)} contact properties")
|
|
1059
|
+
return api_response
|
|
1060
|
+
except ApiException as e:
|
|
1061
|
+
print(f"Exception when fetching contact properties: {e}")
|
|
1062
|
+
|
|
1063
|
+
get_all_contact_properties()
|
|
1064
|
+
```
|
|
1065
|
+
|
|
1066
|
+
### Create Custom Property
|
|
1067
|
+
|
|
1068
|
+
```python
|
|
1069
|
+
from hubspot.crm.properties import PropertyCreate, ApiException
|
|
1070
|
+
|
|
1071
|
+
def create_custom_property():
|
|
1072
|
+
property_create = PropertyCreate(
|
|
1073
|
+
name="favorite_color",
|
|
1074
|
+
label="Favorite Color",
|
|
1075
|
+
type="string",
|
|
1076
|
+
field_type="text",
|
|
1077
|
+
group_name="contactinformation",
|
|
1078
|
+
description="The contact's favorite color"
|
|
1079
|
+
)
|
|
1080
|
+
|
|
1081
|
+
try:
|
|
1082
|
+
api_response = api_client.crm.properties.core_api.create(
|
|
1083
|
+
object_type="contacts",
|
|
1084
|
+
property_create=property_create
|
|
1085
|
+
)
|
|
1086
|
+
print(f"Custom property created: {api_response.name}")
|
|
1087
|
+
return api_response
|
|
1088
|
+
except ApiException as e:
|
|
1089
|
+
print(f"Exception when creating custom property: {e}")
|
|
1090
|
+
|
|
1091
|
+
create_custom_property()
|
|
1092
|
+
```
|
|
1093
|
+
|
|
1094
|
+
### Create Dropdown Property
|
|
1095
|
+
|
|
1096
|
+
```python
|
|
1097
|
+
from hubspot.crm.properties import PropertyCreate, OptionInput, ApiException
|
|
1098
|
+
|
|
1099
|
+
def create_dropdown_property():
|
|
1100
|
+
options = [
|
|
1101
|
+
OptionInput(label="Bronze", value="bronze", display_order=0),
|
|
1102
|
+
OptionInput(label="Silver", value="silver", display_order=1),
|
|
1103
|
+
OptionInput(label="Gold", value="gold", display_order=2),
|
|
1104
|
+
OptionInput(label="Platinum", value="platinum", display_order=3)
|
|
1105
|
+
]
|
|
1106
|
+
|
|
1107
|
+
property_create = PropertyCreate(
|
|
1108
|
+
name="customer_tier",
|
|
1109
|
+
label="Customer Tier",
|
|
1110
|
+
type="enumeration",
|
|
1111
|
+
field_type="select",
|
|
1112
|
+
group_name="contactinformation",
|
|
1113
|
+
options=options
|
|
1114
|
+
)
|
|
1115
|
+
|
|
1116
|
+
try:
|
|
1117
|
+
api_response = api_client.crm.properties.core_api.create(
|
|
1118
|
+
object_type="contacts",
|
|
1119
|
+
property_create=property_create
|
|
1120
|
+
)
|
|
1121
|
+
print(f"Dropdown property created: {api_response.name}")
|
|
1122
|
+
return api_response
|
|
1123
|
+
except ApiException as e:
|
|
1124
|
+
print(f"Exception when creating dropdown property: {e}")
|
|
1125
|
+
|
|
1126
|
+
create_dropdown_property()
|
|
1127
|
+
```
|
|
1128
|
+
|
|
1129
|
+
### Update Property
|
|
1130
|
+
|
|
1131
|
+
```python
|
|
1132
|
+
from hubspot.crm.properties import PropertyUpdate, ApiException
|
|
1133
|
+
|
|
1134
|
+
def update_property(property_name):
|
|
1135
|
+
property_update = PropertyUpdate(
|
|
1136
|
+
label="Updated Label",
|
|
1137
|
+
description="Updated description"
|
|
1138
|
+
)
|
|
1139
|
+
|
|
1140
|
+
try:
|
|
1141
|
+
api_response = api_client.crm.properties.core_api.update(
|
|
1142
|
+
object_type="contacts",
|
|
1143
|
+
property_name=property_name,
|
|
1144
|
+
property_update=property_update
|
|
1145
|
+
)
|
|
1146
|
+
print(f"Property updated: {api_response.name}")
|
|
1147
|
+
return api_response
|
|
1148
|
+
except ApiException as e:
|
|
1149
|
+
print(f"Exception when updating property: {e}")
|
|
1150
|
+
|
|
1151
|
+
update_property("favorite_color")
|
|
1152
|
+
```
|
|
1153
|
+
|
|
1154
|
+
## Marketing API - Emails
|
|
1155
|
+
|
|
1156
|
+
### Get All Marketing Emails
|
|
1157
|
+
|
|
1158
|
+
```python
|
|
1159
|
+
from hubspot.marketing.emails import ApiException
|
|
1160
|
+
|
|
1161
|
+
def get_marketing_emails():
|
|
1162
|
+
try:
|
|
1163
|
+
api_response = api_client.marketing.emails.emails_api.get_page()
|
|
1164
|
+
print(f"Found {len(api_response.results)} marketing emails")
|
|
1165
|
+
return api_response
|
|
1166
|
+
except ApiException as e:
|
|
1167
|
+
print(f"Exception when fetching marketing emails: {e}")
|
|
1168
|
+
|
|
1169
|
+
get_marketing_emails()
|
|
1170
|
+
```
|
|
1171
|
+
|
|
1172
|
+
### Get Email by ID
|
|
1173
|
+
|
|
1174
|
+
```python
|
|
1175
|
+
from hubspot.marketing.emails import ApiException
|
|
1176
|
+
|
|
1177
|
+
def get_marketing_email(email_id):
|
|
1178
|
+
try:
|
|
1179
|
+
api_response = api_client.marketing.emails.emails_api.get_by_id(
|
|
1180
|
+
email_id=email_id
|
|
1181
|
+
)
|
|
1182
|
+
print(f"Email: {api_response.name}")
|
|
1183
|
+
return api_response
|
|
1184
|
+
except ApiException as e:
|
|
1185
|
+
print(f"Exception when fetching marketing email: {e}")
|
|
1186
|
+
|
|
1187
|
+
get_marketing_email("12345")
|
|
1188
|
+
```
|
|
1189
|
+
|
|
1190
|
+
## Marketing API - Forms
|
|
1191
|
+
|
|
1192
|
+
### Get All Forms
|
|
1193
|
+
|
|
1194
|
+
```python
|
|
1195
|
+
from hubspot.marketing.forms import ApiException
|
|
1196
|
+
|
|
1197
|
+
def get_all_forms():
|
|
1198
|
+
try:
|
|
1199
|
+
api_response = api_client.marketing.forms.forms_api.get_page()
|
|
1200
|
+
print(f"Found {len(api_response.results)} forms")
|
|
1201
|
+
return api_response
|
|
1202
|
+
except ApiException as e:
|
|
1203
|
+
print(f"Exception when fetching forms: {e}")
|
|
1204
|
+
|
|
1205
|
+
get_all_forms()
|
|
1206
|
+
```
|
|
1207
|
+
|
|
1208
|
+
### Get Form by ID
|
|
1209
|
+
|
|
1210
|
+
```python
|
|
1211
|
+
from hubspot.marketing.forms import ApiException
|
|
1212
|
+
|
|
1213
|
+
def get_form(form_id):
|
|
1214
|
+
try:
|
|
1215
|
+
api_response = api_client.marketing.forms.forms_api.get_by_id(
|
|
1216
|
+
form_id=form_id
|
|
1217
|
+
)
|
|
1218
|
+
print(f"Form: {api_response.name}")
|
|
1219
|
+
return api_response
|
|
1220
|
+
except ApiException as e:
|
|
1221
|
+
print(f"Exception when fetching form: {e}")
|
|
1222
|
+
|
|
1223
|
+
get_form("12345")
|
|
1224
|
+
```
|
|
1225
|
+
|
|
1226
|
+
### Submit Form Data
|
|
1227
|
+
|
|
1228
|
+
```python
|
|
1229
|
+
import requests
|
|
1230
|
+
|
|
1231
|
+
def submit_form_data(form_guid, portal_id):
|
|
1232
|
+
form_data = {
|
|
1233
|
+
"fields": [
|
|
1234
|
+
{
|
|
1235
|
+
"name": "email",
|
|
1236
|
+
"value": "test@example.com"
|
|
1237
|
+
},
|
|
1238
|
+
{
|
|
1239
|
+
"name": "firstname",
|
|
1240
|
+
"value": "John"
|
|
1241
|
+
},
|
|
1242
|
+
{
|
|
1243
|
+
"name": "lastname",
|
|
1244
|
+
"value": "Doe"
|
|
1245
|
+
}
|
|
1246
|
+
],
|
|
1247
|
+
"context": {
|
|
1248
|
+
"pageUri": "https://example.com/contact",
|
|
1249
|
+
"pageName": "Contact Us"
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
try:
|
|
1254
|
+
response = requests.post(
|
|
1255
|
+
f"https://api.hsforms.com/submissions/v3/integration/submit/{portal_id}/{form_guid}",
|
|
1256
|
+
json=form_data
|
|
1257
|
+
)
|
|
1258
|
+
response.raise_for_status()
|
|
1259
|
+
print("Form submitted successfully")
|
|
1260
|
+
return response.json()
|
|
1261
|
+
except requests.exceptions.RequestException as e:
|
|
1262
|
+
print(f"Error submitting form: {e}")
|
|
1263
|
+
|
|
1264
|
+
submit_form_data("form-guid-here", "12345")
|
|
1265
|
+
```
|
|
1266
|
+
|
|
1267
|
+
## Events API - Timeline Events
|
|
1268
|
+
|
|
1269
|
+
### Create Timeline Event
|
|
1270
|
+
|
|
1271
|
+
```python
|
|
1272
|
+
import requests
|
|
1273
|
+
import os
|
|
1274
|
+
|
|
1275
|
+
def create_timeline_event(event_type_id, object_id):
|
|
1276
|
+
event_data = {
|
|
1277
|
+
"eventTypeId": event_type_id,
|
|
1278
|
+
"objectId": object_id,
|
|
1279
|
+
"extraData": {
|
|
1280
|
+
"eventTitle": "Purchase Completed",
|
|
1281
|
+
"eventDescription": "Customer completed a purchase of $99.99"
|
|
1282
|
+
},
|
|
1283
|
+
"timestamp": "2025-11-07T12:00:00Z"
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
headers = {
|
|
1287
|
+
"Authorization": f"Bearer {os.getenv('HUBSPOT_ACCESS_TOKEN')}",
|
|
1288
|
+
"Content-Type": "application/json"
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
try:
|
|
1292
|
+
response = requests.post(
|
|
1293
|
+
"https://api.hubapi.com/crm/v3/timeline/events",
|
|
1294
|
+
json=event_data,
|
|
1295
|
+
headers=headers
|
|
1296
|
+
)
|
|
1297
|
+
response.raise_for_status()
|
|
1298
|
+
print(f"Timeline event created: {response.json()['id']}")
|
|
1299
|
+
return response.json()
|
|
1300
|
+
except requests.exceptions.RequestException as e:
|
|
1301
|
+
print(f"Error creating timeline event: {e}")
|
|
1302
|
+
|
|
1303
|
+
create_timeline_event("event_type_id_here", "12345")
|
|
1304
|
+
```
|
|
1305
|
+
|
|
1306
|
+
## Automation API - Workflows
|
|
1307
|
+
|
|
1308
|
+
### Get All Workflows
|
|
1309
|
+
|
|
1310
|
+
```python
|
|
1311
|
+
import requests
|
|
1312
|
+
import os
|
|
1313
|
+
|
|
1314
|
+
def get_all_workflows():
|
|
1315
|
+
headers = {
|
|
1316
|
+
"Authorization": f"Bearer {os.getenv('HUBSPOT_ACCESS_TOKEN')}"
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
try:
|
|
1320
|
+
response = requests.get(
|
|
1321
|
+
"https://api.hubapi.com/automation/v3/workflows",
|
|
1322
|
+
headers=headers
|
|
1323
|
+
)
|
|
1324
|
+
response.raise_for_status()
|
|
1325
|
+
workflows = response.json()['workflows']
|
|
1326
|
+
print(f"Found {len(workflows)} workflows")
|
|
1327
|
+
return workflows
|
|
1328
|
+
except requests.exceptions.RequestException as e:
|
|
1329
|
+
print(f"Error fetching workflows: {e}")
|
|
1330
|
+
|
|
1331
|
+
get_all_workflows()
|
|
1332
|
+
```
|
|
1333
|
+
|
|
1334
|
+
### Get Workflow by ID
|
|
1335
|
+
|
|
1336
|
+
```python
|
|
1337
|
+
import requests
|
|
1338
|
+
import os
|
|
1339
|
+
|
|
1340
|
+
def get_workflow(workflow_id):
|
|
1341
|
+
headers = {
|
|
1342
|
+
"Authorization": f"Bearer {os.getenv('HUBSPOT_ACCESS_TOKEN')}"
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
try:
|
|
1346
|
+
response = requests.get(
|
|
1347
|
+
f"https://api.hubapi.com/automation/v3/workflows/{workflow_id}",
|
|
1348
|
+
headers=headers
|
|
1349
|
+
)
|
|
1350
|
+
response.raise_for_status()
|
|
1351
|
+
workflow = response.json()
|
|
1352
|
+
print(f"Workflow: {workflow['name']}")
|
|
1353
|
+
return workflow
|
|
1354
|
+
except requests.exceptions.RequestException as e:
|
|
1355
|
+
print(f"Error fetching workflow: {e}")
|
|
1356
|
+
|
|
1357
|
+
get_workflow("12345")
|
|
1358
|
+
```
|
|
1359
|
+
|
|
1360
|
+
### Enroll Contact in Workflow
|
|
1361
|
+
|
|
1362
|
+
```python
|
|
1363
|
+
import requests
|
|
1364
|
+
import os
|
|
1365
|
+
|
|
1366
|
+
def enroll_contact_in_workflow(workflow_id, contact_email):
|
|
1367
|
+
headers = {
|
|
1368
|
+
"Authorization": f"Bearer {os.getenv('HUBSPOT_ACCESS_TOKEN')}",
|
|
1369
|
+
"Content-Type": "application/json"
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
try:
|
|
1373
|
+
response = requests.post(
|
|
1374
|
+
f"https://api.hubapi.com/automation/v2/workflows/{workflow_id}/enrollments/contacts/{contact_email}",
|
|
1375
|
+
headers=headers,
|
|
1376
|
+
json={}
|
|
1377
|
+
)
|
|
1378
|
+
response.raise_for_status()
|
|
1379
|
+
print("Contact enrolled in workflow")
|
|
1380
|
+
return response.json()
|
|
1381
|
+
except requests.exceptions.RequestException as e:
|
|
1382
|
+
print(f"Error enrolling contact in workflow: {e}")
|
|
1383
|
+
|
|
1384
|
+
enroll_contact_in_workflow("12345", "contact@example.com")
|
|
1385
|
+
```
|
|
1386
|
+
|
|
1387
|
+
## Webhooks API
|
|
1388
|
+
|
|
1389
|
+
### Create Webhook Subscription
|
|
1390
|
+
|
|
1391
|
+
```python
|
|
1392
|
+
from hubspot.webhooks import SubscriptionCreateRequest, ApiException
|
|
1393
|
+
|
|
1394
|
+
def create_webhook_subscription(app_id):
|
|
1395
|
+
subscription_create = SubscriptionCreateRequest(
|
|
1396
|
+
event_type="contact.creation",
|
|
1397
|
+
active=True
|
|
1398
|
+
)
|
|
1399
|
+
|
|
1400
|
+
try:
|
|
1401
|
+
api_response = api_client.webhooks.subscriptions_api.create(
|
|
1402
|
+
app_id=app_id,
|
|
1403
|
+
subscription_create_request=subscription_create
|
|
1404
|
+
)
|
|
1405
|
+
print(f"Webhook subscription created: {api_response.id}")
|
|
1406
|
+
return api_response
|
|
1407
|
+
except ApiException as e:
|
|
1408
|
+
print(f"Exception when creating webhook subscription: {e}")
|
|
1409
|
+
|
|
1410
|
+
create_webhook_subscription(12345)
|
|
1411
|
+
```
|
|
1412
|
+
|
|
1413
|
+
### Get All Webhook Subscriptions
|
|
1414
|
+
|
|
1415
|
+
```python
|
|
1416
|
+
from hubspot.webhooks import ApiException
|
|
1417
|
+
|
|
1418
|
+
def get_webhook_subscriptions(app_id):
|
|
1419
|
+
try:
|
|
1420
|
+
api_response = api_client.webhooks.subscriptions_api.get_all(
|
|
1421
|
+
app_id=app_id
|
|
1422
|
+
)
|
|
1423
|
+
print(f"Found {len(api_response.results)} webhook subscriptions")
|
|
1424
|
+
return api_response
|
|
1425
|
+
except ApiException as e:
|
|
1426
|
+
print(f"Exception when fetching webhook subscriptions: {e}")
|
|
1427
|
+
|
|
1428
|
+
get_webhook_subscriptions(12345)
|
|
1429
|
+
```
|
|
1430
|
+
|
|
1431
|
+
### Delete Webhook Subscription
|
|
1432
|
+
|
|
1433
|
+
```python
|
|
1434
|
+
from hubspot.webhooks import ApiException
|
|
1435
|
+
|
|
1436
|
+
def delete_webhook_subscription(app_id, subscription_id):
|
|
1437
|
+
try:
|
|
1438
|
+
api_client.webhooks.subscriptions_api.archive(
|
|
1439
|
+
subscription_id=subscription_id,
|
|
1440
|
+
app_id=app_id
|
|
1441
|
+
)
|
|
1442
|
+
print("Webhook subscription deleted")
|
|
1443
|
+
except ApiException as e:
|
|
1444
|
+
print(f"Exception when deleting webhook subscription: {e}")
|
|
1445
|
+
|
|
1446
|
+
delete_webhook_subscription(12345, 67890)
|
|
1447
|
+
```
|
|
1448
|
+
|
|
1449
|
+
## Lists API
|
|
1450
|
+
|
|
1451
|
+
### Get All Lists
|
|
1452
|
+
|
|
1453
|
+
```python
|
|
1454
|
+
import requests
|
|
1455
|
+
import os
|
|
1456
|
+
|
|
1457
|
+
def get_all_lists():
|
|
1458
|
+
headers = {
|
|
1459
|
+
"Authorization": f"Bearer {os.getenv('HUBSPOT_ACCESS_TOKEN')}"
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
params = {
|
|
1463
|
+
"count": 100,
|
|
1464
|
+
"offset": 0
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
try:
|
|
1468
|
+
response = requests.get(
|
|
1469
|
+
"https://api.hubapi.com/contacts/v1/lists",
|
|
1470
|
+
headers=headers,
|
|
1471
|
+
params=params
|
|
1472
|
+
)
|
|
1473
|
+
response.raise_for_status()
|
|
1474
|
+
lists = response.json()['lists']
|
|
1475
|
+
print(f"Found {len(lists)} lists")
|
|
1476
|
+
return lists
|
|
1477
|
+
except requests.exceptions.RequestException as e:
|
|
1478
|
+
print(f"Error fetching lists: {e}")
|
|
1479
|
+
|
|
1480
|
+
get_all_lists()
|
|
1481
|
+
```
|
|
1482
|
+
|
|
1483
|
+
### Add Contact to List
|
|
1484
|
+
|
|
1485
|
+
```python
|
|
1486
|
+
import requests
|
|
1487
|
+
import os
|
|
1488
|
+
|
|
1489
|
+
def add_contact_to_list(list_id, contact_id):
|
|
1490
|
+
headers = {
|
|
1491
|
+
"Authorization": f"Bearer {os.getenv('HUBSPOT_ACCESS_TOKEN')}",
|
|
1492
|
+
"Content-Type": "application/json"
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
data = {
|
|
1496
|
+
"vids": [contact_id]
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
try:
|
|
1500
|
+
response = requests.post(
|
|
1501
|
+
f"https://api.hubapi.com/contacts/v1/lists/{list_id}/add",
|
|
1502
|
+
headers=headers,
|
|
1503
|
+
json=data
|
|
1504
|
+
)
|
|
1505
|
+
response.raise_for_status()
|
|
1506
|
+
print("Contact added to list")
|
|
1507
|
+
return response.json()
|
|
1508
|
+
except requests.exceptions.RequestException as e:
|
|
1509
|
+
print(f"Error adding contact to list: {e}")
|
|
1510
|
+
|
|
1511
|
+
add_contact_to_list(123, 456)
|
|
1512
|
+
```
|
|
1513
|
+
|
|
1514
|
+
### Remove Contact from List
|
|
1515
|
+
|
|
1516
|
+
```python
|
|
1517
|
+
import requests
|
|
1518
|
+
import os
|
|
1519
|
+
|
|
1520
|
+
def remove_contact_from_list(list_id, contact_id):
|
|
1521
|
+
headers = {
|
|
1522
|
+
"Authorization": f"Bearer {os.getenv('HUBSPOT_ACCESS_TOKEN')}",
|
|
1523
|
+
"Content-Type": "application/json"
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
data = {
|
|
1527
|
+
"vids": [contact_id]
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
try:
|
|
1531
|
+
response = requests.post(
|
|
1532
|
+
f"https://api.hubapi.com/contacts/v1/lists/{list_id}/remove",
|
|
1533
|
+
headers=headers,
|
|
1534
|
+
json=data
|
|
1535
|
+
)
|
|
1536
|
+
response.raise_for_status()
|
|
1537
|
+
print("Contact removed from list")
|
|
1538
|
+
return response.json()
|
|
1539
|
+
except requests.exceptions.RequestException as e:
|
|
1540
|
+
print(f"Error removing contact from list: {e}")
|
|
1541
|
+
|
|
1542
|
+
remove_contact_from_list(123, 456)
|
|
1543
|
+
```
|
|
1544
|
+
|
|
1545
|
+
## Owners API
|
|
1546
|
+
|
|
1547
|
+
### Get All Owners
|
|
1548
|
+
|
|
1549
|
+
```python
|
|
1550
|
+
from hubspot.crm.owners import ApiException
|
|
1551
|
+
|
|
1552
|
+
def get_all_owners():
|
|
1553
|
+
try:
|
|
1554
|
+
api_response = api_client.crm.owners.owners_api.get_page()
|
|
1555
|
+
print(f"Found {len(api_response.results)} owners")
|
|
1556
|
+
return api_response
|
|
1557
|
+
except ApiException as e:
|
|
1558
|
+
print(f"Exception when fetching owners: {e}")
|
|
1559
|
+
|
|
1560
|
+
get_all_owners()
|
|
1561
|
+
```
|
|
1562
|
+
|
|
1563
|
+
### Get Owner by ID
|
|
1564
|
+
|
|
1565
|
+
```python
|
|
1566
|
+
from hubspot.crm.owners import ApiException
|
|
1567
|
+
|
|
1568
|
+
def get_owner(owner_id):
|
|
1569
|
+
try:
|
|
1570
|
+
api_response = api_client.crm.owners.owners_api.get_by_id(
|
|
1571
|
+
owner_id=owner_id
|
|
1572
|
+
)
|
|
1573
|
+
print(f"Owner: {api_response.email}")
|
|
1574
|
+
return api_response
|
|
1575
|
+
except ApiException as e:
|
|
1576
|
+
print(f"Exception when fetching owner: {e}")
|
|
1577
|
+
|
|
1578
|
+
get_owner("12345")
|
|
1579
|
+
```
|
|
1580
|
+
|
|
1581
|
+
## Error Handling
|
|
1582
|
+
|
|
1583
|
+
### Comprehensive Error Handling
|
|
1584
|
+
|
|
1585
|
+
```python
|
|
1586
|
+
from hubspot.crm.contacts import ApiException
|
|
1587
|
+
|
|
1588
|
+
def handle_api_call():
|
|
1589
|
+
try:
|
|
1590
|
+
api_response = api_client.crm.contacts.basic_api.get_by_id(
|
|
1591
|
+
contact_id="12345"
|
|
1592
|
+
)
|
|
1593
|
+
return api_response
|
|
1594
|
+
except ApiException as e:
|
|
1595
|
+
if e.status == 401:
|
|
1596
|
+
print("Authentication failed - check your access token")
|
|
1597
|
+
elif e.status == 404:
|
|
1598
|
+
print("Resource not found")
|
|
1599
|
+
elif e.status == 409:
|
|
1600
|
+
print("Conflict - resource already exists")
|
|
1601
|
+
elif e.status == 429:
|
|
1602
|
+
print("Rate limit exceeded - wait before retrying")
|
|
1603
|
+
elif e.status >= 500:
|
|
1604
|
+
print("HubSpot server error - try again later")
|
|
1605
|
+
else:
|
|
1606
|
+
print(f"API error: {e}")
|
|
1607
|
+
raise
|
|
1608
|
+
|
|
1609
|
+
handle_api_call()
|
|
1610
|
+
```
|
|
1611
|
+
|
|
1612
|
+
### Retry Logic
|
|
1613
|
+
|
|
1614
|
+
```python
|
|
1615
|
+
import time
|
|
1616
|
+
from hubspot.crm.contacts import ApiException
|
|
1617
|
+
|
|
1618
|
+
def api_call_with_retry(api_call, max_retries=3):
|
|
1619
|
+
for attempt in range(1, max_retries + 1):
|
|
1620
|
+
try:
|
|
1621
|
+
return api_call()
|
|
1622
|
+
except ApiException as e:
|
|
1623
|
+
if e.status == 429 and attempt < max_retries:
|
|
1624
|
+
retry_after = int(e.headers.get('Retry-After', 1))
|
|
1625
|
+
print(f"Rate limited. Retrying after {retry_after} seconds...")
|
|
1626
|
+
time.sleep(retry_after)
|
|
1627
|
+
else:
|
|
1628
|
+
raise
|
|
1629
|
+
|
|
1630
|
+
# Usage
|
|
1631
|
+
result = api_call_with_retry(
|
|
1632
|
+
lambda: api_client.crm.contacts.basic_api.get_by_id(contact_id="12345")
|
|
1633
|
+
)
|
|
1634
|
+
```
|
|
1635
|
+
|
|
1636
|
+
## Rate Limits
|
|
1637
|
+
|
|
1638
|
+
HubSpot API has the following rate limits:
|
|
1639
|
+
|
|
1640
|
+
- **Private Apps:** 100 requests per 10 seconds per account
|
|
1641
|
+
- **OAuth Apps:** 100 requests per 10 seconds per app per account
|
|
1642
|
+
- **Search API:** 5 requests per second, 1000 requests per day (per account)
|
|
1643
|
+
- **Batch API:** 100 objects per request, same rate limits as standard endpoints
|
|
1644
|
+
|
|
1645
|
+
Monitor rate limit headers in responses:
|
|
1646
|
+
|
|
1647
|
+
```python
|
|
1648
|
+
from hubspot.crm.contacts import ApiException
|
|
1649
|
+
|
|
1650
|
+
def check_rate_limits():
|
|
1651
|
+
try:
|
|
1652
|
+
api_response = api_client.crm.contacts.basic_api.get_page(limit=1)
|
|
1653
|
+
|
|
1654
|
+
# Rate limit information is in the response headers
|
|
1655
|
+
# These are typically accessed via the underlying HTTP client
|
|
1656
|
+
print("Request successful")
|
|
1657
|
+
return api_response
|
|
1658
|
+
except ApiException as e:
|
|
1659
|
+
if e.status == 429:
|
|
1660
|
+
print("Rate limit exceeded")
|
|
1661
|
+
print(f"Retry after: {e.headers.get('Retry-After')} seconds")
|
|
1662
|
+
|
|
1663
|
+
check_rate_limits()
|
|
1664
|
+
```
|
|
1665
|
+
|
|
1666
|
+
## Pagination
|
|
1667
|
+
|
|
1668
|
+
Most list endpoints return paginated results. Use the `after` parameter for pagination:
|
|
1669
|
+
|
|
1670
|
+
```python
|
|
1671
|
+
from hubspot.crm.contacts import ApiException
|
|
1672
|
+
|
|
1673
|
+
def paginate_through_contacts():
|
|
1674
|
+
after = None
|
|
1675
|
+
all_contacts = []
|
|
1676
|
+
|
|
1677
|
+
while True:
|
|
1678
|
+
try:
|
|
1679
|
+
api_response = api_client.crm.contacts.basic_api.get_page(
|
|
1680
|
+
limit=100,
|
|
1681
|
+
after=after,
|
|
1682
|
+
properties=["email", "firstname", "lastname"]
|
|
1683
|
+
)
|
|
1684
|
+
|
|
1685
|
+
all_contacts.extend(api_response.results)
|
|
1686
|
+
|
|
1687
|
+
if api_response.paging and api_response.paging.next:
|
|
1688
|
+
after = api_response.paging.next.after
|
|
1689
|
+
else:
|
|
1690
|
+
break
|
|
1691
|
+
except ApiException as e:
|
|
1692
|
+
print(f"Exception during pagination: {e}")
|
|
1693
|
+
break
|
|
1694
|
+
|
|
1695
|
+
return all_contacts
|
|
1696
|
+
|
|
1697
|
+
all_contacts = paginate_through_contacts()
|
|
1698
|
+
print(f"Total contacts: {len(all_contacts)}")
|
|
1699
|
+
```
|
|
1700
|
+
|
|
1701
|
+
## OAuth Implementation
|
|
1702
|
+
|
|
1703
|
+
### Initialize OAuth Provider
|
|
1704
|
+
|
|
1705
|
+
```python
|
|
1706
|
+
from hubspot import HubSpot
|
|
1707
|
+
import os
|
|
1708
|
+
|
|
1709
|
+
api_client = HubSpot(
|
|
1710
|
+
access_token=None, # Will be set after OAuth flow
|
|
1711
|
+
client_id=os.getenv('HUBSPOT_CLIENT_ID'),
|
|
1712
|
+
client_secret=os.getenv('HUBSPOT_CLIENT_SECRET'),
|
|
1713
|
+
redirect_uri='https://yourapp.com/oauth-callback'
|
|
1714
|
+
)
|
|
1715
|
+
```
|
|
1716
|
+
|
|
1717
|
+
### Get Authorization URL
|
|
1718
|
+
|
|
1719
|
+
```python
|
|
1720
|
+
import os
|
|
1721
|
+
|
|
1722
|
+
def get_authorization_url():
|
|
1723
|
+
scopes = ['contacts', 'crm.objects.contacts.read']
|
|
1724
|
+
|
|
1725
|
+
auth_url = (
|
|
1726
|
+
f"https://app.hubspot.com/oauth/authorize"
|
|
1727
|
+
f"?client_id={os.getenv('HUBSPOT_CLIENT_ID')}"
|
|
1728
|
+
f"&redirect_uri={os.getenv('REDIRECT_URI')}"
|
|
1729
|
+
f"&scope={' '.join(scopes)}"
|
|
1730
|
+
)
|
|
1731
|
+
|
|
1732
|
+
return auth_url
|
|
1733
|
+
|
|
1734
|
+
print(get_authorization_url())
|
|
1735
|
+
```
|
|
1736
|
+
|
|
1737
|
+
### Exchange Authorization Code for Tokens
|
|
1738
|
+
|
|
1739
|
+
```python
|
|
1740
|
+
from hubspot.auth.oauth import ApiException
|
|
1741
|
+
|
|
1742
|
+
def get_tokens(authorization_code):
|
|
1743
|
+
try:
|
|
1744
|
+
token_response = api_client.auth.oauth.tokens_api.create(
|
|
1745
|
+
grant_type='authorization_code',
|
|
1746
|
+
code=authorization_code,
|
|
1747
|
+
redirect_uri=os.getenv('REDIRECT_URI'),
|
|
1748
|
+
client_id=os.getenv('HUBSPOT_CLIENT_ID'),
|
|
1749
|
+
client_secret=os.getenv('HUBSPOT_CLIENT_SECRET')
|
|
1750
|
+
)
|
|
1751
|
+
|
|
1752
|
+
return {
|
|
1753
|
+
"access_token": token_response.access_token,
|
|
1754
|
+
"refresh_token": token_response.refresh_token,
|
|
1755
|
+
"expires_in": token_response.expires_in
|
|
1756
|
+
}
|
|
1757
|
+
except ApiException as e:
|
|
1758
|
+
print(f"Error exchanging code for tokens: {e}")
|
|
1759
|
+
|
|
1760
|
+
tokens = get_tokens("authorization_code_here")
|
|
1761
|
+
```
|
|
1762
|
+
|
|
1763
|
+
### Refresh Access Token
|
|
1764
|
+
|
|
1765
|
+
```python
|
|
1766
|
+
from hubspot.auth.oauth import ApiException
|
|
1767
|
+
import os
|
|
1768
|
+
|
|
1769
|
+
def refresh_access_token(refresh_token):
|
|
1770
|
+
try:
|
|
1771
|
+
token_response = api_client.auth.oauth.tokens_api.create(
|
|
1772
|
+
grant_type='refresh_token',
|
|
1773
|
+
redirect_uri=None,
|
|
1774
|
+
refresh_token=refresh_token,
|
|
1775
|
+
client_id=os.getenv('HUBSPOT_CLIENT_ID'),
|
|
1776
|
+
client_secret=os.getenv('HUBSPOT_CLIENT_SECRET')
|
|
1777
|
+
)
|
|
1778
|
+
|
|
1779
|
+
return {
|
|
1780
|
+
"access_token": token_response.access_token,
|
|
1781
|
+
"refresh_token": token_response.refresh_token,
|
|
1782
|
+
"expires_in": token_response.expires_in
|
|
1783
|
+
}
|
|
1784
|
+
except ApiException as e:
|
|
1785
|
+
print(f"Error refreshing token: {e}")
|
|
1786
|
+
|
|
1787
|
+
new_tokens = refresh_access_token("refresh_token_here")
|
|
1788
|
+
```
|
|
1789
|
+
|
|
1790
|
+
## Custom Objects
|
|
1791
|
+
|
|
1792
|
+
### Create Custom Object Schema
|
|
1793
|
+
|
|
1794
|
+
```python
|
|
1795
|
+
from hubspot.crm.schemas import ObjectSchemaEgg, ObjectTypePropertyCreate, ApiException
|
|
1796
|
+
|
|
1797
|
+
def create_custom_object_schema():
|
|
1798
|
+
properties = [
|
|
1799
|
+
ObjectTypePropertyCreate(
|
|
1800
|
+
name="model",
|
|
1801
|
+
label="Model",
|
|
1802
|
+
type="string",
|
|
1803
|
+
field_type="text"
|
|
1804
|
+
),
|
|
1805
|
+
ObjectTypePropertyCreate(
|
|
1806
|
+
name="make",
|
|
1807
|
+
label="Make",
|
|
1808
|
+
type="string",
|
|
1809
|
+
field_type="text"
|
|
1810
|
+
),
|
|
1811
|
+
ObjectTypePropertyCreate(
|
|
1812
|
+
name="year",
|
|
1813
|
+
label="Year",
|
|
1814
|
+
type="number",
|
|
1815
|
+
field_type="number"
|
|
1816
|
+
)
|
|
1817
|
+
]
|
|
1818
|
+
|
|
1819
|
+
schema_egg = ObjectSchemaEgg(
|
|
1820
|
+
name="cars",
|
|
1821
|
+
labels={
|
|
1822
|
+
"singular": "Car",
|
|
1823
|
+
"plural": "Cars"
|
|
1824
|
+
},
|
|
1825
|
+
primary_display_property="model",
|
|
1826
|
+
required_properties=["model", "make"],
|
|
1827
|
+
searchable_properties=["model", "make", "year"],
|
|
1828
|
+
properties=properties
|
|
1829
|
+
)
|
|
1830
|
+
|
|
1831
|
+
try:
|
|
1832
|
+
api_response = api_client.crm.schemas.core_api.create(
|
|
1833
|
+
object_schema_egg=schema_egg
|
|
1834
|
+
)
|
|
1835
|
+
print(f"Custom object schema created: {api_response.name}")
|
|
1836
|
+
return api_response
|
|
1837
|
+
except ApiException as e:
|
|
1838
|
+
print(f"Exception when creating custom object schema: {e}")
|
|
1839
|
+
|
|
1840
|
+
create_custom_object_schema()
|
|
1841
|
+
```
|
|
1842
|
+
|
|
1843
|
+
### Create Custom Object Instance
|
|
1844
|
+
|
|
1845
|
+
```python
|
|
1846
|
+
from hubspot.crm.objects import SimplePublicObjectInputForCreate, ApiException
|
|
1847
|
+
|
|
1848
|
+
def create_custom_object(object_type):
|
|
1849
|
+
object_data = SimplePublicObjectInputForCreate(
|
|
1850
|
+
properties={
|
|
1851
|
+
"model": "Model 3",
|
|
1852
|
+
"make": "Tesla",
|
|
1853
|
+
"year": "2024"
|
|
1854
|
+
}
|
|
1855
|
+
)
|
|
1856
|
+
|
|
1857
|
+
try:
|
|
1858
|
+
api_response = api_client.crm.objects.basic_api.create(
|
|
1859
|
+
object_type=object_type,
|
|
1860
|
+
simple_public_object_input_for_create=object_data
|
|
1861
|
+
)
|
|
1862
|
+
print(f"Custom object created: {api_response.id}")
|
|
1863
|
+
return api_response
|
|
1864
|
+
except ApiException as e:
|
|
1865
|
+
print(f"Exception when creating custom object: {e}")
|
|
1866
|
+
|
|
1867
|
+
create_custom_object("cars")
|
|
1868
|
+
```
|
|
1869
|
+
|
|
1870
|
+
## Complete Example Application
|
|
1871
|
+
|
|
1872
|
+
Here's a complete example that demonstrates multiple API operations:
|
|
1873
|
+
|
|
1874
|
+
```python
|
|
1875
|
+
from hubspot import HubSpot
|
|
1876
|
+
from hubspot.crm.contacts import SimplePublicObjectInputForCreate, PublicObjectSearchRequest
|
|
1877
|
+
from hubspot.crm.companies import SimplePublicObjectInputForCreate as CompanyInput
|
|
1878
|
+
from hubspot.crm.deals import SimplePublicObjectInputForCreate as DealInput
|
|
1879
|
+
from hubspot.crm.contacts import ApiException
|
|
1880
|
+
import os
|
|
1881
|
+
from dotenv import load_dotenv
|
|
1882
|
+
|
|
1883
|
+
load_dotenv()
|
|
1884
|
+
|
|
1885
|
+
api_client = HubSpot(access_token=os.getenv('HUBSPOT_ACCESS_TOKEN'))
|
|
1886
|
+
|
|
1887
|
+
def main():
|
|
1888
|
+
try:
|
|
1889
|
+
# Create a contact
|
|
1890
|
+
print("Creating contact...")
|
|
1891
|
+
new_contact = api_client.crm.contacts.basic_api.create(
|
|
1892
|
+
simple_public_object_input_for_create=SimplePublicObjectInputForCreate(
|
|
1893
|
+
properties={
|
|
1894
|
+
"email": "john.doe@example.com",
|
|
1895
|
+
"firstname": "John",
|
|
1896
|
+
"lastname": "Doe",
|
|
1897
|
+
"phone": "555-0100",
|
|
1898
|
+
"company": "Example Corp"
|
|
1899
|
+
}
|
|
1900
|
+
)
|
|
1901
|
+
)
|
|
1902
|
+
print(f"Contact created with ID: {new_contact.id}")
|
|
1903
|
+
|
|
1904
|
+
# Create a company
|
|
1905
|
+
print("\nCreating company...")
|
|
1906
|
+
new_company = api_client.crm.companies.basic_api.create(
|
|
1907
|
+
simple_public_object_input_for_create=CompanyInput(
|
|
1908
|
+
properties={
|
|
1909
|
+
"name": "Example Corp",
|
|
1910
|
+
"domain": "example.com",
|
|
1911
|
+
"city": "San Francisco",
|
|
1912
|
+
"industry": "Technology"
|
|
1913
|
+
}
|
|
1914
|
+
)
|
|
1915
|
+
)
|
|
1916
|
+
print(f"Company created with ID: {new_company.id}")
|
|
1917
|
+
|
|
1918
|
+
# Associate contact with company
|
|
1919
|
+
print("\nAssociating contact with company...")
|
|
1920
|
+
api_client.crm.contacts.associations_api.create(
|
|
1921
|
+
contact_id=new_contact.id,
|
|
1922
|
+
to_object_type="companies",
|
|
1923
|
+
to_object_id=new_company.id,
|
|
1924
|
+
association_type="contact_to_company"
|
|
1925
|
+
)
|
|
1926
|
+
print("Association created successfully")
|
|
1927
|
+
|
|
1928
|
+
# Create a deal
|
|
1929
|
+
print("\nCreating deal...")
|
|
1930
|
+
new_deal = api_client.crm.deals.basic_api.create(
|
|
1931
|
+
simple_public_object_input_for_create=DealInput(
|
|
1932
|
+
properties={
|
|
1933
|
+
"dealname": "Example Deal",
|
|
1934
|
+
"dealstage": "appointmentscheduled",
|
|
1935
|
+
"amount": "10000",
|
|
1936
|
+
"closedate": "2025-12-31"
|
|
1937
|
+
}
|
|
1938
|
+
)
|
|
1939
|
+
)
|
|
1940
|
+
print(f"Deal created with ID: {new_deal.id}")
|
|
1941
|
+
|
|
1942
|
+
# Associate deal with contact
|
|
1943
|
+
print("\nAssociating deal with contact...")
|
|
1944
|
+
api_client.crm.deals.associations_api.create(
|
|
1945
|
+
deal_id=new_deal.id,
|
|
1946
|
+
to_object_type="contacts",
|
|
1947
|
+
to_object_id=new_contact.id,
|
|
1948
|
+
association_type="deal_to_contact"
|
|
1949
|
+
)
|
|
1950
|
+
print("Deal associated with contact")
|
|
1951
|
+
|
|
1952
|
+
# Search for contacts
|
|
1953
|
+
print("\nSearching for leads...")
|
|
1954
|
+
search_results = api_client.crm.contacts.search_api.do_search(
|
|
1955
|
+
public_object_search_request=PublicObjectSearchRequest(
|
|
1956
|
+
filter_groups=[
|
|
1957
|
+
{
|
|
1958
|
+
"filters": [
|
|
1959
|
+
{
|
|
1960
|
+
"propertyName": "email",
|
|
1961
|
+
"operator": "CONTAINS_TOKEN",
|
|
1962
|
+
"value": "example.com"
|
|
1963
|
+
}
|
|
1964
|
+
]
|
|
1965
|
+
}
|
|
1966
|
+
],
|
|
1967
|
+
properties=["email", "firstname", "lastname", "company"],
|
|
1968
|
+
limit=10
|
|
1969
|
+
)
|
|
1970
|
+
)
|
|
1971
|
+
print(f"Found {search_results.total} contacts")
|
|
1972
|
+
|
|
1973
|
+
# List all owners
|
|
1974
|
+
print("\nFetching owners...")
|
|
1975
|
+
owners = api_client.crm.owners.owners_api.get_page()
|
|
1976
|
+
print(f"Found {len(owners.results)} owners")
|
|
1977
|
+
|
|
1978
|
+
print("\nAll operations completed successfully!")
|
|
1979
|
+
|
|
1980
|
+
except ApiException as e:
|
|
1981
|
+
print(f"Error: {e}")
|
|
1982
|
+
|
|
1983
|
+
if __name__ == "__main__":
|
|
1984
|
+
main()
|
|
1985
|
+
```
|
|
1986
|
+
|
|
1987
|
+
## Environment Variables Template
|
|
1988
|
+
|
|
1989
|
+
```bash
|
|
1990
|
+
# .env file
|
|
1991
|
+
HUBSPOT_ACCESS_TOKEN=your_private_app_access_token
|
|
1992
|
+
HUBSPOT_CLIENT_ID=your_client_id
|
|
1993
|
+
HUBSPOT_CLIENT_SECRET=your_client_secret
|
|
1994
|
+
REDIRECT_URI=https://yourapp.com/oauth-callback
|
|
1995
|
+
```
|
|
1996
|
+
|
|
1997
|
+
## API Scopes
|
|
1998
|
+
|
|
1999
|
+
When creating a private app or OAuth app, configure the following scopes based on your needs:
|
|
2000
|
+
|
|
2001
|
+
**CRM:**
|
|
2002
|
+
- `crm.objects.contacts.read` / `crm.objects.contacts.write`
|
|
2003
|
+
- `crm.objects.companies.read` / `crm.objects.companies.write`
|
|
2004
|
+
- `crm.objects.deals.read` / `crm.objects.deals.write`
|
|
2005
|
+
- `crm.objects.owners.read`
|
|
2006
|
+
- `crm.schemas.contacts.read` / `crm.schemas.contacts.write`
|
|
2007
|
+
|
|
2008
|
+
**Marketing:**
|
|
2009
|
+
- `forms` - Read and write forms
|
|
2010
|
+
- `content` - Read and write marketing emails
|
|
2011
|
+
|
|
2012
|
+
**Automation:**
|
|
2013
|
+
- `automation` - Access to workflows
|
|
2014
|
+
|
|
2015
|
+
**Timeline:**
|
|
2016
|
+
- `timeline` - Create timeline events
|
|
2017
|
+
|
|
2018
|
+
## Migration from Legacy API Keys
|
|
2019
|
+
|
|
2020
|
+
If you're using legacy API keys (deprecated), migrate to private apps:
|
|
2021
|
+
|
|
2022
|
+
**Old (Deprecated):**
|
|
2023
|
+
```python
|
|
2024
|
+
# DON'T USE THIS - hapikey is no longer supported
|
|
2025
|
+
api_client = HubSpot(api_key='your-api-key') # Removed after v5.1.0
|
|
2026
|
+
```
|
|
2027
|
+
|
|
2028
|
+
**New (Correct):**
|
|
2029
|
+
```python
|
|
2030
|
+
api_client = HubSpot(access_token=os.getenv('HUBSPOT_ACCESS_TOKEN'))
|
|
2031
|
+
```
|
|
2032
|
+
|
|
2033
|
+
Legacy API keys will be revoked on November 19, 2025.
|