chub-dev 0.1.0 → 0.1.2-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/README.md +55 -0
  2. package/bin/chub-mcp +2 -0
  3. package/dist/airtable/docs/database/javascript/DOC.md +1437 -0
  4. package/dist/airtable/docs/database/python/DOC.md +1735 -0
  5. package/dist/amplitude/docs/analytics/javascript/DOC.md +1282 -0
  6. package/dist/amplitude/docs/analytics/python/DOC.md +1199 -0
  7. package/dist/anthropic/docs/claude-api/javascript/DOC.md +503 -0
  8. package/dist/anthropic/docs/claude-api/python/DOC.md +389 -0
  9. package/dist/asana/docs/tasks/DOC.md +1396 -0
  10. package/dist/assemblyai/docs/transcription/DOC.md +1043 -0
  11. package/dist/atlassian/docs/confluence/javascript/DOC.md +1347 -0
  12. package/dist/atlassian/docs/confluence/python/DOC.md +1604 -0
  13. package/dist/auth0/docs/identity/javascript/DOC.md +968 -0
  14. package/dist/auth0/docs/identity/python/DOC.md +1199 -0
  15. package/dist/aws/docs/s3/javascript/DOC.md +1773 -0
  16. package/dist/aws/docs/s3/python/DOC.md +1807 -0
  17. package/dist/binance/docs/trading/javascript/DOC.md +1315 -0
  18. package/dist/binance/docs/trading/python/DOC.md +1454 -0
  19. package/dist/braintree/docs/gateway/javascript/DOC.md +1278 -0
  20. package/dist/braintree/docs/gateway/python/DOC.md +1179 -0
  21. package/dist/chromadb/docs/embeddings-db/javascript/DOC.md +1263 -0
  22. package/dist/chromadb/docs/embeddings-db/python/DOC.md +1707 -0
  23. package/dist/clerk/docs/auth/javascript/DOC.md +1220 -0
  24. package/dist/clerk/docs/auth/python/DOC.md +274 -0
  25. package/dist/cloudflare/docs/workers/javascript/DOC.md +918 -0
  26. package/dist/cloudflare/docs/workers/python/DOC.md +994 -0
  27. package/dist/cockroachdb/docs/distributed-db/DOC.md +1500 -0
  28. package/dist/cohere/docs/llm/DOC.md +1335 -0
  29. package/dist/datadog/docs/monitoring/javascript/DOC.md +1740 -0
  30. package/dist/datadog/docs/monitoring/python/DOC.md +1815 -0
  31. package/dist/deepgram/docs/speech/javascript/DOC.md +885 -0
  32. package/dist/deepgram/docs/speech/python/DOC.md +685 -0
  33. package/dist/deepl/docs/translation/javascript/DOC.md +887 -0
  34. package/dist/deepl/docs/translation/python/DOC.md +944 -0
  35. package/dist/deepseek/docs/llm/DOC.md +1220 -0
  36. package/dist/directus/docs/headless-cms/javascript/DOC.md +1128 -0
  37. package/dist/directus/docs/headless-cms/python/DOC.md +1276 -0
  38. package/dist/discord/docs/bot/javascript/DOC.md +1090 -0
  39. package/dist/discord/docs/bot/python/DOC.md +1130 -0
  40. package/dist/elasticsearch/docs/search/DOC.md +1634 -0
  41. package/dist/elevenlabs/docs/text-to-speech/javascript/DOC.md +336 -0
  42. package/dist/elevenlabs/docs/text-to-speech/python/DOC.md +552 -0
  43. package/dist/firebase/docs/auth/DOC.md +1015 -0
  44. package/dist/gemini/docs/genai/javascript/DOC.md +691 -0
  45. package/dist/gemini/docs/genai/python/DOC.md +555 -0
  46. package/dist/github/docs/octokit/DOC.md +1560 -0
  47. package/dist/google/docs/bigquery/javascript/DOC.md +1688 -0
  48. package/dist/google/docs/bigquery/python/DOC.md +1503 -0
  49. package/dist/hubspot/docs/crm/javascript/DOC.md +1805 -0
  50. package/dist/hubspot/docs/crm/python/DOC.md +2033 -0
  51. package/dist/huggingface/docs/transformers/DOC.md +948 -0
  52. package/dist/intercom/docs/messaging/javascript/DOC.md +1844 -0
  53. package/dist/intercom/docs/messaging/python/DOC.md +1797 -0
  54. package/dist/jira/docs/issues/javascript/DOC.md +1420 -0
  55. package/dist/jira/docs/issues/python/DOC.md +1492 -0
  56. package/dist/kafka/docs/streaming/javascript/DOC.md +1671 -0
  57. package/dist/kafka/docs/streaming/python/DOC.md +1464 -0
  58. package/dist/landingai-ade/docs/api/DOC.md +620 -0
  59. package/dist/landingai-ade/docs/sdk/python/DOC.md +489 -0
  60. package/dist/landingai-ade/docs/sdk/typescript/DOC.md +542 -0
  61. package/dist/landingai-ade/skills/SKILL.md +489 -0
  62. package/dist/launchdarkly/docs/feature-flags/javascript/DOC.md +1191 -0
  63. package/dist/launchdarkly/docs/feature-flags/python/DOC.md +1671 -0
  64. package/dist/linear/docs/tracker/DOC.md +1554 -0
  65. package/dist/livekit/docs/realtime/javascript/DOC.md +303 -0
  66. package/dist/livekit/docs/realtime/python/DOC.md +163 -0
  67. package/dist/mailchimp/docs/marketing/DOC.md +1420 -0
  68. package/dist/meilisearch/docs/search/DOC.md +1241 -0
  69. package/dist/microsoft/docs/onedrive/javascript/DOC.md +1421 -0
  70. package/dist/microsoft/docs/onedrive/python/DOC.md +1549 -0
  71. package/dist/mongodb/docs/atlas/DOC.md +2041 -0
  72. package/dist/notion/docs/workspace-api/javascript/DOC.md +1435 -0
  73. package/dist/notion/docs/workspace-api/python/DOC.md +1400 -0
  74. package/dist/okta/docs/identity/javascript/DOC.md +1171 -0
  75. package/dist/okta/docs/identity/python/DOC.md +1401 -0
  76. package/dist/openai/docs/chat/javascript/DOC.md +407 -0
  77. package/dist/openai/docs/chat/python/DOC.md +568 -0
  78. package/dist/paypal/docs/checkout/DOC.md +278 -0
  79. package/dist/pinecone/docs/sdk/javascript/DOC.md +984 -0
  80. package/dist/pinecone/docs/sdk/python/DOC.md +1395 -0
  81. package/dist/plaid/docs/banking/javascript/DOC.md +1163 -0
  82. package/dist/plaid/docs/banking/python/DOC.md +1203 -0
  83. package/dist/playwright-community/skills/login-flows/SKILL.md +108 -0
  84. package/dist/postmark/docs/transactional-email/DOC.md +1168 -0
  85. package/dist/prisma/docs/orm/javascript/DOC.md +1419 -0
  86. package/dist/prisma/docs/orm/python/DOC.md +1317 -0
  87. package/dist/qdrant/docs/vector-search/javascript/DOC.md +1221 -0
  88. package/dist/qdrant/docs/vector-search/python/DOC.md +1653 -0
  89. package/dist/rabbitmq/docs/message-queue/javascript/DOC.md +1193 -0
  90. package/dist/rabbitmq/docs/message-queue/python/DOC.md +1243 -0
  91. package/dist/razorpay/docs/payments/javascript/DOC.md +1219 -0
  92. package/dist/razorpay/docs/payments/python/DOC.md +1330 -0
  93. package/dist/redis/docs/key-value/javascript/DOC.md +1851 -0
  94. package/dist/redis/docs/key-value/python/DOC.md +2054 -0
  95. package/dist/registry.json +2817 -0
  96. package/dist/replicate/docs/model-hosting/DOC.md +1318 -0
  97. package/dist/resend/docs/email/DOC.md +1271 -0
  98. package/dist/salesforce/docs/crm/javascript/DOC.md +1241 -0
  99. package/dist/salesforce/docs/crm/python/DOC.md +1183 -0
  100. package/dist/search-index.json +1 -0
  101. package/dist/sendgrid/docs/email-api/javascript/DOC.md +371 -0
  102. package/dist/sendgrid/docs/email-api/python/DOC.md +656 -0
  103. package/dist/sentry/docs/error-tracking/javascript/DOC.md +1073 -0
  104. package/dist/sentry/docs/error-tracking/python/DOC.md +1309 -0
  105. package/dist/shopify/docs/storefront/DOC.md +457 -0
  106. package/dist/slack/docs/workspace/javascript/DOC.md +933 -0
  107. package/dist/slack/docs/workspace/python/DOC.md +271 -0
  108. package/dist/square/docs/payments/javascript/DOC.md +1855 -0
  109. package/dist/square/docs/payments/python/DOC.md +1728 -0
  110. package/dist/stripe/docs/api/DOC.md +1727 -0
  111. package/dist/stripe/docs/payments/DOC.md +1726 -0
  112. package/dist/stytch/docs/auth/javascript/DOC.md +1813 -0
  113. package/dist/stytch/docs/auth/python/DOC.md +1962 -0
  114. package/dist/supabase/docs/client/DOC.md +1606 -0
  115. package/dist/twilio/docs/messaging/python/DOC.md +469 -0
  116. package/dist/twilio/docs/messaging/typescript/DOC.md +946 -0
  117. package/dist/vercel/docs/platform/DOC.md +1940 -0
  118. package/dist/weaviate/docs/vector-db/javascript/DOC.md +1268 -0
  119. package/dist/weaviate/docs/vector-db/python/DOC.md +1388 -0
  120. package/dist/zendesk/docs/support/javascript/DOC.md +2150 -0
  121. package/dist/zendesk/docs/support/python/DOC.md +2297 -0
  122. package/package.json +22 -6
  123. package/skills/get-api-docs/SKILL.md +84 -0
  124. package/src/commands/annotate.js +83 -0
  125. package/src/commands/build.js +12 -1
  126. package/src/commands/feedback.js +150 -0
  127. package/src/commands/get.js +83 -42
  128. package/src/commands/search.js +7 -0
  129. package/src/index.js +43 -17
  130. package/src/lib/analytics.js +90 -0
  131. package/src/lib/annotations.js +57 -0
  132. package/src/lib/bm25.js +170 -0
  133. package/src/lib/cache.js +69 -6
  134. package/src/lib/config.js +8 -3
  135. package/src/lib/identity.js +99 -0
  136. package/src/lib/registry.js +103 -20
  137. package/src/lib/telemetry.js +86 -0
  138. package/src/mcp/server.js +177 -0
  139. package/src/mcp/tools.js +251 -0
