attio 0.1.3 โ 0.3.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.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +3 -51
- data/CHANGELOG.md +62 -1
- data/CLAUDE.md +360 -0
- data/CONCEPTS.md +428 -0
- data/Gemfile.lock +3 -1
- data/README.md +304 -7
- data/examples/advanced_filtering.rb +178 -0
- data/examples/basic_usage.rb +110 -0
- data/examples/collaboration_example.rb +173 -0
- data/examples/full_workflow.rb +348 -0
- data/examples/notes_and_tasks.rb +200 -0
- data/lib/attio/client.rb +86 -0
- data/lib/attio/errors.rb +30 -2
- data/lib/attio/http_client.rb +16 -4
- data/lib/attio/rate_limiter.rb +212 -0
- data/lib/attio/resources/base.rb +70 -6
- data/lib/attio/resources/bulk.rb +290 -0
- data/lib/attio/resources/comments.rb +147 -0
- data/lib/attio/resources/deals.rb +183 -0
- data/lib/attio/resources/lists.rb +9 -21
- data/lib/attio/resources/meta.rb +72 -0
- data/lib/attio/resources/notes.rb +110 -0
- data/lib/attio/resources/records.rb +11 -24
- data/lib/attio/resources/tasks.rb +131 -0
- data/lib/attio/resources/threads.rb +154 -0
- data/lib/attio/resources/workspace_members.rb +103 -0
- data/lib/attio/version.rb +1 -1
- data/lib/attio.rb +9 -0
- metadata +17 -1
data/README.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
[](https://github.com/idl3/attio/tree/master/spec)
|
5
5
|
[](https://idl3.github.io/attio)
|
6
6
|
[](https://badge.fury.io/rb/attio)
|
7
|
-
[](https://github.com/idl3/attio/tree/master/spec)
|
8
8
|
|
9
9
|
Ruby client for the [Attio CRM API](https://developers.attio.com/). This library provides easy access to the Attio API, allowing you to manage records, objects, lists, and more.
|
10
10
|
|
@@ -154,6 +154,156 @@ client.records.update(
|
|
154
154
|
|
155
155
|
### Working with Other Resources
|
156
156
|
|
157
|
+
#### Comments
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
# List comments on a record
|
161
|
+
comments = client.comments.list(
|
162
|
+
parent_object: 'people',
|
163
|
+
parent_record_id: 'person-123'
|
164
|
+
)
|
165
|
+
|
166
|
+
# List comments in a thread
|
167
|
+
thread_comments = client.comments.list(thread_id: 'thread-456')
|
168
|
+
|
169
|
+
# Create a comment on a record
|
170
|
+
comment = client.comments.create(
|
171
|
+
parent_object: 'people',
|
172
|
+
parent_record_id: 'person-123',
|
173
|
+
content: 'This is a comment with **markdown** support!'
|
174
|
+
)
|
175
|
+
|
176
|
+
# Create a comment in a thread
|
177
|
+
thread_comment = client.comments.create(
|
178
|
+
thread_id: 'thread-456',
|
179
|
+
content: 'Following up on this discussion'
|
180
|
+
)
|
181
|
+
|
182
|
+
# Update a comment
|
183
|
+
updated_comment = client.comments.update(
|
184
|
+
id: 'comment-123',
|
185
|
+
content: 'Updated comment content'
|
186
|
+
)
|
187
|
+
|
188
|
+
# React to a comment
|
189
|
+
client.comments.react(id: 'comment-123', emoji: '๐')
|
190
|
+
|
191
|
+
# Remove reaction
|
192
|
+
client.comments.unreact(id: 'comment-123', emoji: '๐')
|
193
|
+
|
194
|
+
# Delete a comment
|
195
|
+
client.comments.delete(id: 'comment-123')
|
196
|
+
```
|
197
|
+
|
198
|
+
#### Threads
|
199
|
+
|
200
|
+
```ruby
|
201
|
+
# List threads on a record
|
202
|
+
threads = client.threads.list(
|
203
|
+
parent_object: 'companies',
|
204
|
+
parent_record_id: 'company-123'
|
205
|
+
)
|
206
|
+
|
207
|
+
# Get a thread with comments
|
208
|
+
thread = client.threads.get(id: 'thread-123', include_comments: true)
|
209
|
+
|
210
|
+
# Create a thread
|
211
|
+
thread = client.threads.create(
|
212
|
+
parent_object: 'companies',
|
213
|
+
parent_record_id: 'company-123',
|
214
|
+
title: 'Q4 Planning Discussion',
|
215
|
+
description: 'Thread for Q4 planning discussions',
|
216
|
+
participant_ids: ['user-1', 'user-2']
|
217
|
+
)
|
218
|
+
|
219
|
+
# Update thread title
|
220
|
+
client.threads.update(id: 'thread-123', title: 'Updated Q4 Planning')
|
221
|
+
|
222
|
+
# Manage participants
|
223
|
+
client.threads.add_participants(id: 'thread-123', user_ids: ['user-3', 'user-4'])
|
224
|
+
client.threads.remove_participants(id: 'thread-123', user_ids: ['user-2'])
|
225
|
+
|
226
|
+
# Close and reopen threads
|
227
|
+
client.threads.close(id: 'thread-123')
|
228
|
+
client.threads.reopen(id: 'thread-123')
|
229
|
+
|
230
|
+
# Delete a thread
|
231
|
+
client.threads.delete(id: 'thread-123')
|
232
|
+
```
|
233
|
+
|
234
|
+
#### Tasks
|
235
|
+
|
236
|
+
```ruby
|
237
|
+
# List all tasks
|
238
|
+
tasks = client.tasks.list
|
239
|
+
|
240
|
+
# List tasks with filters
|
241
|
+
my_tasks = client.tasks.list(
|
242
|
+
assignee_id: 'user-123',
|
243
|
+
status: 'pending'
|
244
|
+
)
|
245
|
+
|
246
|
+
# Get a specific task
|
247
|
+
task = client.tasks.get(id: 'task-123')
|
248
|
+
|
249
|
+
# Create a task
|
250
|
+
task = client.tasks.create(
|
251
|
+
parent_object: 'people',
|
252
|
+
parent_record_id: 'person-123',
|
253
|
+
title: 'Follow up with customer',
|
254
|
+
due_date: '2025-02-01',
|
255
|
+
assignee_id: 'user-456'
|
256
|
+
)
|
257
|
+
|
258
|
+
# Update a task
|
259
|
+
client.tasks.update(
|
260
|
+
id: 'task-123',
|
261
|
+
title: 'Updated task title',
|
262
|
+
status: 'in_progress'
|
263
|
+
)
|
264
|
+
|
265
|
+
# Complete a task
|
266
|
+
client.tasks.complete(id: 'task-123', completed_at: Time.now.iso8601)
|
267
|
+
|
268
|
+
# Reopen a task
|
269
|
+
client.tasks.reopen(id: 'task-123')
|
270
|
+
|
271
|
+
# Delete a task
|
272
|
+
client.tasks.delete(id: 'task-123')
|
273
|
+
```
|
274
|
+
|
275
|
+
#### Notes
|
276
|
+
|
277
|
+
```ruby
|
278
|
+
# List notes on a record
|
279
|
+
notes = client.notes.list(
|
280
|
+
parent_object: 'companies',
|
281
|
+
parent_record_id: 'company-123'
|
282
|
+
)
|
283
|
+
|
284
|
+
# Get a specific note
|
285
|
+
note = client.notes.get(id: 'note-123')
|
286
|
+
|
287
|
+
# Create a note
|
288
|
+
note = client.notes.create(
|
289
|
+
parent_object: 'companies',
|
290
|
+
parent_record_id: 'company-123',
|
291
|
+
title: 'Meeting Notes - Q4 Planning',
|
292
|
+
content: 'Discussed roadmap and resource allocation...',
|
293
|
+
tags: ['important', 'quarterly-planning']
|
294
|
+
)
|
295
|
+
|
296
|
+
# Update a note
|
297
|
+
client.notes.update(
|
298
|
+
id: 'note-123',
|
299
|
+
title: 'Updated Meeting Notes',
|
300
|
+
content: 'Added action items from discussion'
|
301
|
+
)
|
302
|
+
|
303
|
+
# Delete a note
|
304
|
+
client.notes.delete(id: 'note-123')
|
305
|
+
```
|
306
|
+
|
157
307
|
#### Objects
|
158
308
|
|
159
309
|
```ruby
|
@@ -211,6 +361,137 @@ users = client.users.list
|
|
211
361
|
user = client.users.me
|
212
362
|
```
|
213
363
|
|
364
|
+
### Advanced Features
|
365
|
+
|
366
|
+
#### Workspace Members
|
367
|
+
|
368
|
+
```ruby
|
369
|
+
# List workspace members
|
370
|
+
members = client.workspace_members.list
|
371
|
+
|
372
|
+
# Invite a new member
|
373
|
+
invitation = client.workspace_members.invite(
|
374
|
+
email: 'new.member@example.com',
|
375
|
+
role: 'member' # admin, member, or guest
|
376
|
+
)
|
377
|
+
|
378
|
+
# Update member permissions
|
379
|
+
client.workspace_members.update(
|
380
|
+
member_id: 'user-123',
|
381
|
+
data: { role: 'admin' }
|
382
|
+
)
|
383
|
+
|
384
|
+
# Remove a member
|
385
|
+
client.workspace_members.remove(member_id: 'user-123')
|
386
|
+
```
|
387
|
+
|
388
|
+
#### Deals
|
389
|
+
|
390
|
+
```ruby
|
391
|
+
# List all deals
|
392
|
+
deals = client.deals.list
|
393
|
+
|
394
|
+
# Create a new deal
|
395
|
+
deal = client.deals.create(
|
396
|
+
data: {
|
397
|
+
name: 'Enterprise Contract',
|
398
|
+
value: 50000,
|
399
|
+
stage_id: 'stage-negotiation',
|
400
|
+
company_id: 'company-123'
|
401
|
+
}
|
402
|
+
)
|
403
|
+
|
404
|
+
# Update deal stage
|
405
|
+
client.deals.update_stage(id: 'deal-123', stage_id: 'stage-won')
|
406
|
+
|
407
|
+
# Mark deal as won/lost
|
408
|
+
client.deals.mark_won(id: 'deal-123', won_date: Date.today)
|
409
|
+
client.deals.mark_lost(id: 'deal-123', lost_reason: 'Budget constraints')
|
410
|
+
|
411
|
+
# List deals by various criteria
|
412
|
+
pipeline_deals = client.deals.list_by_stage(stage_id: 'stage-proposal')
|
413
|
+
company_deals = client.deals.list_by_company(company_id: 'company-123')
|
414
|
+
my_deals = client.deals.list_by_owner(owner_id: 'user-456')
|
415
|
+
```
|
416
|
+
|
417
|
+
#### Bulk Operations
|
418
|
+
|
419
|
+
```ruby
|
420
|
+
# Bulk create records
|
421
|
+
results = client.bulk.create_records(
|
422
|
+
object: 'people',
|
423
|
+
records: [
|
424
|
+
{ name: 'John Doe', email: 'john@example.com' },
|
425
|
+
{ name: 'Jane Smith', email: 'jane@example.com' },
|
426
|
+
# ... up to 100 records per batch
|
427
|
+
]
|
428
|
+
)
|
429
|
+
|
430
|
+
# Bulk update records
|
431
|
+
results = client.bulk.update_records(
|
432
|
+
object: 'companies',
|
433
|
+
updates: [
|
434
|
+
{ id: 'company-1', data: { status: 'active' } },
|
435
|
+
{ id: 'company-2', data: { status: 'inactive' } }
|
436
|
+
]
|
437
|
+
)
|
438
|
+
|
439
|
+
# Bulk upsert (create or update based on matching)
|
440
|
+
results = client.bulk.upsert_records(
|
441
|
+
object: 'people',
|
442
|
+
match_attribute: 'email',
|
443
|
+
records: [
|
444
|
+
{ email: 'john@example.com', name: 'John Updated' },
|
445
|
+
{ email: 'new@example.com', name: 'New Person' }
|
446
|
+
]
|
447
|
+
)
|
448
|
+
```
|
449
|
+
|
450
|
+
#### Rate Limiting
|
451
|
+
|
452
|
+
```ruby
|
453
|
+
# Initialize client with custom rate limiter
|
454
|
+
limiter = Attio::RateLimiter.new(
|
455
|
+
max_requests: 100,
|
456
|
+
window_seconds: 60,
|
457
|
+
max_retries: 3
|
458
|
+
)
|
459
|
+
client.rate_limiter = limiter
|
460
|
+
|
461
|
+
# Execute with rate limiting
|
462
|
+
limiter.execute { client.records.list(object: 'people') }
|
463
|
+
|
464
|
+
# Queue requests for later processing
|
465
|
+
limiter.queue_request(priority: 1) { important_operation }
|
466
|
+
limiter.queue_request(priority: 5) { less_important_operation }
|
467
|
+
|
468
|
+
# Process queued requests
|
469
|
+
results = limiter.process_queue(max_per_batch: 10)
|
470
|
+
|
471
|
+
# Check rate limit status
|
472
|
+
status = limiter.status
|
473
|
+
puts "Remaining: #{status[:remaining]}/#{status[:limit]}"
|
474
|
+
```
|
475
|
+
|
476
|
+
#### Meta API
|
477
|
+
|
478
|
+
```ruby
|
479
|
+
# Identify current workspace and user
|
480
|
+
info = client.meta.identify
|
481
|
+
puts "Workspace: #{info['workspace']['name']}"
|
482
|
+
puts "User: #{info['user']['email']}"
|
483
|
+
|
484
|
+
# Validate API key
|
485
|
+
validation = client.meta.validate_key
|
486
|
+
puts "Valid: #{validation['valid']}"
|
487
|
+
puts "Permissions: #{validation['permissions']}"
|
488
|
+
|
489
|
+
# Get usage statistics
|
490
|
+
usage = client.meta.usage_stats
|
491
|
+
puts "Records: #{usage['records']['total']}"
|
492
|
+
puts "API calls today: #{usage['api_calls']['today']}"
|
493
|
+
```
|
494
|
+
|
214
495
|
### Error Handling
|
215
496
|
|
216
497
|
The client will raise appropriate exceptions for different error conditions:
|
@@ -240,12 +521,28 @@ end
|
|
240
521
|
|
241
522
|
This client supports all major Attio API endpoints:
|
242
523
|
|
243
|
-
|
244
|
-
- โ
|
245
|
-
- โ
|
246
|
-
- โ
|
247
|
-
- โ
Attributes
|
248
|
-
- โ
|
524
|
+
### Core Resources
|
525
|
+
- โ
**Records** - Full CRUD operations, querying with filters and sorting
|
526
|
+
- โ
**Objects** - List, get schema information
|
527
|
+
- โ
**Lists** - List, get entries, manage list entries
|
528
|
+
- โ
**Attributes** - List, create, update custom attributes
|
529
|
+
- โ
**Workspaces** - List, get current workspace
|
530
|
+
- โ
**Users** - List, get current user
|
531
|
+
|
532
|
+
### Collaboration Features
|
533
|
+
- โ
**Comments** - CRUD operations, emoji reactions on records and threads
|
534
|
+
- โ
**Threads** - CRUD operations, participant management, status control
|
535
|
+
- โ
**Tasks** - CRUD operations, assignment, completion tracking
|
536
|
+
- โ
**Notes** - CRUD operations on records
|
537
|
+
|
538
|
+
### Sales & CRM
|
539
|
+
- โ
**Deals** - Pipeline management, stage tracking, win/loss tracking
|
540
|
+
- โ
**Workspace Members** - Member management, invitations, permissions
|
541
|
+
|
542
|
+
### Advanced Features
|
543
|
+
- โ
**Bulk Operations** - Batch create/update/delete with automatic batching
|
544
|
+
- โ
**Rate Limiting** - Intelligent retry with exponential backoff and request queuing
|
545
|
+
- โ
**Meta API** - Identify workspace, validate API keys, get usage stats
|
249
546
|
|
250
547
|
## Development
|
251
548
|
|
@@ -0,0 +1,178 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "attio"
|
5
|
+
require "json"
|
6
|
+
|
7
|
+
# Example: Advanced Filtering and Querying
|
8
|
+
#
|
9
|
+
# This example demonstrates how to use advanced filtering and sorting
|
10
|
+
# capabilities when querying records in Attio.
|
11
|
+
|
12
|
+
# Initialize the client
|
13
|
+
client = Attio.client(api_key: ENV.fetch("ATTIO_API_KEY"))
|
14
|
+
|
15
|
+
puts "Attio Advanced Filtering Example"
|
16
|
+
puts "=" * 40
|
17
|
+
|
18
|
+
# 1. Query with simple filters
|
19
|
+
puts "\n1. Finding people by email domain..."
|
20
|
+
people_from_domain = client.records.list(
|
21
|
+
object: "people",
|
22
|
+
filters: {
|
23
|
+
email: { contains: "@example.com" },
|
24
|
+
},
|
25
|
+
limit: 10
|
26
|
+
)
|
27
|
+
puts " Found #{people_from_domain['data']&.length || 0} people from example.com"
|
28
|
+
|
29
|
+
# 2. Query with multiple filters (AND condition)
|
30
|
+
puts "\n2. Finding high-value companies in technology sector..."
|
31
|
+
high_value_tech = client.records.list(
|
32
|
+
object: "companies",
|
33
|
+
filters: {
|
34
|
+
industry: { equals: "Technology" },
|
35
|
+
annual_revenue: { greater_than: 1_000_000 },
|
36
|
+
},
|
37
|
+
sorts: [
|
38
|
+
{ field: "annual_revenue", direction: "desc" },
|
39
|
+
],
|
40
|
+
limit: 5
|
41
|
+
)
|
42
|
+
puts " Found #{high_value_tech['data']&.length || 0} high-value tech companies"
|
43
|
+
|
44
|
+
# 3. Query with date range filters
|
45
|
+
puts "\n3. Finding recently created records..."
|
46
|
+
recent_date = (Date.today - 30).iso8601
|
47
|
+
recent_records = client.records.list(
|
48
|
+
object: "people",
|
49
|
+
filters: {
|
50
|
+
created_at: { greater_than: recent_date },
|
51
|
+
},
|
52
|
+
sorts: [
|
53
|
+
{ field: "created_at", direction: "desc" },
|
54
|
+
]
|
55
|
+
)
|
56
|
+
puts " Found #{recent_records['data']&.length || 0} people created in last 30 days"
|
57
|
+
|
58
|
+
# 4. Query with relationship filters
|
59
|
+
puts "\n4. Finding people associated with specific companies..."
|
60
|
+
# First, get a company
|
61
|
+
companies = client.records.list(object: "companies", limit: 1)
|
62
|
+
if companies.dig("data", 0)
|
63
|
+
company_id = companies.dig("data", 0, "id", "record_id")
|
64
|
+
|
65
|
+
people_at_company = client.records.list(
|
66
|
+
object: "people",
|
67
|
+
filters: {
|
68
|
+
company: {
|
69
|
+
target_object: "companies",
|
70
|
+
target_record_id: company_id,
|
71
|
+
},
|
72
|
+
}
|
73
|
+
)
|
74
|
+
puts " Found #{people_at_company['data']&.length || 0} people at the company"
|
75
|
+
else
|
76
|
+
puts " No companies found for demo"
|
77
|
+
end
|
78
|
+
|
79
|
+
# 5. Query with null/not null filters
|
80
|
+
puts "\n5. Finding records with missing data..."
|
81
|
+
missing_email = client.records.list(
|
82
|
+
object: "people",
|
83
|
+
filters: {
|
84
|
+
email: { is_null: true },
|
85
|
+
},
|
86
|
+
limit: 10
|
87
|
+
)
|
88
|
+
puts " Found #{missing_email['data']&.length || 0} people without email addresses"
|
89
|
+
|
90
|
+
# 6. Complex sorting with multiple fields
|
91
|
+
puts "\n6. Sorting by multiple criteria..."
|
92
|
+
sorted_companies = client.records.list(
|
93
|
+
object: "companies",
|
94
|
+
sorts: [
|
95
|
+
{ field: "industry", direction: "asc" },
|
96
|
+
{ field: "annual_revenue", direction: "desc" },
|
97
|
+
{ field: "name", direction: "asc" },
|
98
|
+
],
|
99
|
+
limit: 20
|
100
|
+
)
|
101
|
+
puts " Retrieved #{sorted_companies['data']&.length || 0} companies sorted by industry, revenue, and name"
|
102
|
+
|
103
|
+
# 7. Pagination example
|
104
|
+
puts "\n7. Paginating through results..."
|
105
|
+
page_size = 5
|
106
|
+
total_fetched = 0
|
107
|
+
cursor = nil
|
108
|
+
|
109
|
+
3.times do |page|
|
110
|
+
params = {
|
111
|
+
object: "people",
|
112
|
+
limit: page_size,
|
113
|
+
}
|
114
|
+
params[:cursor] = cursor if cursor
|
115
|
+
|
116
|
+
page_results = client.records.list(**params)
|
117
|
+
fetched = page_results["data"]&.length || 0
|
118
|
+
total_fetched += fetched
|
119
|
+
|
120
|
+
puts " Page #{page + 1}: fetched #{fetched} records"
|
121
|
+
|
122
|
+
cursor = page_results.dig("pagination", "next_cursor")
|
123
|
+
break unless cursor
|
124
|
+
end
|
125
|
+
puts " Total fetched across pages: #{total_fetched}"
|
126
|
+
|
127
|
+
# 8. Query tasks with status filter
|
128
|
+
puts "\n8. Finding pending tasks..."
|
129
|
+
pending_tasks = client.tasks.list(
|
130
|
+
status: "pending",
|
131
|
+
limit: 10
|
132
|
+
)
|
133
|
+
puts " Found #{pending_tasks['data']&.length || 0} pending tasks"
|
134
|
+
|
135
|
+
# 9. Query with custom field filters
|
136
|
+
puts "\n9. Filtering by custom fields..."
|
137
|
+
# This assumes you have custom fields set up
|
138
|
+
client.records.list(
|
139
|
+
object: "people",
|
140
|
+
filters: {
|
141
|
+
# Replace with your actual custom field API slug
|
142
|
+
# custom_field: { equals: "some_value" }
|
143
|
+
},
|
144
|
+
limit: 10
|
145
|
+
)
|
146
|
+
puts " Custom field filtering available for your specific schema"
|
147
|
+
|
148
|
+
# 10. Export query for analysis
|
149
|
+
puts "\n10. Exporting query results..."
|
150
|
+
export_data = client.records.list(
|
151
|
+
object: "companies",
|
152
|
+
filters: {
|
153
|
+
industry: { not_null: true },
|
154
|
+
},
|
155
|
+
limit: 100
|
156
|
+
)
|
157
|
+
|
158
|
+
if export_data["data"] && !export_data["data"].empty?
|
159
|
+
# Simple CSV-like export
|
160
|
+
puts " Sample export (first 3 records):"
|
161
|
+
export_data["data"].take(3).each do |record|
|
162
|
+
name = record.dig("values", "name", 0, "value") || "N/A"
|
163
|
+
industry = record.dig("values", "industry", 0, "value") || "N/A"
|
164
|
+
puts " - #{name}: #{industry}"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
puts "\n#{'=' * 40}"
|
169
|
+
puts "Example completed successfully!"
|
170
|
+
puts "\nThis example demonstrated:"
|
171
|
+
puts " โข Simple and complex filtering"
|
172
|
+
puts " โข Multi-field sorting"
|
173
|
+
puts " โข Date range queries"
|
174
|
+
puts " โข Relationship filters"
|
175
|
+
puts " โข Null/not-null checks"
|
176
|
+
puts " โข Pagination"
|
177
|
+
puts " โข Task filtering"
|
178
|
+
puts " โข Custom field queries"
|
@@ -0,0 +1,110 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "attio"
|
6
|
+
|
7
|
+
# Basic usage example for the Attio Ruby gem
|
8
|
+
#
|
9
|
+
# This example demonstrates:
|
10
|
+
# - Client initialization
|
11
|
+
# - Working with records (people, companies)
|
12
|
+
# - Creating relationships between records
|
13
|
+
# - Error handling
|
14
|
+
|
15
|
+
# Initialize the client with your API key
|
16
|
+
# You can get your API key from: https://app.attio.com/settings/api-keys
|
17
|
+
client = Attio.client(api_key: ENV.fetch("ATTIO_API_KEY"))
|
18
|
+
|
19
|
+
puts "๐ Attio Ruby Client - Basic Usage Example"
|
20
|
+
puts "=" * 50
|
21
|
+
|
22
|
+
begin
|
23
|
+
# List all available objects in your workspace
|
24
|
+
puts "\n๐ Available Objects:"
|
25
|
+
objects = client.objects.list
|
26
|
+
objects["data"].each do |object|
|
27
|
+
puts " - #{object['name']} (#{object['id']})"
|
28
|
+
end
|
29
|
+
|
30
|
+
# Working with People records
|
31
|
+
puts "\n๐ฅ Working with People:"
|
32
|
+
|
33
|
+
# List existing people (first 5)
|
34
|
+
people = client.records.list(object: "people", limit: 5)
|
35
|
+
puts " Found #{people['data'].length} people records"
|
36
|
+
|
37
|
+
# Create a new person
|
38
|
+
new_person = client.records.create(
|
39
|
+
object: "people",
|
40
|
+
data: {
|
41
|
+
name: "John Doe",
|
42
|
+
email: "john.doe@example.com",
|
43
|
+
phone: "+1-555-0123",
|
44
|
+
title: "Software Engineer",
|
45
|
+
}
|
46
|
+
)
|
47
|
+
puts " โ
Created person: #{new_person['data']['name']} (ID: #{new_person['data']['id']})"
|
48
|
+
|
49
|
+
# Update the person
|
50
|
+
updated_person = client.records.update(
|
51
|
+
object: "people",
|
52
|
+
id: new_person["data"]["id"],
|
53
|
+
data: { title: "Senior Software Engineer" }
|
54
|
+
)
|
55
|
+
puts " โ
Updated title to: #{updated_person['data']['title']}"
|
56
|
+
|
57
|
+
# Working with Companies
|
58
|
+
puts "\n๐ข Working with Companies:"
|
59
|
+
|
60
|
+
# Create a company
|
61
|
+
new_company = client.records.create(
|
62
|
+
object: "companies",
|
63
|
+
data: {
|
64
|
+
name: "Acme Corp",
|
65
|
+
domain: "acme.com",
|
66
|
+
employee_count: 100,
|
67
|
+
description: "Leading provider of innovative solutions",
|
68
|
+
}
|
69
|
+
)
|
70
|
+
puts " โ
Created company: #{new_company['data']['name']}"
|
71
|
+
|
72
|
+
# Link person to company (create relationship)
|
73
|
+
# Note: This requires the person and company to have a relationship field configured
|
74
|
+
puts "\n๐ Creating Relationships:"
|
75
|
+
# This would typically be done through a reference field
|
76
|
+
# The exact implementation depends on your Attio workspace configuration
|
77
|
+
|
78
|
+
# Working with Lists
|
79
|
+
puts "\n๐ Working with Lists:"
|
80
|
+
lists = client.lists.list(limit: 5)
|
81
|
+
if lists["data"].any?
|
82
|
+
first_list = lists["data"].first
|
83
|
+
puts " Found list: #{first_list['name']}"
|
84
|
+
|
85
|
+
# Get entries in the list
|
86
|
+
entries = client.lists.entries(id: first_list["id"], limit: 5)
|
87
|
+
puts " List has #{entries['data'].length} entries"
|
88
|
+
else
|
89
|
+
puts " No lists found in workspace"
|
90
|
+
end
|
91
|
+
|
92
|
+
# Cleanup - Delete the test records
|
93
|
+
puts "\n๐งน Cleaning up test data:"
|
94
|
+
client.records.delete(object: "people", id: new_person["data"]["id"])
|
95
|
+
puts " โ
Deleted test person record"
|
96
|
+
|
97
|
+
client.records.delete(object: "companies", id: new_company["data"]["id"])
|
98
|
+
puts " โ
Deleted test company record"
|
99
|
+
rescue Attio::AuthenticationError => e
|
100
|
+
puts "โ Authentication failed: #{e.message}"
|
101
|
+
puts " Please check your API key"
|
102
|
+
rescue Attio::NotFoundError => e
|
103
|
+
puts "โ Resource not found: #{e.message}"
|
104
|
+
rescue Attio::ValidationError => e
|
105
|
+
puts "โ Validation error: #{e.message}"
|
106
|
+
rescue Attio::Error => e
|
107
|
+
puts "โ API error: #{e.message}"
|
108
|
+
end
|
109
|
+
|
110
|
+
puts "\nโจ Example completed!"
|