attio-ts-sdk 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright 2026 Harold Martin <harold.martin@gmail.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,411 @@
1
+ # Attio CRM TypeScript SDK
2
+
3
+ A modern, type-safe TypeScript SDK for the [Attio](https://attio.com) CRM API. Built with Zod v4 and a new Attio‑aware client layer that adds retries, error normalization, caching, and higher‑level helpers on top of the generated OpenAPI client.
4
+
5
+ - **Create an Attio client in one line** (`createAttioClient({ apiKey })`)
6
+ - **Retry & rate‑limit aware** (exponential backoff + `Retry-After`)
7
+ - **Normalized errors** (consistent shape + optional suggestions for select/status mismatches)
8
+ - **Record normalization** (handles inconsistent response shapes)
9
+ - **Metadata caching** (attributes, select options, statuses)
10
+ - **Pagination helpers** (`paginate` + cursor handling)
11
+
12
+ You still have full access to the generated, spec‑accurate endpoints.
13
+
14
+ ## Features
15
+
16
+ - **Full Attio API Coverage** - People, companies, lists, notes, tasks, meetings, webhooks, and more
17
+ - **Runtime Validation** - Every request and response validated with Zod v4 schemas
18
+ - **Tiny Bundle** - Browser build under 3.5KB gzipped
19
+ - **Tree-Shakeable** - Import only what you need
20
+ - **Isomorphic** - Works in Node.js, Bun, Deno, and browsers
21
+ - **TypeScript First** - Complete type definitions generated from OpenAPI spec
22
+ - **Attio-Aware Client** - Retries, normalized errors, caching, helpers
23
+ - **Zero Config** - Sensible defaults, just add your API key
24
+
25
+ ## Installing
26
+
27
+ ```bash
28
+ # pnpm (recommended)
29
+ pnpm add attio-ts-sdk zod
30
+
31
+ # npm
32
+ npm install attio-ts-sdk zod
33
+
34
+ # yarn
35
+ yarn add attio-ts-sdk zod
36
+
37
+ # bun
38
+ bun add attio-ts-sdk zod
39
+ ```
40
+
41
+ > **Note:** Zod v4 is a peer dependency - install it alongside the SDK.
42
+
43
+ ## Usage
44
+
45
+ This SDK provides two layers:
46
+
47
+ 1) **Attio helpers** (recommended): `createAttioClient`, `createRecord`, `queryRecords`, etc.
48
+ 2) **Generated endpoints**: `getV2Objects`, `postV2ObjectsByObjectRecordsQuery`, etc.
49
+
50
+ ### Quick Start
51
+
52
+ ```typescript
53
+ import { createAttioClient, getV2Objects, postV2ObjectsByObjectRecordsQuery } from 'attio-ts-sdk';
54
+
55
+ // Configure the client with your API key
56
+ const client = createAttioClient({
57
+ apiKey: process.env.ATTIO_API_KEY,
58
+ });
59
+
60
+ // List all objects in your workspace
61
+ const { data: objects } = await getV2Objects({ client });
62
+ console.log(objects);
63
+
64
+ // Query people records
65
+ const { data: people } = await postV2ObjectsByObjectRecordsQuery({
66
+ client,
67
+ path: { object: 'people' },
68
+ body: {
69
+ limit: 10,
70
+ sorts: [{ attribute: 'created_at', direction: 'desc' }],
71
+ },
72
+ });
73
+ ```
74
+
75
+ ### Attio Convenience Layer
76
+
77
+ The Attio helpers wrap the generated endpoints with retries, error normalization,
78
+ record normalization, and opinionated defaults.
79
+
80
+ ```typescript
81
+ import { createAttioClient, createRecord, listLists, searchRecords } from 'attio-ts-sdk';
82
+
83
+ const client = createAttioClient({ apiKey: process.env.ATTIO_API_KEY });
84
+
85
+ const lists = await listLists({ client });
86
+
87
+ const company = await createRecord({
88
+ client,
89
+ object: 'companies',
90
+ values: {
91
+ name: [{ value: 'Acme Corp' }],
92
+ domains: [{ domain: 'acme.com' }],
93
+ },
94
+ });
95
+
96
+ const matches = await searchRecords({
97
+ client,
98
+ query: 'acme.com',
99
+ objects: ['companies'],
100
+ });
101
+ ```
102
+
103
+ ### Client Configuration
104
+
105
+ ```typescript
106
+ import { createAttioClient } from 'attio-ts-sdk';
107
+
108
+ const client = createAttioClient({
109
+ apiKey: process.env.ATTIO_API_KEY,
110
+ baseUrl: 'https://api.attio.com',
111
+ timeoutMs: 20_000,
112
+ retry: { maxRetries: 4 },
113
+ cache: { enabled: true },
114
+ });
115
+ ```
116
+
117
+ ### Error Handling
118
+
119
+ Errors are normalized to `AttioError` / `AttioApiError` / `AttioNetworkError`.
120
+
121
+ ```typescript
122
+ import { createAttioClient, createRecord, AttioError } from 'attio-ts-sdk';
123
+
124
+ const client = createAttioClient({ apiKey: process.env.ATTIO_API_KEY });
125
+
126
+ try {
127
+ await createRecord({
128
+ client,
129
+ object: 'companies',
130
+ values: { stage: [{ value: 'Prospectt' }] },
131
+ });
132
+ } catch (err) {
133
+ const error = err as AttioError;
134
+ console.log(error.status, error.code, error.requestId, error.suggestions);
135
+ }
136
+ ```
137
+
138
+ ### Pagination Helpers
139
+
140
+ ```typescript
141
+ import { createAttioClient, paginate, getV2Meetings } from 'attio-ts-sdk';
142
+
143
+ const client = createAttioClient({ apiKey: process.env.ATTIO_API_KEY });
144
+
145
+
146
+ const meetings = await paginate(async (cursor) => {
147
+ const result = await getV2Meetings({
148
+ client,
149
+ query: { cursor },
150
+ });
151
+ return result;
152
+ });
153
+ ```
154
+
155
+ ### Metadata Helpers
156
+
157
+ ```typescript
158
+ import { createAttioClient, getAttributeOptions } from 'attio-ts-sdk';
159
+
160
+ const client = createAttioClient({ apiKey: process.env.ATTIO_API_KEY });
161
+
162
+ const options = await getAttributeOptions({
163
+ client,
164
+ target: 'objects',
165
+ identifier: 'companies',
166
+ attribute: 'stage',
167
+ });
168
+ ```
169
+
170
+ ### Working with Records
171
+
172
+ ```typescript
173
+ import {
174
+ createAttioClient,
175
+ createRecord,
176
+ upsertRecord,
177
+ getRecord,
178
+ deleteRecord,
179
+ } from 'attio-ts-sdk';
180
+
181
+ const client = createAttioClient({ apiKey: process.env.ATTIO_API_KEY });
182
+
183
+ // Create a new company
184
+ const newCompany = await createRecord({
185
+ client,
186
+ object: 'companies',
187
+ values: {
188
+ name: [{ value: 'Acme Corp' }],
189
+ domains: [{ domain: 'acme.com' }],
190
+ },
191
+ });
192
+
193
+ // Upsert a record (create or update based on matching attribute)
194
+ const upserted = await upsertRecord({
195
+ client,
196
+ object: 'companies',
197
+ matchingAttribute: 'domains',
198
+ values: {
199
+ name: [{ value: 'Acme Corp' }],
200
+ domains: [{ domain: 'acme.com' }],
201
+ description: [{ value: 'Updated description' }],
202
+ },
203
+ });
204
+
205
+ // Get a specific record
206
+ const company = await getRecord({
207
+ client,
208
+ object: 'companies',
209
+ recordId: 'abc-123',
210
+ });
211
+
212
+ // Delete a record
213
+ await deleteRecord({
214
+ client,
215
+ object: 'companies',
216
+ recordId: 'abc-123',
217
+ });
218
+ ```
219
+
220
+ ### Using Generated Endpoints Directly
221
+
222
+ You can always call the generated endpoints for full spec coverage:
223
+
224
+ ```typescript
225
+ import { createAttioClient, getV2Objects } from 'attio-ts-sdk';
226
+
227
+ const client = createAttioClient({ apiKey: process.env.ATTIO_API_KEY });
228
+ const { data: objects } = await getV2Objects({ client });
229
+ ```
230
+
231
+ ### Managing Lists
232
+
233
+ ```typescript
234
+ import {
235
+ getV2Lists,
236
+ postV2ListsByListEntriesQuery,
237
+ postV2ListsByListEntries,
238
+ } from 'attio-ts-sdk';
239
+
240
+ // Get all lists
241
+ const { data: lists } = await getV2Lists({ client });
242
+
243
+ // Query entries in a list
244
+ const { data: entries } = await postV2ListsByListEntriesQuery({
245
+ client,
246
+ path: { list: 'sales-pipeline' },
247
+ body: {
248
+ filter: {
249
+ attribute: 'stage',
250
+ value: 'negotiation',
251
+ },
252
+ },
253
+ });
254
+
255
+ // Add a record to a list
256
+ const { data: entry } = await postV2ListsByListEntries({
257
+ client,
258
+ path: { list: 'sales-pipeline' },
259
+ body: {
260
+ data: {
261
+ parent_record_id: 'company-record-id',
262
+ entry_values: {
263
+ stage: [{ status: 'prospecting' }],
264
+ deal_value: [{ currency_value: 50000 }],
265
+ },
266
+ },
267
+ },
268
+ });
269
+ ```
270
+
271
+ ### Notes and Tasks
272
+
273
+ ```typescript
274
+ import { postV2Notes, postV2Tasks, patchV2TasksByTaskId } from 'attio-ts-sdk';
275
+
276
+ // Create a note on a record
277
+ const { data: note } = await postV2Notes({
278
+ client,
279
+ body: {
280
+ data: {
281
+ parent_object: 'companies',
282
+ parent_record_id: 'abc-123',
283
+ title: 'Meeting Notes',
284
+ content: 'Discussed Q4 roadmap...',
285
+ },
286
+ },
287
+ });
288
+
289
+ // Create a task
290
+ const { data: task } = await postV2Tasks({
291
+ client,
292
+ body: {
293
+ data: {
294
+ content: 'Follow up on proposal',
295
+ deadline_at: '2024-12-31T17:00:00Z',
296
+ linked_records: [{ target_object: 'companies', target_record_id: 'abc-123' }],
297
+ },
298
+ },
299
+ });
300
+
301
+ // Mark task as complete
302
+ await patchV2TasksByTaskId({
303
+ client,
304
+ path: { task_id: task.data.id.task_id },
305
+ body: { data: { is_completed: true } },
306
+ });
307
+ ```
308
+
309
+ ### Webhooks
310
+
311
+ ```typescript
312
+ import { postV2Webhooks, getV2Webhooks } from 'attio-ts-sdk';
313
+
314
+ // Create a webhook
315
+ const { data: webhook } = await postV2Webhooks({
316
+ client,
317
+ body: {
318
+ data: {
319
+ target_url: 'https://your-app.com/webhooks/attio',
320
+ subscriptions: [
321
+ { event_type: 'record.created', filter: { object: 'companies' } },
322
+ { event_type: 'record.updated', filter: { object: 'companies' } },
323
+ ],
324
+ },
325
+ },
326
+ });
327
+
328
+ // List all webhooks
329
+ const { data: webhooks } = await getV2Webhooks({ client });
330
+ ```
331
+
332
+ ### Browser Usage
333
+
334
+ For browsers, import from the `/browser` entry point:
335
+
336
+ ```typescript
337
+ import { createClient, getV2Self } from 'attio-ts-sdk/browser';
338
+
339
+ const client = createClient({
340
+ baseUrl: 'https://api.attio.com',
341
+ headers: {
342
+ Authorization: `Bearer ${apiKey}`,
343
+ },
344
+ });
345
+
346
+ const { data: self } = await getV2Self({ client });
347
+ ```
348
+
349
+ ### Error Handling
350
+
351
+ ```typescript
352
+ import { postV2ObjectsByObjectRecords } from 'attio-ts-sdk';
353
+
354
+ const result = await postV2ObjectsByObjectRecords({
355
+ client,
356
+ path: { object: 'companies' },
357
+ body: { data: { values: { name: [{ value: 'Test' }] } } },
358
+ });
359
+
360
+ if (result.error) {
361
+ console.error('API Error:', result.error);
362
+ } else {
363
+ console.log('Created:', result.data);
364
+ }
365
+
366
+ // Or use throwOnError for exceptions
367
+ try {
368
+ const { data } = await postV2ObjectsByObjectRecords({
369
+ client,
370
+ path: { object: 'companies' },
371
+ body: { data: { values: { name: [{ value: 'Test' }] } } },
372
+ throwOnError: true,
373
+ });
374
+ } catch (error) {
375
+ console.error('Request failed:', error);
376
+ }
377
+ ```
378
+
379
+ ## Development
380
+
381
+ ### Tools
382
+
383
+ - **Biome**: lint and format with a single tool
384
+ - **Vitest**: fast tests with coverage and thresholds
385
+ - **Size Limit**: keep bundles tiny, with CI checks
386
+ - **tsdown**: ESM builds for Node and a separate browser bundle
387
+ - **CI**: lint, typecheck, test, coverage, and size comments/badges
388
+ - **Deno-friendly**: `.ts` source imports for direct consumption
389
+ - **OIDC + Provenance**: publish to npm and JSR via manual CI release
390
+
391
+ ### Setup
392
+
393
+ Install dependencies and run scripts:
394
+
395
+ ```bash
396
+ git clone git@github.com:hbmartin/attio-ts-sdk.git
397
+ cd attio-ts-sdk
398
+ pnpm i
399
+ pnpm lint
400
+ pnpm test
401
+ pnpm build
402
+ ```
403
+
404
+ ### Releasing
405
+
406
+ - Merge the automated Release PR created by Release Please
407
+ - Manually run the "Release" workflow to publish to npm and JSR with provenance
408
+
409
+ ## License
410
+
411
+ MIT © Harold Martin