attio 0.1.1 → 0.2.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/ci.yml +39 -15
- data/.github/workflows/coverage.yml +67 -0
- data/.github/workflows/pr_checks.yml +25 -7
- data/.github/workflows/release.yml +27 -13
- data/.github/workflows/tests.yml +67 -0
- data/.rubocop.yml +362 -90
- data/CHANGELOG.md +49 -1
- data/CONCEPTS.md +428 -0
- data/CONTRIBUTING.md +4 -4
- data/Gemfile +8 -5
- data/Gemfile.lock +4 -4
- data/README.md +164 -2
- data/Rakefile +8 -6
- data/attio.gemspec +6 -7
- data/danger/Dangerfile +22 -34
- data/docs/example.rb +30 -29
- 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 +67 -29
- data/lib/attio/connection_pool.rb +26 -14
- data/lib/attio/errors.rb +4 -2
- data/lib/attio/http_client.rb +70 -41
- data/lib/attio/logger.rb +37 -27
- data/lib/attio/resources/attributes.rb +12 -5
- data/lib/attio/resources/base.rb +66 -27
- data/lib/attio/resources/comments.rb +147 -0
- data/lib/attio/resources/lists.rb +21 -24
- data/lib/attio/resources/notes.rb +110 -0
- data/lib/attio/resources/objects.rb +11 -4
- data/lib/attio/resources/records.rb +49 -67
- data/lib/attio/resources/tasks.rb +131 -0
- data/lib/attio/resources/threads.rb +154 -0
- data/lib/attio/resources/users.rb +10 -4
- data/lib/attio/resources/workspaces.rb +9 -1
- data/lib/attio/retry_handler.rb +19 -11
- data/lib/attio/version.rb +3 -1
- data/lib/attio.rb +15 -9
- metadata +13 -18
- data/run_tests.rb +0 -52
- data/test_basic.rb +0 -51
- data/test_typhoeus.rb +0 -31
@@ -0,0 +1,173 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "attio"
|
5
|
+
require "time"
|
6
|
+
|
7
|
+
# Example: Collaboration Features (Comments, Threads, Tasks, Notes)
|
8
|
+
#
|
9
|
+
# This example demonstrates how to use Attio's collaboration features
|
10
|
+
# to manage team communication and tasks on customer records.
|
11
|
+
|
12
|
+
# Initialize the client
|
13
|
+
client = Attio.client(api_key: ENV.fetch("ATTIO_API_KEY"))
|
14
|
+
|
15
|
+
puts "Attio Collaboration Features Example"
|
16
|
+
puts "=" * 40
|
17
|
+
|
18
|
+
# 1. Create a company and contact for our example
|
19
|
+
puts "\n1. Creating sample company and contact..."
|
20
|
+
company = client.records.create(
|
21
|
+
object: "companies",
|
22
|
+
data: {
|
23
|
+
name: "TechCorp Solutions",
|
24
|
+
domain: "techcorp.example.com",
|
25
|
+
industry: "Software Development",
|
26
|
+
}
|
27
|
+
)
|
28
|
+
puts " ✓ Created company: #{company.dig('data', 'values', 'name', 0, 'value')}"
|
29
|
+
|
30
|
+
contact = client.records.create(
|
31
|
+
object: "people",
|
32
|
+
data: {
|
33
|
+
name: "Sarah Johnson",
|
34
|
+
email: "sarah@techcorp.example.com",
|
35
|
+
title: "VP of Engineering",
|
36
|
+
}
|
37
|
+
)
|
38
|
+
puts " ✓ Created contact: #{contact.dig('data', 'values', 'name', 0, 'value')}"
|
39
|
+
|
40
|
+
company_id = company.dig("data", "id", "record_id")
|
41
|
+
contact_id = contact.dig("data", "id", "record_id")
|
42
|
+
|
43
|
+
# 2. Create a thread for discussion
|
44
|
+
puts "\n2. Creating a discussion thread..."
|
45
|
+
thread = client.threads.create(
|
46
|
+
parent_object: "companies",
|
47
|
+
parent_record_id: company_id,
|
48
|
+
title: "Q1 2025 Contract Renewal Discussion",
|
49
|
+
description: "Thread to track all discussions related to the Q1 2025 contract renewal"
|
50
|
+
)
|
51
|
+
thread_id = thread.dig("data", "id", "thread_id")
|
52
|
+
puts " ✓ Created thread: #{thread.dig('data', 'title')}"
|
53
|
+
|
54
|
+
# 3. Add comments to the thread
|
55
|
+
puts "\n3. Adding comments to the thread..."
|
56
|
+
client.comments.create(
|
57
|
+
thread_id: thread_id,
|
58
|
+
content: "Initial meeting scheduled for next Monday. Key topics:\n\n" \
|
59
|
+
"- Review current usage metrics\n" \
|
60
|
+
"- Discuss expansion opportunities\n" \
|
61
|
+
"- Address any concerns"
|
62
|
+
)
|
63
|
+
puts " ✓ Added initial comment"
|
64
|
+
|
65
|
+
comment2 = client.comments.create(
|
66
|
+
thread_id: thread_id,
|
67
|
+
content: "Sarah confirmed attendance. She mentioned interest in our new API features."
|
68
|
+
)
|
69
|
+
puts " ✓ Added follow-up comment"
|
70
|
+
|
71
|
+
# 4. React to a comment
|
72
|
+
puts "\n4. Adding reactions to comments..."
|
73
|
+
client.comments.react(id: comment2.dig("data", "id", "comment_id"), emoji: "👍")
|
74
|
+
puts " ✓ Added 👍 reaction"
|
75
|
+
|
76
|
+
# 5. Create tasks
|
77
|
+
puts "\n5. Creating tasks..."
|
78
|
+
task1 = client.tasks.create(
|
79
|
+
parent_object: "companies",
|
80
|
+
parent_record_id: company_id,
|
81
|
+
title: "Prepare renewal proposal",
|
82
|
+
due_date: (Date.today + 7).iso8601,
|
83
|
+
description: "Create comprehensive renewal proposal including pricing and new features"
|
84
|
+
)
|
85
|
+
puts " ✓ Created task: #{task1.dig('data', 'title')}"
|
86
|
+
|
87
|
+
task2 = client.tasks.create(
|
88
|
+
parent_object: "people",
|
89
|
+
parent_record_id: contact_id,
|
90
|
+
title: "Schedule follow-up call",
|
91
|
+
due_date: (Date.today + 14).iso8601
|
92
|
+
)
|
93
|
+
puts " ✓ Created task: #{task2.dig('data', 'title')}"
|
94
|
+
|
95
|
+
# 6. Create meeting notes
|
96
|
+
puts "\n6. Creating meeting notes..."
|
97
|
+
client.notes.create(
|
98
|
+
parent_object: "companies",
|
99
|
+
parent_record_id: company_id,
|
100
|
+
title: "Contract Renewal Meeting - #{Date.today}",
|
101
|
+
content: <<~CONTENT
|
102
|
+
## Attendees
|
103
|
+
- Sarah Johnson (TechCorp)
|
104
|
+
- Our team: Sales, Customer Success
|
105
|
+
|
106
|
+
## Key Points Discussed
|
107
|
+
1. Current contract value: $50,000/year
|
108
|
+
2. Usage has grown 40% in last quarter
|
109
|
+
3. Interest in API expansion package
|
110
|
+
|
111
|
+
## Action Items
|
112
|
+
- [ ] Send updated pricing proposal by EOW
|
113
|
+
- [ ] Schedule technical demo for API features
|
114
|
+
- [ ] Review SLA requirements
|
115
|
+
|
116
|
+
## Next Steps
|
117
|
+
Follow-up call scheduled for next week
|
118
|
+
CONTENT
|
119
|
+
)
|
120
|
+
puts " ✓ Created meeting notes"
|
121
|
+
|
122
|
+
# 7. List all collaboration items
|
123
|
+
puts "\n7. Listing collaboration items..."
|
124
|
+
|
125
|
+
# List threads
|
126
|
+
threads = client.threads.list(
|
127
|
+
parent_object: "companies",
|
128
|
+
parent_record_id: company_id
|
129
|
+
)
|
130
|
+
puts " Threads on company: #{threads['data']&.length || 0}"
|
131
|
+
|
132
|
+
# List comments in thread
|
133
|
+
comments = client.comments.list(thread_id: thread_id)
|
134
|
+
puts " Comments in thread: #{comments['data']&.length || 0}"
|
135
|
+
|
136
|
+
# List tasks
|
137
|
+
all_tasks = client.tasks.list
|
138
|
+
puts " Total tasks: #{all_tasks['data']&.length || 0}"
|
139
|
+
|
140
|
+
# List notes
|
141
|
+
notes = client.notes.list(
|
142
|
+
parent_object: "companies",
|
143
|
+
parent_record_id: company_id
|
144
|
+
)
|
145
|
+
puts " Notes on company: #{notes['data']&.length || 0}"
|
146
|
+
|
147
|
+
# 8. Update task status
|
148
|
+
puts "\n8. Updating task status..."
|
149
|
+
client.tasks.complete(
|
150
|
+
id: task1.dig("data", "id", "task_id"),
|
151
|
+
completed_at: Time.now.iso8601
|
152
|
+
)
|
153
|
+
puts " ✓ Marked task as complete"
|
154
|
+
|
155
|
+
# 9. Close the thread
|
156
|
+
puts "\n9. Closing the discussion thread..."
|
157
|
+
client.threads.close(id: thread_id)
|
158
|
+
puts " ✓ Thread closed"
|
159
|
+
|
160
|
+
puts "\n#{'=' * 40}"
|
161
|
+
puts "Example completed successfully!"
|
162
|
+
puts "\nThis example demonstrated:"
|
163
|
+
puts " • Creating and managing discussion threads"
|
164
|
+
puts " • Adding comments and reactions"
|
165
|
+
puts " • Creating and completing tasks"
|
166
|
+
puts " • Creating detailed meeting notes"
|
167
|
+
puts " • Listing collaboration items"
|
168
|
+
|
169
|
+
# Clean up (optional - uncomment to delete created records)
|
170
|
+
# puts "\nCleaning up..."
|
171
|
+
# client.records.delete(object: "companies", id: company_id)
|
172
|
+
# client.records.delete(object: "people", id: contact_id)
|
173
|
+
# puts " ✓ Cleanup complete"
|
@@ -0,0 +1,348 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "attio"
|
5
|
+
require "time"
|
6
|
+
|
7
|
+
# Example: Complete CRM Workflow
|
8
|
+
#
|
9
|
+
# This example demonstrates a complete CRM workflow including:
|
10
|
+
# - Creating and managing companies and contacts
|
11
|
+
# - Working with lists and workspace management
|
12
|
+
# - Using collaboration features
|
13
|
+
# - Error handling
|
14
|
+
|
15
|
+
# Initialize the client
|
16
|
+
client = Attio.client(api_key: ENV.fetch("ATTIO_API_KEY"))
|
17
|
+
|
18
|
+
puts "Attio Complete CRM Workflow Example"
|
19
|
+
puts "=" * 40
|
20
|
+
|
21
|
+
# Error handling wrapper
|
22
|
+
def safe_execute(description)
|
23
|
+
print "#{description}..."
|
24
|
+
result = yield
|
25
|
+
puts " ✓"
|
26
|
+
result
|
27
|
+
rescue Attio::NotFoundError => e
|
28
|
+
puts " ✗ Not found: #{e.message}"
|
29
|
+
nil
|
30
|
+
rescue Attio::ValidationError => e
|
31
|
+
puts " ✗ Validation error: #{e.message}"
|
32
|
+
nil
|
33
|
+
rescue Attio::Error => e
|
34
|
+
puts " ✗ Error: #{e.message}"
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
|
38
|
+
# 1. Get workspace information
|
39
|
+
puts "\n1. Workspace Information"
|
40
|
+
puts "-" * 20
|
41
|
+
workspace = safe_execute("Getting current workspace") do
|
42
|
+
client.workspaces.get
|
43
|
+
end
|
44
|
+
|
45
|
+
if workspace
|
46
|
+
puts " Workspace: #{workspace.dig('data', 'name')}"
|
47
|
+
puts " ID: #{workspace.dig('data', 'id', 'workspace_id')}"
|
48
|
+
end
|
49
|
+
|
50
|
+
# 2. List available objects and attributes
|
51
|
+
puts "\n2. Schema Information"
|
52
|
+
puts "-" * 20
|
53
|
+
objects = safe_execute("Listing objects") do
|
54
|
+
client.objects.list
|
55
|
+
end
|
56
|
+
|
57
|
+
if objects && objects["data"]
|
58
|
+
puts " Available objects:"
|
59
|
+
objects["data"].each do |obj|
|
60
|
+
puts " - #{obj['api_slug']}: #{obj['name']}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# 3. Create a sales pipeline workflow
|
65
|
+
puts "\n3. Sales Pipeline Setup"
|
66
|
+
puts "-" * 20
|
67
|
+
|
68
|
+
# Create a company
|
69
|
+
company = safe_execute("Creating prospect company") do
|
70
|
+
client.records.create(
|
71
|
+
object: "companies",
|
72
|
+
data: {
|
73
|
+
name: "Innovation Labs Inc",
|
74
|
+
domain: "innovationlabs.example.com",
|
75
|
+
industry: "Technology",
|
76
|
+
description: "Potential enterprise customer",
|
77
|
+
}
|
78
|
+
)
|
79
|
+
end
|
80
|
+
company_id = company&.dig("data", "id", "record_id")
|
81
|
+
|
82
|
+
# Create primary contact
|
83
|
+
contact = safe_execute("Creating primary contact") do
|
84
|
+
client.records.create(
|
85
|
+
object: "people",
|
86
|
+
data: {
|
87
|
+
name: "Michael Chen",
|
88
|
+
email: "m.chen@innovationlabs.example.com",
|
89
|
+
title: "CTO",
|
90
|
+
phone: "+1-555-0123",
|
91
|
+
}
|
92
|
+
)
|
93
|
+
end
|
94
|
+
contact&.dig("data", "id", "record_id")
|
95
|
+
|
96
|
+
# Create additional contacts
|
97
|
+
if company_id
|
98
|
+
safe_execute("Creating additional contact") do
|
99
|
+
client.records.create(
|
100
|
+
object: "people",
|
101
|
+
data: {
|
102
|
+
name: "Lisa Park",
|
103
|
+
email: "l.park@innovationlabs.example.com",
|
104
|
+
title: "VP of Product",
|
105
|
+
}
|
106
|
+
)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# 4. Create and manage lists
|
111
|
+
puts "\n4. List Management"
|
112
|
+
puts "-" * 20
|
113
|
+
|
114
|
+
lists = safe_execute("Getting available lists") do
|
115
|
+
client.lists.list
|
116
|
+
end
|
117
|
+
|
118
|
+
if lists && lists["data"] && !lists["data"].empty?
|
119
|
+
list_id = lists["data"].first["id"]["list_id"]
|
120
|
+
|
121
|
+
# Add company to a list
|
122
|
+
if company_id
|
123
|
+
safe_execute("Adding company to list") do
|
124
|
+
client.lists.create_entry(
|
125
|
+
id: list_id,
|
126
|
+
data: {
|
127
|
+
record_id: company_id,
|
128
|
+
notes: "High priority prospect",
|
129
|
+
}
|
130
|
+
)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Get list entries
|
135
|
+
entries = safe_execute("Getting list entries") do
|
136
|
+
client.lists.entries(id: list_id, limit: 5)
|
137
|
+
end
|
138
|
+
|
139
|
+
puts " List has #{entries['data']&.length || 0} entries" if entries
|
140
|
+
end
|
141
|
+
|
142
|
+
# 5. Collaboration workflow
|
143
|
+
puts "\n5. Collaboration Workflow"
|
144
|
+
puts "-" * 20
|
145
|
+
|
146
|
+
if company_id
|
147
|
+
# Create a discussion thread
|
148
|
+
thread = safe_execute("Creating sales discussion thread") do
|
149
|
+
client.threads.create(
|
150
|
+
parent_object: "companies",
|
151
|
+
parent_record_id: company_id,
|
152
|
+
title: "Sales Opportunity - Innovation Labs",
|
153
|
+
description: "Track all sales activities and discussions"
|
154
|
+
)
|
155
|
+
end
|
156
|
+
thread_id = thread&.dig("data", "id", "thread_id")
|
157
|
+
|
158
|
+
# Add initial comment
|
159
|
+
if thread_id
|
160
|
+
safe_execute("Adding sales strategy comment") do
|
161
|
+
client.comments.create(
|
162
|
+
thread_id: thread_id,
|
163
|
+
content: <<~CONTENT
|
164
|
+
## Opportunity Overview
|
165
|
+
- **Company**: Innovation Labs Inc
|
166
|
+
- **Potential Value**: $100K ARR
|
167
|
+
- **Timeline**: Q1 2025
|
168
|
+
|
169
|
+
## Next Steps
|
170
|
+
1. Schedule discovery call
|
171
|
+
2. Prepare custom demo
|
172
|
+
3. Send pricing proposal
|
173
|
+
CONTENT
|
174
|
+
)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# Create tasks
|
179
|
+
safe_execute("Creating discovery call task") do
|
180
|
+
client.tasks.create(
|
181
|
+
parent_object: "companies",
|
182
|
+
parent_record_id: company_id,
|
183
|
+
title: "Schedule discovery call with Michael Chen",
|
184
|
+
due_date: (Date.today + 3).iso8601,
|
185
|
+
description: "Initial discovery call to understand their requirements"
|
186
|
+
)
|
187
|
+
end
|
188
|
+
|
189
|
+
safe_execute("Creating demo prep task") do
|
190
|
+
client.tasks.create(
|
191
|
+
parent_object: "companies",
|
192
|
+
parent_record_id: company_id,
|
193
|
+
title: "Prepare customized product demo",
|
194
|
+
due_date: (Date.today + 7).iso8601
|
195
|
+
)
|
196
|
+
end
|
197
|
+
|
198
|
+
# Create meeting notes
|
199
|
+
safe_execute("Creating initial contact notes") do
|
200
|
+
client.notes.create(
|
201
|
+
parent_object: "companies",
|
202
|
+
parent_record_id: company_id,
|
203
|
+
title: "Initial Contact - #{Date.today}",
|
204
|
+
content: <<~CONTENT
|
205
|
+
## Contact Method
|
206
|
+
Inbound inquiry via website
|
207
|
+
|
208
|
+
## Requirements
|
209
|
+
- Looking for enterprise CRM solution
|
210
|
+
- Team size: 200+ employees
|
211
|
+
- Current solution: Spreadsheets
|
212
|
+
|
213
|
+
## Pain Points
|
214
|
+
- No centralized customer data
|
215
|
+
- Manual reporting processes
|
216
|
+
- Limited collaboration features
|
217
|
+
|
218
|
+
## Budget
|
219
|
+
Approved budget: $100-150K annually
|
220
|
+
|
221
|
+
## Decision Timeline
|
222
|
+
Looking to implement in Q1 2025
|
223
|
+
CONTENT
|
224
|
+
)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# 6. Query and reporting
|
229
|
+
puts "\n6. Queries and Reporting"
|
230
|
+
puts "-" * 20
|
231
|
+
|
232
|
+
# Get all high-priority tasks
|
233
|
+
tasks = safe_execute("Getting pending tasks") do
|
234
|
+
client.tasks.list(status: "pending", limit: 5)
|
235
|
+
end
|
236
|
+
|
237
|
+
if tasks
|
238
|
+
puts " Pending tasks: #{tasks['data']&.length || 0}"
|
239
|
+
tasks["data"]&.each do |task|
|
240
|
+
puts " - #{task['title']}"
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# Query recent companies
|
245
|
+
recent_companies = safe_execute("Finding recent companies") do
|
246
|
+
client.records.list(
|
247
|
+
object: "companies",
|
248
|
+
sorts: [{ field: "created_at", direction: "desc" }],
|
249
|
+
limit: 5
|
250
|
+
)
|
251
|
+
end
|
252
|
+
|
253
|
+
puts " Recent companies: #{recent_companies['data']&.length || 0}" if recent_companies
|
254
|
+
|
255
|
+
# 7. User management
|
256
|
+
puts "\n7. User Information"
|
257
|
+
puts "-" * 20
|
258
|
+
|
259
|
+
# Get current user
|
260
|
+
me = safe_execute("Getting current user") do
|
261
|
+
client.users.me
|
262
|
+
end
|
263
|
+
|
264
|
+
if me
|
265
|
+
puts " Current user: #{me.dig('data', 'name')}"
|
266
|
+
puts " Email: #{me.dig('data', 'email')}"
|
267
|
+
end
|
268
|
+
|
269
|
+
# List all users
|
270
|
+
users = safe_execute("Listing workspace users") do
|
271
|
+
client.users.list
|
272
|
+
end
|
273
|
+
|
274
|
+
puts " Total users: #{users['data']&.length || 0}" if users
|
275
|
+
|
276
|
+
# 8. Advanced features
|
277
|
+
puts "\n8. Advanced Features"
|
278
|
+
puts "-" * 20
|
279
|
+
|
280
|
+
# Get custom attributes
|
281
|
+
if company_id
|
282
|
+
attributes = safe_execute("Getting company attributes") do
|
283
|
+
client.attributes.list(object: "companies")
|
284
|
+
end
|
285
|
+
|
286
|
+
puts " Company attributes: #{attributes['data']&.length || 0}" if attributes
|
287
|
+
end
|
288
|
+
|
289
|
+
# Demonstrate pagination
|
290
|
+
puts " Demonstrating pagination..."
|
291
|
+
all_records = []
|
292
|
+
cursor = nil
|
293
|
+
pages = 0
|
294
|
+
|
295
|
+
loop do
|
296
|
+
params = { object: "companies", limit: 2 }
|
297
|
+
params[:cursor] = cursor if cursor
|
298
|
+
|
299
|
+
page = safe_execute(" Fetching page #{pages + 1}") do
|
300
|
+
client.records.list(**params)
|
301
|
+
end
|
302
|
+
|
303
|
+
break unless page && page["data"]
|
304
|
+
|
305
|
+
all_records.concat(page["data"])
|
306
|
+
pages += 1
|
307
|
+
|
308
|
+
cursor = page.dig("pagination", "next_cursor")
|
309
|
+
break unless cursor && pages < 3 # Limit to 3 pages for demo
|
310
|
+
end
|
311
|
+
|
312
|
+
puts " Fetched #{all_records.length} records across #{pages} pages"
|
313
|
+
|
314
|
+
# 9. Summary
|
315
|
+
puts "\n9. Workflow Summary"
|
316
|
+
puts "-" * 20
|
317
|
+
puts " ✓ Workspace configured"
|
318
|
+
puts " ✓ Company and contacts created"
|
319
|
+
puts " ✓ Lists managed"
|
320
|
+
puts " ✓ Collaboration tools utilized"
|
321
|
+
puts " ✓ Tasks and notes created"
|
322
|
+
puts " ✓ Queries executed"
|
323
|
+
puts " ✓ User information retrieved"
|
324
|
+
|
325
|
+
puts "\n#{'=' * 40}"
|
326
|
+
puts "Complete workflow example finished!"
|
327
|
+
puts "\nThis example demonstrated:"
|
328
|
+
puts " • Complete CRM setup"
|
329
|
+
puts " • Record creation and management"
|
330
|
+
puts " • List operations"
|
331
|
+
puts " • Collaboration features"
|
332
|
+
puts " • Task management"
|
333
|
+
puts " • Querying and reporting"
|
334
|
+
puts " • User management"
|
335
|
+
puts " • Error handling"
|
336
|
+
puts " • Pagination"
|
337
|
+
|
338
|
+
# Optional cleanup
|
339
|
+
# if company_id
|
340
|
+
# safe_execute("Cleaning up company") do
|
341
|
+
# client.records.delete(object: "companies", id: company_id)
|
342
|
+
# end
|
343
|
+
# end
|
344
|
+
# if contact_id
|
345
|
+
# safe_execute("Cleaning up contact") do
|
346
|
+
# client.records.delete(object: "people", id: contact_id)
|
347
|
+
# end
|
348
|
+
# end
|