@@ -0,0 +1,1797 @@
1
+ ---
2
+ name: messaging
3
+ description: "Intercom Python SDK for customer messaging and chat support"
4
+ metadata:
5
+ languages: "python"
6
+ versions: "4.0.0"
7
+ updated-on: "2026-03-02"
8
+ source: maintainer
9
+ tags: "intercom,messaging,customer,chat,support"
10
+ ---
11
+
12
+ # Intercom Python SDK (v4.0.0)
13
+
14
+ ## Golden Rule
15
+
16
+ **ALWAYS use `python-intercom` version 4.0.0 or later.**
17
+
18
+ ```bash
19
+ pip install python-intercom
20
+ ```
21
+
22
+ **DO NOT use these deprecated or unofficial packages:**
23
+ - `intercom-python-2` (community fork)
24
+ - Old versions of `python-intercom` < 4.0.0 (different API structure)
25
+
26
+ The official Intercom Python SDK is `python-intercom`, maintained by Intercom at https://github.com/intercom/python-intercom
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ pip install python-intercom
32
+ ```
33
+
34
+ For Poetry projects:
35
+
36
+ ```bash
37
+ poetry add python-intercom
38
+ ```
39
+
40
+ **Environment Setup:**
41
+
42
+ ```bash
43
+ # .env file
44
+ INTERCOM_ACCESS_TOKEN=your_access_token_here
45
+ ```
46
+
47
+ **Loading environment variables:**
48
+
49
+ ```python
50
+ import os
51
+ from dotenv import load_dotenv
52
+
53
+ load_dotenv()
54
+
55
+ token = os.getenv('INTERCOM_ACCESS_TOKEN')
56
+ ```
57
+
58
+ ## Initialization
59
+
60
+ **Basic Client Setup:**
61
+
62
+ ```python
63
+ from intercom import Intercom
64
+
65
+ client = Intercom(
66
+ token=os.getenv('INTERCOM_ACCESS_TOKEN')
67
+ )
68
+ ```
69
+
70
+ **With custom configuration:**
71
+
72
+ ```python
73
+ from intercom import Intercom
74
+
75
+ client = Intercom(
76
+ token=os.getenv('INTERCOM_ACCESS_TOKEN'),
77
+ timeout=120, # Default is 60 seconds
78
+ max_retries=3, # Default is 2
79
+ )
80
+ ```
81
+
82
+ **Async Client:**
83
+
84
+ ```python
85
+ from intercom import AsyncIntercom
86
+ import asyncio
87
+
88
+ async def main():
89
+ client = AsyncIntercom(
90
+ token=os.getenv('INTERCOM_ACCESS_TOKEN')
91
+ )
92
+
93
+ contact = await client.contacts.find(id='65f9a5e4f5e5b40001234567')
94
+ print(contact.email)
95
+
96
+ asyncio.run(main())
97
+ ```
98
+
99
+ **API Version Selection:**
100
+
101
+ ```python
102
+ client = Intercom(
103
+ token=os.getenv('INTERCOM_ACCESS_TOKEN'),
104
+ api_version='2.11', # Default is latest stable
105
+ )
106
+ ```
107
+
108
+ ## Core API Surfaces
109
+
110
+ ### Contacts
111
+
112
+ Contacts represent users, leads, and visitors in Intercom. They are the primary entities for customer communication.
113
+
114
+ **Create a contact:**
115
+
116
+ ```python
117
+ contact = client.contacts.create(
118
+ email='[email protected]',
119
+ name='John Doe',
120
+ phone='+1234567890',
121
+ role='user', # 'user' or 'lead'
122
+ )
123
+
124
+ print(contact.id)
125
+ ```
126
+
127
+ **Create with custom attributes:**
128
+
129
+ ```python
130
+ contact = client.contacts.create(
131
+ email='[email protected]',
132
+ name='Jane Smith',
133
+ role='user',
134
+ custom_attributes={
135
+ 'plan': 'premium',
136
+ 'signup_date': '2025-01-15',
137
+ 'total_spend': 599.99,
138
+ 'active': True,
139
+ }
140
+ )
141
+ ```
142
+
143
+ **Retrieve a contact:**
144
+
145
+ ```python
146
+ contact = client.contacts.find(id='65f9a5e4f5e5b40001234567')
147
+
148
+ print(contact.email, contact.name)
149
+ ```
150
+
151
+ **Update a contact:**
152
+
153
+ ```python
154
+ updated = client.contacts.update(
155
+ id='65f9a5e4f5e5b40001234567',
156
+ name='John Updated',
157
+ custom_attributes={
158
+ 'plan': 'enterprise',
159
+ }
160
+ )
161
+ ```
162
+
163
+ **Search contacts:**
164
+
165
+ ```python
166
+ results = client.contacts.search(
167
+ query={
168
+ 'field': 'email',
169
+ 'operator': '=',
170
+ 'value': '[email protected]',
171
+ }
172
+ )
173
+
174
+ for contact in results.data:
175
+ print(contact.name, contact.email)
176
+ ```
177
+
178
+ **Search with filters:**
179
+
180
+ ```python
181
+ results = client.contacts.search(
182
+ query={
183
+ 'operator': 'AND',
184
+ 'value': [
185
+ {
186
+ 'field': 'role',
187
+ 'operator': '=',
188
+ 'value': 'user',
189
+ },
190
+ {
191
+ 'field': 'created_at',
192
+ 'operator': '>',
193
+ 'value': 1704067200, # Unix timestamp
194
+ },
195
+ ],
196
+ },
197
+ pagination={
198
+ 'per_page': 50,
199
+ }
200
+ )
201
+ ```
202
+
203
+ **List all contacts:**
204
+
205
+ ```python
206
+ response = client.contacts.list(per_page=150)
207
+
208
+ # Iterate through paginated results
209
+ for contact in response:
210
+ print(contact.email)
211
+ ```
212
+
213
+ **Delete a contact:**
214
+
215
+ ```python
216
+ client.contacts.delete(id='65f9a5e4f5e5b40001234567')
217
+ ```
218
+
219
+ **Archive a contact:**
220
+
221
+ ```python
222
+ archived = client.contacts.archive(id='65f9a5e4f5e5b40001234567')
223
+ ```
224
+
225
+ **Unarchive a contact:**
226
+
227
+ ```python
228
+ unarchived = client.contacts.unarchive(id='65f9a5e4f5e5b40001234567')
229
+ ```
230
+
231
+ **Merge contacts:**
232
+
233
+ ```python
234
+ merged = client.contacts.merge(
235
+ from_='65f9a5e4f5e5b40001234567',
236
+ into='65f9a5e4f5e5b40009876543'
237
+ )
238
+ ```
239
+
240
+ ### Companies
241
+
242
+ Companies group contacts together by organization. They're useful for B2B use cases.
243
+
244
+ **Create a company:**
245
+
246
+ ```python
247
+ company = client.companies.create(
248
+ company_id='company_123',
249
+ name='Acme Corporation',
250
+ website='https://acme.com',
251
+ industry='Technology',
252
+ size=500,
253
+ custom_attributes={
254
+ 'plan_level': 'enterprise',
255
+ 'mrr': 50000,
256
+ }
257
+ )
258
+ ```
259
+
260
+ **Retrieve a company:**
261
+
262
+ ```python
263
+ company = client.companies.find(company_id='company_123')
264
+ ```
265
+
266
+ **Update a company:**
267
+
268
+ ```python
269
+ updated = client.companies.update(
270
+ company_id='company_123',
271
+ name='Acme Corp',
272
+ size=600,
273
+ custom_attributes={
274
+ 'mrr': 60000,
275
+ }
276
+ )
277
+ ```
278
+
279
+ **List companies:**
280
+
281
+ ```python
282
+ response = client.companies.list(per_page=50)
283
+
284
+ for company in response:
285
+ print(company.name, company.company_id)
286
+ ```
287
+
288
+ **Attach contact to company:**
289
+
290
+ ```python
291
+ client.contacts.update(
292
+ id='65f9a5e4f5e5b40001234567',
293
+ companies=[
294
+ {
295
+ 'company_id': 'company_123',
296
+ }
297
+ ]
298
+ )
299
+ ```
300
+
301
+ **List company contacts:**
302
+
303
+ ```python
304
+ contacts = client.companies.list_contacts(company_id='company_123')
305
+
306
+ for contact in contacts:
307
+ print(contact.email)
308
+ ```
309
+
310
+ **Delete a company:**
311
+
312
+ ```python
313
+ client.companies.delete(company_id='company_123')
314
+ ```
315
+
316
+ ### Conversations
317
+
318
+ Conversations are threads of communication between contacts and your team.
319
+
320
+ **Create a conversation:**
321
+
322
+ ```python
323
+ conversation = client.conversations.create(
324
+ from_={
325
+ 'type': 'user',
326
+ 'id': '65f9a5e4f5e5b40001234567',
327
+ },
328
+ body='Hello, I need help with my account.'
329
+ )
330
+
331
+ print(conversation.id)
332
+ ```
333
+
334
+ **Create conversation with user:**
335
+
336
+ ```python
337
+ conversation = client.conversations.create_conversation(
338
+ user_id='65f9a5e4f5e5b40001234567',
339
+ body='I have a question about billing.'
340
+ )
341
+ ```
342
+
343
+ **Retrieve a conversation:**
344
+
345
+ ```python
346
+ conversation = client.conversations.find(id='123456')
347
+
348
+ print(conversation.state) # 'open', 'closed', 'snoozed'
349
+ ```
350
+
351
+ **Reply to conversation as admin:**
352
+
353
+ ```python
354
+ reply = client.conversations.reply(
355
+ id='123456',
356
+ message_type='comment',
357
+ type='admin',
358
+ admin_id='987654',
359
+ body='Thanks for reaching out! How can I help?'
360
+ )
361
+ ```
362
+
363
+ **Reply with attachment:**
364
+
365
+ ```python
366
+ reply = client.conversations.reply(
367
+ id='123456',
368
+ message_type='comment',
369
+ type='admin',
370
+ admin_id='987654',
371
+ body='Here is the document you requested.',
372
+ attachment_urls=[
373
+ 'https://example.com/document.pdf',
374
+ ]
375
+ )
376
+ ```
377
+
378
+ **Reply as user:**
379
+
380
+ ```python
381
+ reply = client.conversations.reply(
382
+ id='123456',
383
+ message_type='comment',
384
+ type='user',
385
+ user_id='65f9a5e4f5e5b40001234567',
386
+ body='Thank you for your help!'
387
+ )
388
+ ```
389
+
390
+ **Search conversations:**
391
+
392
+ ```python
393
+ results = client.conversations.search(
394
+ query={
395
+ 'field': 'state',
396
+ 'operator': '=',
397
+ 'value': 'open',
398
+ },
399
+ pagination={
400
+ 'per_page': 50,
401
+ }
402
+ )
403
+
404
+ for conv in results.conversations:
405
+ print(conv.id, conv.created_at)
406
+ ```
407
+
408
+ **Search with multiple filters:**
409
+
410
+ ```python
411
+ results = client.conversations.search(
412
+ query={
413
+ 'operator': 'AND',
414
+ 'value': [
415
+ {
416
+ 'field': 'state',
417
+ 'operator': '=',
418
+ 'value': 'open',
419
+ },
420
+ {
421
+ 'field': 'updated_at',
422
+ 'operator': '>',
423
+ 'value': 1704067200,
424
+ },
425
+ ],
426
+ },
427
+ sort={
428
+ 'field': 'updated_at',
429
+ 'order': 'descending',
430
+ }
431
+ )
432
+ ```
433
+
434
+ **List conversations:**
435
+
436
+ ```python
437
+ response = client.conversations.list()
438
+
439
+ for conversation in response:
440
+ print(conversation.id, conversation.state)
441
+ ```
442
+
443
+ **Close a conversation:**
444
+
445
+ ```python
446
+ closed = client.conversations.close(
447
+ id='123456',
448
+ type='admin',
449
+ admin_id='987654'
450
+ )
451
+ ```
452
+
453
+ **Open a conversation:**
454
+
455
+ ```python
456
+ opened = client.conversations.open(
457
+ id='123456',
458
+ type='admin',
459
+ admin_id='987654'
460
+ )
461
+ ```
462
+
463
+ **Snooze a conversation:**
464
+
465
+ ```python
466
+ snoozed = client.conversations.snooze(
467
+ id='123456',
468
+ type='admin',
469
+ admin_id='987654',
470
+ snoozed_until=1704153600 # Unix timestamp
471
+ )
472
+ ```
473
+
474
+ **Assign conversation to admin:**
475
+
476
+ ```python
477
+ assigned = client.conversations.assign(
478
+ id='123456',
479
+ type='admin',
480
+ admin_id='987654',
481
+ assignee_id='111222'
482
+ )
483
+ ```
484
+
485
+ **Assign to team:**
486
+
487
+ ```python
488
+ assigned = client.conversations.assign(
489
+ id='123456',
490
+ type='admin',
491
+ admin_id='987654',
492
+ assignee_id='333444',
493
+ assignment_type='team'
494
+ )
495
+ ```
496
+
497
+ **Convert conversation to ticket:**
498
+
499
+ ```python
500
+ ticket = client.conversations.convert_to_ticket(
501
+ id='123456',
502
+ ticket_type_id='100'
503
+ )
504
+ ```
505
+
506
+ **Add tag to conversation:**
507
+
508
+ ```python
509
+ client.conversations.attach_tag(
510
+ conversation_id='123456',
511
+ id='tag_789',
512
+ admin_id='987654'
513
+ )
514
+ ```
515
+
516
+ **Remove tag from conversation:**
517
+
518
+ ```python
519
+ client.conversations.detach_tag(
520
+ conversation_id='123456',
521
+ id='tag_789',
522
+ admin_id='987654'
523
+ )
524
+ ```
525
+
526
+ ### Messages
527
+
528
+ Send messages to contacts via Intercom.
529
+
530
+ **Send a message to contact:**
531
+
532
+ ```python
533
+ message = client.messages.create(
534
+ message_type='email',
535
+ from_={
536
+ 'type': 'admin',
537
+ 'id': '987654',
538
+ },
539
+ to={
540
+ 'type': 'user',
541
+ 'id': '65f9a5e4f5e5b40001234567',
542
+ },
543
+ subject='Welcome to our platform',
544
+ body='Thanks for signing up! Here are some tips to get started.'
545
+ )
546
+ ```
547
+
548
+ **Send message by email:**
549
+
550
+ ```python
551
+ message = client.messages.create(
552
+ message_type='email',
553
+ from_={
554
+ 'type': 'admin',
555
+ 'id': '987654',
556
+ },
557
+ to={
558
+ 'type': 'user',
559
+ 'email': '[email protected]',
560
+ },
561
+ subject='Your monthly report',
562
+ body='Here is your activity summary for January.'
563
+ )
564
+ ```
565
+
566
+ **Send in-app message:**
567
+
568
+ ```python
569
+ message = client.messages.create(
570
+ message_type='inapp',
571
+ from_={
572
+ 'type': 'admin',
573
+ 'id': '987654',
574
+ },
575
+ to={
576
+ 'type': 'user',
577
+ 'id': '65f9a5e4f5e5b40001234567',
578
+ },
579
+ body='Check out our new features!'
580
+ )
581
+ ```
582
+
583
+ **Send message with custom data:**
584
+
585
+ ```python
586
+ message = client.messages.create(
587
+ message_type='email',
588
+ from_={
589
+ 'type': 'admin',
590
+ 'id': '987654',
591
+ },
592
+ to={
593
+ 'type': 'user',
594
+ 'id': '65f9a5e4f5e5b40001234567',
595
+ },
596
+ subject='Order confirmation',
597
+ body='Your order has been confirmed.',
598
+ template='plain',
599
+ create_conversation_without_contact_reply=False
600
+ )
601
+ ```
602
+
603
+ ### Data Events
604
+
605
+ Track user behavior and custom events.
606
+
607
+ **Submit a data event:**
608
+
609
+ ```python
610
+ import time
611
+
612
+ client.events.create(
613
+ event_name='purchased_item',
614
+ created_at=int(time.time()),
615
+ user_id='65f9a5e4f5e5b40001234567',
616
+ metadata={
617
+ 'item_name': 'Premium Plan',
618
+ 'item_price': 99.99,
619
+ 'currency': 'USD',
620
+ 'quantity': 1,
621
+ }
622
+ )
623
+ ```
624
+
625
+ **Event with email identifier:**
626
+
627
+ ```python
628
+ client.events.create(
629
+ event_name='signed_up',
630
+ created_at=int(time.time()),
631
+ email='[email protected]',
632
+ metadata={
633
+ 'source': 'landing_page',
634
+ 'campaign': 'winter_2025',
635
+ }
636
+ )
637
+ ```
638
+
639
+ **Complex event metadata:**
640
+
641
+ ```python
642
+ client.events.create(
643
+ event_name='completed_onboarding',
644
+ created_at=int(time.time()),
645
+ user_id='65f9a5e4f5e5b40001234567',
646
+ metadata={
647
+ 'steps_completed': 5,
648
+ 'time_taken_seconds': 320,
649
+ 'skipped_steps': ['profile_picture'],
650
+ 'completion_rate': 0.95,
651
+ 'device': 'mobile',
652
+ }
653
+ )
654
+ ```
655
+
656
+ **List events for user:**
657
+
658
+ ```python
659
+ events = client.events.list(
660
+ type='user',
661
+ user_id='65f9a5e4f5e5b40001234567'
662
+ )
663
+
664
+ for event in events.events:
665
+ print(event.event_name, event.created_at)
666
+ ```
667
+
668
+ **Event summaries:**
669
+
670
+ ```python
671
+ summary = client.events.summaries(
672
+ user_id='65f9a5e4f5e5b40001234567',
673
+ event_name='purchased_item'
674
+ )
675
+
676
+ print(summary.count, summary.first, summary.last)
677
+ ```
678
+
679
+ ### Tags
680
+
681
+ Organize and categorize contacts, companies, and conversations.
682
+
683
+ **Create a tag:**
684
+
685
+ ```python
686
+ tag = client.tags.create(name='VIP Customer')
687
+
688
+ print(tag.id)
689
+ ```
690
+
691
+ **Retrieve a tag:**
692
+
693
+ ```python
694
+ tag = client.tags.find(id='tag_789')
695
+ ```
696
+
697
+ **List all tags:**
698
+
699
+ ```python
700
+ tags = client.tags.list()
701
+
702
+ for tag in tags.data:
703
+ print(tag.name, tag.id)
704
+ ```
705
+
706
+ **Tag a contact:**
707
+
708
+ ```python
709
+ client.contacts.tag(
710
+ contact_id='65f9a5e4f5e5b40001234567',
711
+ id='tag_789'
712
+ )
713
+ ```
714
+
715
+ **Tag a company:**
716
+
717
+ ```python
718
+ client.companies.tag(
719
+ company_id='company_123',
720
+ id='tag_789'
721
+ )
722
+ ```
723
+
724
+ **Untag a contact:**
725
+
726
+ ```python
727
+ client.contacts.untag(
728
+ contact_id='65f9a5e4f5e5b40001234567',
729
+ id='tag_789'
730
+ )
731
+ ```
732
+
733
+ **Delete a tag:**
734
+
735
+ ```python
736
+ client.tags.delete(id='tag_789')
737
+ ```
738
+
739
+ ### Data Attributes
740
+
741
+ Define custom attributes for contacts and companies.
742
+
743
+ **Create a contact attribute:**
744
+
745
+ ```python
746
+ attribute = client.data_attributes.create(
747
+ name='subscription_tier',
748
+ model='contact',
749
+ data_type='string',
750
+ options=['free', 'pro', 'enterprise'],
751
+ description='Customer subscription level'
752
+ )
753
+ ```
754
+
755
+ **Create a company attribute:**
756
+
757
+ ```python
758
+ attribute = client.data_attributes.create(
759
+ name='annual_revenue',
760
+ model='company',
761
+ data_type='float',
762
+ description='Company annual revenue in USD'
763
+ )
764
+ ```
765
+
766
+ **Create boolean attribute:**
767
+
768
+ ```python
769
+ attribute = client.data_attributes.create(
770
+ name='is_beta_tester',
771
+ model='contact',
772
+ data_type='boolean',
773
+ description='Whether user is enrolled in beta program'
774
+ )
775
+ ```
776
+
777
+ **Create date attribute:**
778
+
779
+ ```python
780
+ attribute = client.data_attributes.create(
781
+ name='trial_end_date',
782
+ model='contact',
783
+ data_type='date',
784
+ description='Date when trial period ends'
785
+ )
786
+ ```
787
+
788
+ **List data attributes:**
789
+
790
+ ```python
791
+ attributes = client.data_attributes.list(model='contact')
792
+
793
+ for attr in attributes.data:
794
+ print(attr.name, attr.data_type)
795
+ ```
796
+
797
+ **Update an attribute:**
798
+
799
+ ```python
800
+ updated = client.data_attributes.update(
801
+ id='attr_123',
802
+ description='Updated description',
803
+ options=['free', 'pro', 'enterprise', 'custom']
804
+ )
805
+ ```
806
+
807
+ ### Notes
808
+
809
+ Add notes to contacts and companies for internal reference.
810
+
811
+ **Create a note for contact:**
812
+
813
+ ```python
814
+ note = client.notes.create(
815
+ contact_id='65f9a5e4f5e5b40001234567',
816
+ admin_id='987654',
817
+ body='Customer requested custom integration. Follow up next week.'
818
+ )
819
+ ```
820
+
821
+ **Create a note for company:**
822
+
823
+ ```python
824
+ note = client.notes.create(
825
+ company_id='company_123',
826
+ admin_id='987654',
827
+ body='Contract renewal coming up in Q2 2025.'
828
+ )
829
+ ```
830
+
831
+ **Retrieve a note:**
832
+
833
+ ```python
834
+ note = client.notes.find(id='note_456')
835
+ ```
836
+
837
+ **List notes for contact:**
838
+
839
+ ```python
840
+ notes = client.contacts.list_notes(id='65f9a5e4f5e5b40001234567')
841
+
842
+ for note in notes.data:
843
+ print(note.body, note.created_at)
844
+ ```
845
+
846
+ ### Segments
847
+
848
+ Query and retrieve segments (groups of contacts).
849
+
850
+ **List all segments:**
851
+
852
+ ```python
853
+ segments = client.segments.list()
854
+
855
+ for segment in segments.segments:
856
+ print(segment.name, segment.count)
857
+ ```
858
+
859
+ **Retrieve a segment:**
860
+
861
+ ```python
862
+ segment = client.segments.find(id='segment_999')
863
+
864
+ print(segment.name, segment.person_type)
865
+ ```
866
+
867
+ **List contacts in segment:**
868
+
869
+ ```python
870
+ contacts = client.segments.list_contacts(id='segment_999')
871
+
872
+ for contact in contacts:
873
+ print(contact.email)
874
+ ```
875
+
876
+ ### Tickets
877
+
878
+ Manage customer support tickets.
879
+
880
+ **Create a ticket:**
881
+
882
+ ```python
883
+ ticket = client.tickets.create(
884
+ contact_id='65f9a5e4f5e5b40001234567',
885
+ ticket_type_id='100',
886
+ contacts=[
887
+ {
888
+ 'id': '65f9a5e4f5e5b40001234567',
889
+ }
890
+ ],
891
+ ticket_attributes={
892
+ '_default_title_': 'Payment issue',
893
+ '_default_description_': 'Customer unable to process payment',
894
+ }
895
+ )
896
+ ```
897
+
898
+ **Retrieve a ticket:**
899
+
900
+ ```python
901
+ ticket = client.tickets.find(id='ticket_888')
902
+
903
+ print(ticket.ticket_state)
904
+ ```
905
+
906
+ **Update a ticket:**
907
+
908
+ ```python
909
+ updated = client.tickets.update(
910
+ id='ticket_888',
911
+ ticket_attributes={
912
+ '_default_title_': 'Payment issue - RESOLVED',
913
+ },
914
+ ticket_state='submitted'
915
+ )
916
+ ```
917
+
918
+ **Reply to ticket:**
919
+
920
+ ```python
921
+ reply = client.tickets.reply(
922
+ id='ticket_888',
923
+ admin_id='987654',
924
+ message_type='comment',
925
+ body='Issue has been resolved. Payment processed successfully.'
926
+ )
927
+ ```
928
+
929
+ **Search tickets:**
930
+
931
+ ```python
932
+ results = client.tickets.search(
933
+ query={
934
+ 'field': 'ticket_state',
935
+ 'operator': '=',
936
+ 'value': 'submitted',
937
+ }
938
+ )
939
+
940
+ for ticket in results.tickets:
941
+ print(ticket.id, ticket.ticket_attributes)
942
+ ```
943
+
944
+ ### Admins
945
+
946
+ Manage admin users and teams.
947
+
948
+ **List all admins:**
949
+
950
+ ```python
951
+ admins = client.admins.list()
952
+
953
+ for admin in admins.admins:
954
+ print(admin.name, admin.email)
955
+ ```
956
+
957
+ **Retrieve an admin:**
958
+
959
+ ```python
960
+ admin = client.admins.find(id='987654')
961
+
962
+ print(admin.name, admin.away_mode_enabled)
963
+ ```
964
+
965
+ **Retrieve current admin:**
966
+
967
+ ```python
968
+ me = client.admins.me()
969
+
970
+ print(me.name, me.email)
971
+ ```
972
+
973
+ **Set away mode:**
974
+
975
+ ```python
976
+ updated = client.admins.set_away_mode(
977
+ admin_id='987654',
978
+ away_mode_enabled=True,
979
+ away_mode_reassign=True
980
+ )
981
+ ```
982
+
983
+ **List teams:**
984
+
985
+ ```python
986
+ teams = client.teams.list()
987
+
988
+ for team in teams.teams:
989
+ print(team.name, team.id)
990
+ ```
991
+
992
+ **Retrieve a team:**
993
+
994
+ ```python
995
+ team = client.teams.find(id='333444')
996
+ ```
997
+
998
+ ### Articles
999
+
1000
+ Manage help center articles.
1001
+
1002
+ **Create an article:**
1003
+
1004
+ ```python
1005
+ article = client.articles.create(
1006
+ title='Getting Started Guide',
1007
+ description='Learn how to use our platform',
1008
+ body='<h1>Welcome</h1><p>This guide will help you get started...</p>',
1009
+ author_id=987654,
1010
+ state='published'
1011
+ )
1012
+ ```
1013
+
1014
+ **Retrieve an article:**
1015
+
1016
+ ```python
1017
+ article = client.articles.find(id='article_555')
1018
+ ```
1019
+
1020
+ **Update an article:**
1021
+
1022
+ ```python
1023
+ updated = client.articles.update(
1024
+ id='article_555',
1025
+ title='Getting Started Guide (Updated)',
1026
+ body='<h1>Welcome</h1><p>This updated guide...</p>'
1027
+ )
1028
+ ```
1029
+
1030
+ **List articles:**
1031
+
1032
+ ```python
1033
+ response = client.articles.list(per_page=50)
1034
+
1035
+ for article in response:
1036
+ print(article.title, article.state)
1037
+ ```
1038
+
1039
+ **Delete an article:**
1040
+
1041
+ ```python
1042
+ client.articles.delete(id='article_555')
1043
+ ```
1044
+
1045
+ ### Subscription Types
1046
+
1047
+ Manage subscription preferences for contacts.
1048
+
1049
+ **List subscription types:**
1050
+
1051
+ ```python
1052
+ types = client.subscription_types.list()
1053
+
1054
+ for sub_type in types.data:
1055
+ print(sub_type.id, sub_type.content_type)
1056
+ ```
1057
+
1058
+ **Subscribe contact:**
1059
+
1060
+ ```python
1061
+ client.contacts.subscribe(
1062
+ id='65f9a5e4f5e5b40001234567',
1063
+ subscription_type_id='sub_123'
1064
+ )
1065
+ ```
1066
+
1067
+ **Unsubscribe contact:**
1068
+
1069
+ ```python
1070
+ client.contacts.unsubscribe(
1071
+ id='65f9a5e4f5e5b40001234567',
1072
+ subscription_type_id='sub_123'
1073
+ )
1074
+ ```
1075
+
1076
+ ## Error Handling
1077
+
1078
+ **Basic error handling:**
1079
+
1080
+ ```python
1081
+ from intercom import ApiError
1082
+
1083
+ try:
1084
+ contact = client.contacts.find(id='invalid_id')
1085
+ except ApiError as e:
1086
+ print(f'Status: {e.status_code}')
1087
+ print(f'Message: {e.message}')
1088
+ print(f'Body: {e.body}')
1089
+ ```
1090
+
1091
+ **Handle specific error codes:**
1092
+
1093
+ ```python
1094
+ try:
1095
+ client.contacts.create(email='[email protected]')
1096
+ except ApiError as e:
1097
+ if e.status_code == 400:
1098
+ print('Bad request:', e.message)
1099
+ elif e.status_code == 401:
1100
+ print('Unauthorized - check your token')
1101
+ elif e.status_code == 404:
1102
+ print('Resource not found')
1103
+ elif e.status_code == 429:
1104
+ print('Rate limit exceeded')
1105
+ else:
1106
+ print('Error:', e.message)
1107
+ ```
1108
+
1109
+ **Retry on rate limit:**
1110
+
1111
+ ```python
1112
+ import time
1113
+ from intercom import ApiError
1114
+
1115
+ def create_contact_with_retry(data, max_retries=3):
1116
+ for attempt in range(1, max_retries + 1):
1117
+ try:
1118
+ return client.contacts.create(**data)
1119
+ except ApiError as e:
1120
+ if e.status_code == 429 and attempt < max_retries:
1121
+ delay = 2 ** attempt
1122
+ print(f'Rate limited, retrying in {delay}s...')
1123
+ time.sleep(delay)
1124
+ continue
1125
+ raise
1126
+ ```
1127
+
1128
+ ## Pagination
1129
+
1130
+ **Auto-pagination with iterator:**
1131
+
1132
+ ```python
1133
+ response = client.contacts.list()
1134
+
1135
+ for contact in response:
1136
+ print(contact.email)
1137
+ # Automatically fetches next page when needed
1138
+ ```
1139
+
1140
+ **Manual pagination:**
1141
+
1142
+ ```python
1143
+ has_more = True
1144
+ starting_after = None
1145
+
1146
+ while has_more:
1147
+ response = client.contacts.list(
1148
+ per_page=50,
1149
+ starting_after=starting_after
1150
+ )
1151
+
1152
+ for contact in response.data:
1153
+ print(contact.email)
1154
+
1155
+ has_more = response.pages and response.pages.next
1156
+ starting_after = response.pages.next.starting_after if has_more else None
1157
+ ```
1158
+
1159
+ **Get all pages at once:**
1160
+
1161
+ ```python
1162
+ all_contacts = []
1163
+ response = client.contacts.list()
1164
+
1165
+ for contact in response:
1166
+ all_contacts.append(contact)
1167
+
1168
+ print(f'Total contacts: {len(all_contacts)}')
1169
+ ```
1170
+
1171
+ ## Async Client
1172
+
1173
+ **Basic async usage:**
1174
+
1175
+ ```python
1176
+ import asyncio
1177
+ from intercom import AsyncIntercom
1178
+
1179
+ async def main():
1180
+ client = AsyncIntercom(
1181
+ token=os.getenv('INTERCOM_ACCESS_TOKEN')
1182
+ )
1183
+
1184
+ contact = await client.contacts.find(id='65f9a5e4f5e5b40001234567')
1185
+ print(contact.email)
1186
+
1187
+ await client.close()
1188
+
1189
+ asyncio.run(main())
1190
+ ```
1191
+
1192
+ **Async context manager:**
1193
+
1194
+ ```python
1195
+ async def main():
1196
+ async with AsyncIntercom(token=os.getenv('INTERCOM_ACCESS_TOKEN')) as client:
1197
+ contact = await client.contacts.create(
1198
+ email='[email protected]',
1199
+ name='Async User'
1200
+ )
1201
+ print(contact.id)
1202
+
1203
+ asyncio.run(main())
1204
+ ```
1205
+
1206
+ **Concurrent operations:**
1207
+
1208
+ ```python
1209
+ async def create_multiple_contacts():
1210
+ async with AsyncIntercom(token=os.getenv('INTERCOM_ACCESS_TOKEN')) as client:
1211
+ tasks = [
1212
+ client.contacts.create(email=f'user{i}@example.com', name=f'User {i}')
1213
+ for i in range(10)
1214
+ ]
1215
+
1216
+ contacts = await asyncio.gather(*tasks)
1217
+
1218
+ for contact in contacts:
1219
+ print(contact.email)
1220
+
1221
+ asyncio.run(create_multiple_contacts())
1222
+ ```
1223
+
1224
+ **Async pagination:**
1225
+
1226
+ ```python
1227
+ async def list_all_contacts():
1228
+ async with AsyncIntercom(token=os.getenv('INTERCOM_ACCESS_TOKEN')) as client:
1229
+ response = await client.contacts.list()
1230
+
1231
+ async for contact in response:
1232
+ print(contact.email)
1233
+
1234
+ asyncio.run(list_all_contacts())
1235
+ ```
1236
+
1237
+ ## Advanced Features
1238
+
1239
+ **Custom headers:**
1240
+
1241
+ ```python
1242
+ contact = client.contacts.create(
1243
+ email='[email protected]',
1244
+ name='Test User',
1245
+ headers={
1246
+ 'X-Custom-Header': 'custom-value',
1247
+ }
1248
+ )
1249
+ ```
1250
+
1251
+ **Request timeout:**
1252
+
1253
+ ```python
1254
+ contact = client.contacts.find(
1255
+ id='65f9a5e4f5e5b40001234567',
1256
+ timeout=30
1257
+ )
1258
+ ```
1259
+
1260
+ **Disable automatic retries:**
1261
+
1262
+ ```python
1263
+ client = Intercom(
1264
+ token=os.getenv('INTERCOM_ACCESS_TOKEN'),
1265
+ max_retries=0 # Disable retries
1266
+ )
1267
+ ```
1268
+
1269
+ **Custom retry configuration:**
1270
+
1271
+ ```python
1272
+ client = Intercom(
1273
+ token=os.getenv('INTERCOM_ACCESS_TOKEN'),
1274
+ max_retries=5,
1275
+ timeout=90
1276
+ )
1277
+ ```
1278
+
1279
+ ## Webhooks
1280
+
1281
+ **Verify webhook signature:**
1282
+
1283
+ ```python
1284
+ import hmac
1285
+ import hashlib
1286
+
1287
+ def verify_webhook(body, signature, secret):
1288
+ computed_hash = hmac.new(
1289
+ secret.encode('utf-8'),
1290
+ body.encode('utf-8'),
1291
+ hashlib.sha256
1292
+ ).hexdigest()
1293
+
1294
+ return signature == computed_hash
1295
+
1296
+ # Flask example
1297
+ from flask import Flask, request, jsonify
1298
+
1299
+ app = Flask(__name__)
1300
+
1301
+ @app.route('/webhooks/intercom', methods=['POST'])
1302
+ def webhook():
1303
+ signature = request.headers.get('X-Hub-Signature')
1304
+ body = request.get_data(as_text=True)
1305
+
1306
+ is_valid = verify_webhook(
1307
+ body,
1308
+ signature,
1309
+ os.getenv('INTERCOM_WEBHOOK_SECRET')
1310
+ )
1311
+
1312
+ if not is_valid:
1313
+ return jsonify({'error': 'Invalid signature'}), 401
1314
+
1315
+ event = request.json
1316
+ print(f'Webhook event: {event["topic"]}')
1317
+
1318
+ return jsonify({'status': 'ok'})
1319
+ ```
1320
+
1321
+ **Handle webhook events:**
1322
+
1323
+ ```python
1324
+ @app.route('/webhooks/intercom', methods=['POST'])
1325
+ def webhook():
1326
+ event = request.json
1327
+ topic = event.get('topic')
1328
+ data = event.get('data')
1329
+
1330
+ if topic == 'contact.created':
1331
+ print(f'New contact: {data["item"]["email"]}')
1332
+
1333
+ elif topic == 'conversation.user.created':
1334
+ print(f'New conversation: {data["item"]["id"]}')
1335
+
1336
+ elif topic == 'conversation.admin.replied':
1337
+ print(f'Admin replied to: {data["item"]["id"]}')
1338
+
1339
+ elif topic == 'user.tag.created':
1340
+ print(f'User tagged: {data["item"]["user"]["email"]}')
1341
+
1342
+ else:
1343
+ print(f'Unknown event: {topic}')
1344
+
1345
+ return jsonify({'status': 'ok'})
1346
+ ```
1347
+
1348
+ **Django webhook handler:**
1349
+
1350
+ ```python
1351
+ from django.http import JsonResponse
1352
+ from django.views.decorators.csrf import csrf_exempt
1353
+ import json
1354
+
1355
+ @csrf_exempt
1356
+ def intercom_webhook(request):
1357
+ if request.method == 'POST':
1358
+ signature = request.headers.get('X-Hub-Signature')
1359
+ body = request.body.decode('utf-8')
1360
+
1361
+ is_valid = verify_webhook(
1362
+ body,
1363
+ signature,
1364
+ os.getenv('INTERCOM_WEBHOOK_SECRET')
1365
+ )
1366
+
1367
+ if not is_valid:
1368
+ return JsonResponse({'error': 'Invalid signature'}, status=401)
1369
+
1370
+ event = json.loads(body)
1371
+ topic = event.get('topic')
1372
+
1373
+ # Handle event
1374
+ print(f'Event: {topic}')
1375
+
1376
+ return JsonResponse({'status': 'ok'})
1377
+
1378
+ return JsonResponse({'error': 'Method not allowed'}, status=405)
1379
+ ```
1380
+
1381
+ ## Rate Limiting
1382
+
1383
+ Intercom enforces rate limits on API requests. The SDK handles retries automatically.
1384
+
1385
+ **Default retry behavior:**
1386
+
1387
+ ```python
1388
+ # SDK automatically retries on 429 (rate limit) responses
1389
+ # with exponential backoff (2 retries by default)
1390
+
1391
+ client = Intercom(
1392
+ token=os.getenv('INTERCOM_ACCESS_TOKEN'),
1393
+ max_retries=2 # Default
1394
+ )
1395
+ ```
1396
+
1397
+ **Handle rate limits manually:**
1398
+
1399
+ ```python
1400
+ import time
1401
+ from intercom import ApiError
1402
+
1403
+ def make_request_with_backoff(request_fn, max_retries=5):
1404
+ for i in range(max_retries):
1405
+ try:
1406
+ return request_fn()
1407
+ except ApiError as e:
1408
+ if e.status_code == 429:
1409
+ if i < max_retries - 1:
1410
+ wait_time = 2 ** i
1411
+ print(f'Rate limited. Waiting {wait_time}s...')
1412
+ time.sleep(wait_time)
1413
+ continue
1414
+ raise
1415
+
1416
+ # Usage
1417
+ contact = make_request_with_backoff(
1418
+ lambda: client.contacts.create(email='[email protected]')
1419
+ )
1420
+ ```
1421
+
1422
+ ## Bulk Operations
1423
+
1424
+ **Bulk create contacts:**
1425
+
1426
+ ```python
1427
+ contacts_data = [
1428
+ {'email': '[email protected]', 'name': 'User 1'},
1429
+ {'email': '[email protected]', 'name': 'User 2'},
1430
+ {'email': '[email protected]', 'name': 'User 3'},
1431
+ ]
1432
+
1433
+ results = []
1434
+ for data in contacts_data:
1435
+ try:
1436
+ contact = client.contacts.create(**data)
1437
+ results.append({'success': True, 'data': contact})
1438
+ except ApiError as e:
1439
+ results.append({'success': False, 'error': str(e)})
1440
+
1441
+ succeeded = sum(1 for r in results if r['success'])
1442
+ print(f'Created {succeeded} contacts')
1443
+ ```
1444
+
1445
+ **Bulk update with concurrency (async):**
1446
+
1447
+ ```python
1448
+ import asyncio
1449
+ from intercom import AsyncIntercom, ApiError
1450
+
1451
+ async def bulk_update_contacts(updates):
1452
+ async with AsyncIntercom(token=os.getenv('INTERCOM_ACCESS_TOKEN')) as client:
1453
+ tasks = [
1454
+ client.contacts.update(**data)
1455
+ for data in updates
1456
+ ]
1457
+
1458
+ results = await asyncio.gather(*tasks, return_exceptions=True)
1459
+
1460
+ succeeded = sum(1 for r in results if not isinstance(r, Exception))
1461
+ failed = len(results) - succeeded
1462
+
1463
+ print(f'Success: {succeeded}, Failed: {failed}')
1464
+ return results
1465
+
1466
+ # Usage
1467
+ updates = [
1468
+ {'id': '1', 'name': 'Updated 1'},
1469
+ {'id': '2', 'name': 'Updated 2'},
1470
+ {'id': '3', 'name': 'Updated 3'},
1471
+ ]
1472
+
1473
+ asyncio.run(bulk_update_contacts(updates))
1474
+ ```
1475
+
1476
+ **Rate-limited bulk operations:**
1477
+
1478
+ ```python
1479
+ import time
1480
+
1481
+ def bulk_operation_with_rate_limit(items, operation, requests_per_second=5):
1482
+ results = []
1483
+ delay = 1.0 / requests_per_second
1484
+
1485
+ for item in items:
1486
+ try:
1487
+ result = operation(item)
1488
+ results.append({'success': True, 'data': result})
1489
+ except ApiError as e:
1490
+ results.append({'success': False, 'error': str(e)})
1491
+
1492
+ time.sleep(delay)
1493
+
1494
+ return results
1495
+
1496
+ # Usage
1497
+ contact_data = [
1498
+ {'email': '[email protected]', 'name': 'User 1'},
1499
+ {'email': '[email protected]', 'name': 'User 2'},
1500
+ ]
1501
+
1502
+ results = bulk_operation_with_rate_limit(
1503
+ contact_data,
1504
+ lambda data: client.contacts.create(**data),
1505
+ requests_per_second=5
1506
+ )
1507
+ ```
1508
+
1509
+ ## Environment-Specific Configuration
1510
+
1511
+ **Development:**
1512
+
1513
+ ```python
1514
+ client = Intercom(
1515
+ token=os.getenv('INTERCOM_ACCESS_TOKEN'),
1516
+ timeout=30,
1517
+ max_retries=1
1518
+ )
1519
+ ```
1520
+
1521
+ **Production:**
1522
+
1523
+ ```python
1524
+ client = Intercom(
1525
+ token=os.getenv('INTERCOM_ACCESS_TOKEN'),
1526
+ timeout=120,
1527
+ max_retries=3
1528
+ )
1529
+ ```
1530
+
1531
+ **Testing with mock:**
1532
+
1533
+ ```python
1534
+ from unittest.mock import Mock
1535
+
1536
+ # Mock client for testing
1537
+ mock_client = Mock(spec=Intercom)
1538
+ mock_client.contacts.create.return_value = Mock(
1539
+ id='test_id',
1540
+ email='[email protected]',
1541
+ name='Test User'
1542
+ )
1543
+ ```
1544
+
1545
+ ## Complete Examples
1546
+
1547
+ **User onboarding workflow:**
1548
+
1549
+ ```python
1550
+ import time
1551
+ from intercom import ApiError
1552
+
1553
+ def onboard_user(email, name, plan):
1554
+ try:
1555
+ # Create contact
1556
+ contact = client.contacts.create(
1557
+ email=email,
1558
+ name=name,
1559
+ role='user',
1560
+ custom_attributes={
1561
+ 'plan': plan,
1562
+ 'signup_date': time.strftime('%Y-%m-%d'),
1563
+ }
1564
+ )
1565
+
1566
+ # Track signup event
1567
+ client.events.create(
1568
+ event_name='signed_up',
1569
+ created_at=int(time.time()),
1570
+ user_id=contact.id,
1571
+ metadata={
1572
+ 'plan': plan,
1573
+ 'source': 'web',
1574
+ }
1575
+ )
1576
+
1577
+ # Tag as new user
1578
+ new_user_tag = client.tags.create(name='New User')
1579
+ client.contacts.tag(
1580
+ contact_id=contact.id,
1581
+ id=new_user_tag.id
1582
+ )
1583
+
1584
+ # Send welcome message
1585
+ client.messages.create(
1586
+ message_type='email',
1587
+ from_={
1588
+ 'type': 'admin',
1589
+ 'id': os.getenv('ADMIN_ID'),
1590
+ },
1591
+ to={
1592
+ 'type': 'user',
1593
+ 'id': contact.id,
1594
+ },
1595
+ subject='Welcome to our platform!',
1596
+ body=f'Hi {name}, thanks for signing up!'
1597
+ )
1598
+
1599
+ print(f'User onboarded successfully: {contact.id}')
1600
+ return contact
1601
+
1602
+ except ApiError as e:
1603
+ print(f'Onboarding failed: {e}')
1604
+ raise
1605
+ ```
1606
+
1607
+ **Customer support workflow:**
1608
+
1609
+ ```python
1610
+ def handle_support_request(user_id, subject, message):
1611
+ try:
1612
+ # Create conversation
1613
+ conversation = client.conversations.create(
1614
+ from_={
1615
+ 'type': 'user',
1616
+ 'id': user_id,
1617
+ },
1618
+ body=message
1619
+ )
1620
+
1621
+ # Assign to team
1622
+ client.conversations.assign(
1623
+ id=conversation.id,
1624
+ type='admin',
1625
+ admin_id=os.getenv('ADMIN_ID'),
1626
+ assignee_id=os.getenv('SUPPORT_TEAM_ID'),
1627
+ assignment_type='team'
1628
+ )
1629
+
1630
+ # Add priority tag if urgent
1631
+ if 'urgent' in subject.lower():
1632
+ urgent_tag = client.tags.create(name='Urgent')
1633
+ client.conversations.attach_tag(
1634
+ conversation_id=conversation.id,
1635
+ id=urgent_tag.id,
1636
+ admin_id=os.getenv('ADMIN_ID')
1637
+ )
1638
+
1639
+ # Track support event
1640
+ client.events.create(
1641
+ event_name='support_request_created',
1642
+ created_at=int(time.time()),
1643
+ user_id=user_id,
1644
+ metadata={
1645
+ 'conversation_id': conversation.id,
1646
+ 'subject': subject,
1647
+ 'urgent': 'urgent' in subject.lower(),
1648
+ }
1649
+ )
1650
+
1651
+ return conversation
1652
+
1653
+ except ApiError as e:
1654
+ print(f'Support request failed: {e}')
1655
+ raise
1656
+ ```
1657
+
1658
+ **Company and contact management:**
1659
+
1660
+ ```python
1661
+ def add_contact_to_company(contact_email, company_id):
1662
+ try:
1663
+ # Find or create contact
1664
+ try:
1665
+ search_results = client.contacts.search(
1666
+ query={
1667
+ 'field': 'email',
1668
+ 'operator': '=',
1669
+ 'value': contact_email,
1670
+ }
1671
+ )
1672
+ contact = search_results.data[0]
1673
+ except (ApiError, IndexError):
1674
+ contact = client.contacts.create(
1675
+ email=contact_email,
1676
+ role='user'
1677
+ )
1678
+
1679
+ # Attach to company
1680
+ client.contacts.update(
1681
+ id=contact.id,
1682
+ companies=[
1683
+ {
1684
+ 'company_id': company_id,
1685
+ }
1686
+ ]
1687
+ )
1688
+
1689
+ # Get company details
1690
+ company = client.companies.find(company_id=company_id)
1691
+
1692
+ print(f'Added {contact_email} to {company.name}')
1693
+
1694
+ return {'contact': contact, 'company': company}
1695
+
1696
+ except ApiError as e:
1697
+ print(f'Failed to add contact to company: {e}')
1698
+ raise
1699
+ ```
1700
+
1701
+ **Analytics and reporting:**
1702
+
1703
+ ```python
1704
+ def generate_user_report(user_id):
1705
+ try:
1706
+ # Get user details
1707
+ contact = client.contacts.find(id=user_id)
1708
+
1709
+ # Get user events
1710
+ events = client.events.list(
1711
+ type='user',
1712
+ user_id=user_id
1713
+ )
1714
+
1715
+ # Get conversations
1716
+ conversations = client.conversations.search(
1717
+ query={
1718
+ 'field': 'contact_ids',
1719
+ 'operator': '=',
1720
+ 'value': user_id,
1721
+ }
1722
+ )
1723
+
1724
+ # Get notes
1725
+ notes = client.contacts.list_notes(id=user_id)
1726
+
1727
+ report = {
1728
+ 'contact': {
1729
+ 'email': contact.email,
1730
+ 'name': contact.name,
1731
+ 'created_at': contact.created_at,
1732
+ 'custom_attributes': contact.custom_attributes,
1733
+ },
1734
+ 'events': [
1735
+ {
1736
+ 'name': e.event_name,
1737
+ 'created_at': e.created_at,
1738
+ 'metadata': e.metadata,
1739
+ }
1740
+ for e in events.events
1741
+ ],
1742
+ 'conversations': {
1743
+ 'total': conversations.total_count,
1744
+ 'open': sum(1 for c in conversations.conversations if c.state == 'open'),
1745
+ 'closed': sum(1 for c in conversations.conversations if c.state == 'closed'),
1746
+ },
1747
+ 'notes': [
1748
+ {
1749
+ 'body': n.body,
1750
+ 'created_at': n.created_at,
1751
+ }
1752
+ for n in notes.data
1753
+ ],
1754
+ }
1755
+
1756
+ return report
1757
+
1758
+ except ApiError as e:
1759
+ print(f'Report generation failed: {e}')
1760
+ raise
1761
+ ```
1762
+
1763
+ **Async batch processing:**
1764
+
1765
+ ```python
1766
+ import asyncio
1767
+ from intercom import AsyncIntercom
1768
+
1769
+ async def process_contacts_batch(contact_ids):
1770
+ async with AsyncIntercom(token=os.getenv('INTERCOM_ACCESS_TOKEN')) as client:
1771
+ # Fetch all contacts concurrently
1772
+ tasks = [client.contacts.find(id=contact_id) for contact_id in contact_ids]
1773
+ contacts = await asyncio.gather(*tasks, return_exceptions=True)
1774
+
1775
+ # Process successful results
1776
+ valid_contacts = [c for c in contacts if not isinstance(c, Exception)]
1777
+
1778
+ # Update contacts concurrently
1779
+ update_tasks = [
1780
+ client.contacts.update(
1781
+ id=contact.id,
1782
+ custom_attributes={'last_processed': int(time.time())}
1783
+ )
1784
+ for contact in valid_contacts
1785
+ ]
1786
+
1787
+ results = await asyncio.gather(*update_tasks, return_exceptions=True)
1788
+
1789
+ succeeded = sum(1 for r in results if not isinstance(r, Exception))
1790
+ print(f'Processed {succeeded}/{len(contact_ids)} contacts')
1791
+
1792
+ return results
1793
+
1794
+ # Usage
1795
+ contact_ids = ['id1', 'id2', 'id3', 'id4', 'id5']
1796
+ asyncio.run(process_contacts_batch(contact_ids))
1797
+ ```