diff --git a/apps/docs/content/docs/en/tools/attio.mdx b/apps/docs/content/docs/en/tools/attio.mdx index 85ad63126b9..5a36922ee42 100644 --- a/apps/docs/content/docs/en/tools/attio.mdx +++ b/apps/docs/content/docs/en/tools/attio.mdx @@ -359,6 +359,35 @@ List tasks in Attio, optionally filtered by record, assignee, or completion stat | ↳ `createdAt` | string | When the task was created | | `count` | number | Number of tasks returned | +### `attio_get_task` + +Get a single task by ID from Attio + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `taskId` | string | Yes | The ID of the task to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `taskId` | string | The task ID | +| `content` | string | The task content | +| `deadlineAt` | string | The task deadline | +| `isCompleted` | boolean | Whether the task is completed | +| `linkedRecords` | array | Records linked to this task | +| ↳ `targetObjectId` | string | The linked object ID | +| ↳ `targetRecordId` | string | The linked record ID | +| `assignees` | array | Task assignees | +| ↳ `type` | string | The assignee actor type \(e.g. workspace-member\) | +| ↳ `id` | string | The assignee actor ID | +| `createdByActor` | object | The actor who created this task | +| ↳ `type` | string | The actor type \(e.g. workspace-member, api-token, system\) | +| ↳ `id` | string | The actor ID | +| `createdAt` | string | When the task was created | + ### `attio_create_task` Create a task in Attio @@ -1012,8 +1041,8 @@ Update a webhook in Attio (target URL and/or subscriptions) | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `webhookId` | string | Yes | The webhook ID to update | -| `targetUrl` | string | Yes | HTTPS target URL for webhook delivery | -| `subscriptions` | string | Yes | JSON array of subscriptions, e.g. \[\{"event_type":"note.created"\}\] | +| `targetUrl` | string | No | HTTPS target URL for webhook delivery | +| `subscriptions` | string | No | JSON array of subscriptions, e.g. \[\{"event_type":"note.created"\}\] | #### Output diff --git a/apps/sim/app/(landing)/integrations/data/integrations.json b/apps/sim/app/(landing)/integrations/data/integrations.json index 6c6120a545c..9062a0b789a 100644 --- a/apps/sim/app/(landing)/integrations/data/integrations.json +++ b/apps/sim/app/(landing)/integrations/data/integrations.json @@ -926,6 +926,10 @@ "name": "List Tasks", "description": "List tasks in Attio, optionally filtered by record, assignee, or completion status" }, + { + "name": "Get Task", + "description": "Get a single task by ID from Attio" + }, { "name": "Create Task", "description": "Create a task in Attio" @@ -1039,7 +1043,7 @@ "description": "Delete a webhook from Attio" } ], - "operationCount": 40, + "operationCount": 41, "triggers": [ { "id": "attio_record_created", @@ -1126,13 +1130,33 @@ "name": "Attio List Entry Deleted", "description": "Trigger workflow when a list entry is deleted in Attio" }, + { + "id": "attio_list_created", + "name": "Attio List Created", + "description": "Trigger workflow when a list is created in Attio" + }, + { + "id": "attio_list_updated", + "name": "Attio List Updated", + "description": "Trigger workflow when a list is updated in Attio" + }, + { + "id": "attio_list_deleted", + "name": "Attio List Deleted", + "description": "Trigger workflow when a list is deleted in Attio" + }, + { + "id": "attio_workspace_member_created", + "name": "Attio Workspace Member Created", + "description": "Trigger workflow when a new member is added to the Attio workspace" + }, { "id": "attio_webhook", "name": "Attio Webhook (All Events)", "description": "Trigger workflow on any Attio webhook event" } ], - "triggerCount": 18, + "triggerCount": 22, "authType": "oauth", "category": "tools", "integrationType": "crm", diff --git a/apps/sim/blocks/blocks/attio.ts b/apps/sim/blocks/blocks/attio.ts index 21ee5ffdf82..9a6af86f6a3 100644 --- a/apps/sim/blocks/blocks/attio.ts +++ b/apps/sim/blocks/blocks/attio.ts @@ -36,6 +36,7 @@ export const AttioBlock: BlockConfig = { { label: 'Create Note', id: 'create_note' }, { label: 'Delete Note', id: 'delete_note' }, { label: 'List Tasks', id: 'list_tasks' }, + { label: 'Get Task', id: 'get_task' }, { label: 'Create Task', id: 'create_task' }, { label: 'Update Task', id: 'update_task' }, { label: 'Delete Task', id: 'delete_task' }, @@ -490,8 +491,8 @@ Return ONLY the JSON array. No explanations, no markdown, no extra text. title: 'Task ID', type: 'short-input', placeholder: 'Enter the task ID', - condition: { field: 'operation', value: ['update_task', 'delete_task'] }, - required: { field: 'operation', value: ['update_task', 'delete_task'] }, + condition: { field: 'operation', value: ['get_task', 'update_task', 'delete_task'] }, + required: { field: 'operation', value: ['get_task', 'update_task', 'delete_task'] }, }, { id: 'taskFilterObject', @@ -944,7 +945,7 @@ YYYY-MM-DDTHH:mm:ss.SSSZ type: 'short-input', placeholder: 'https://example.com/webhook', condition: { field: 'operation', value: ['create_webhook', 'update_webhook'] }, - required: { field: 'operation', value: ['create_webhook', 'update_webhook'] }, + required: { field: 'operation', value: 'create_webhook' }, }, { id: 'webhookSubscriptions', @@ -952,7 +953,7 @@ YYYY-MM-DDTHH:mm:ss.SSSZ type: 'code', placeholder: '[{"event_type":"record.created","filter":{"object_id":"..."}}]', condition: { field: 'operation', value: ['create_webhook', 'update_webhook'] }, - required: { field: 'operation', value: ['create_webhook', 'update_webhook'] }, + required: { field: 'operation', value: 'create_webhook' }, wandConfig: { enabled: true, maintainHistory: true, @@ -1040,6 +1041,10 @@ workspace-member.created ...getTrigger('attio_list_entry_created').subBlocks, ...getTrigger('attio_list_entry_updated').subBlocks, ...getTrigger('attio_list_entry_deleted').subBlocks, + ...getTrigger('attio_list_created').subBlocks, + ...getTrigger('attio_list_updated').subBlocks, + ...getTrigger('attio_list_deleted').subBlocks, + ...getTrigger('attio_workspace_member_created').subBlocks, ...getTrigger('attio_webhook').subBlocks, ], @@ -1063,6 +1068,10 @@ workspace-member.created 'attio_list_entry_created', 'attio_list_entry_updated', 'attio_list_entry_deleted', + 'attio_list_created', + 'attio_list_updated', + 'attio_list_deleted', + 'attio_workspace_member_created', 'attio_webhook', ], }, @@ -1081,6 +1090,7 @@ workspace-member.created 'attio_create_note', 'attio_delete_note', 'attio_list_tasks', + 'attio_get_task', 'attio_create_task', 'attio_update_task', 'attio_delete_task', diff --git a/apps/sim/lib/webhooks/utils.server.ts b/apps/sim/lib/webhooks/utils.server.ts index 3eec55697f4..4decf492eb5 100644 --- a/apps/sim/lib/webhooks/utils.server.ts +++ b/apps/sim/lib/webhooks/utils.server.ts @@ -1311,6 +1311,8 @@ export async function formatWebhookInput( extractAttioCommentData, extractAttioListEntryData, extractAttioListEntryUpdatedData, + extractAttioListData, + extractAttioWorkspaceMemberData, extractAttioGenericData, } = await import('@/triggers/attio/utils') @@ -1341,6 +1343,16 @@ export async function formatWebhookInput( if (triggerId === 'attio_list_entry_created' || triggerId === 'attio_list_entry_deleted') { return extractAttioListEntryData(body) } + if ( + triggerId === 'attio_list_created' || + triggerId === 'attio_list_updated' || + triggerId === 'attio_list_deleted' + ) { + return extractAttioListData(body) + } + if (triggerId === 'attio_workspace_member_created') { + return extractAttioWorkspaceMemberData(body) + } return extractAttioGenericData(body) } diff --git a/apps/sim/tools/attio/assert_record.ts b/apps/sim/tools/attio/assert_record.ts index 3f1414b102c..00864d740a0 100644 --- a/apps/sim/tools/attio/assert_record.ts +++ b/apps/sim/tools/attio/assert_record.ts @@ -49,7 +49,7 @@ export const attioAssertRecordTool: ToolConfig - `https://api.attio.com/v2/objects/${params.objectType}/records?matching_attribute=${params.matchingAttribute}`, + `https://api.attio.com/v2/objects/${params.objectType.trim()}/records?matching_attribute=${params.matchingAttribute.trim()}`, method: 'PUT', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/create_list_entry.ts b/apps/sim/tools/attio/create_list_entry.ts index 381e61e1d7f..c194b3407b0 100644 --- a/apps/sim/tools/attio/create_list_entry.ts +++ b/apps/sim/tools/attio/create_list_entry.ts @@ -53,7 +53,7 @@ export const attioCreateListEntryTool: ToolConfig< }, request: { - url: (params) => `https://api.attio.com/v2/lists/${params.list}/entries`, + url: (params) => `https://api.attio.com/v2/lists/${params.list.trim()}/entries`, method: 'POST', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/create_record.ts b/apps/sim/tools/attio/create_record.ts index 3589c0072c0..4ec2bb13d33 100644 --- a/apps/sim/tools/attio/create_record.ts +++ b/apps/sim/tools/attio/create_record.ts @@ -39,7 +39,7 @@ export const attioCreateRecordTool: ToolConfig `https://api.attio.com/v2/objects/${params.objectType}/records`, + url: (params) => `https://api.attio.com/v2/objects/${params.objectType.trim()}/records`, method: 'POST', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/delete_comment.ts b/apps/sim/tools/attio/delete_comment.ts index 5fc0aed80b1..e78d71e1b33 100644 --- a/apps/sim/tools/attio/delete_comment.ts +++ b/apps/sim/tools/attio/delete_comment.ts @@ -34,7 +34,7 @@ export const attioDeleteCommentTool: ToolConfig< }, request: { - url: (params) => `https://api.attio.com/v2/comments/${params.commentId}`, + url: (params) => `https://api.attio.com/v2/comments/${params.commentId.trim()}`, method: 'DELETE', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/delete_list_entry.ts b/apps/sim/tools/attio/delete_list_entry.ts index 8aede08525d..e46da4d42ee 100644 --- a/apps/sim/tools/attio/delete_list_entry.ts +++ b/apps/sim/tools/attio/delete_list_entry.ts @@ -40,7 +40,8 @@ export const attioDeleteListEntryTool: ToolConfig< }, request: { - url: (params) => `https://api.attio.com/v2/lists/${params.list}/entries/${params.entryId}`, + url: (params) => + `https://api.attio.com/v2/lists/${params.list.trim()}/entries/${params.entryId.trim()}`, method: 'DELETE', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/delete_note.ts b/apps/sim/tools/attio/delete_note.ts index 2980801cc66..bd5cfe1a05d 100644 --- a/apps/sim/tools/attio/delete_note.ts +++ b/apps/sim/tools/attio/delete_note.ts @@ -31,7 +31,7 @@ export const attioDeleteNoteTool: ToolConfig `https://api.attio.com/v2/notes/${params.noteId}`, + url: (params) => `https://api.attio.com/v2/notes/${params.noteId.trim()}`, method: 'DELETE', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/delete_record.ts b/apps/sim/tools/attio/delete_record.ts index 82da6b68c61..cc28440030e 100644 --- a/apps/sim/tools/attio/delete_record.ts +++ b/apps/sim/tools/attio/delete_record.ts @@ -39,7 +39,7 @@ export const attioDeleteRecordTool: ToolConfig - `https://api.attio.com/v2/objects/${params.objectType}/records/${params.recordId}`, + `https://api.attio.com/v2/objects/${params.objectType.trim()}/records/${params.recordId.trim()}`, method: 'DELETE', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/delete_task.ts b/apps/sim/tools/attio/delete_task.ts index 02672f6cd3f..088f74707c3 100644 --- a/apps/sim/tools/attio/delete_task.ts +++ b/apps/sim/tools/attio/delete_task.ts @@ -31,7 +31,7 @@ export const attioDeleteTaskTool: ToolConfig `https://api.attio.com/v2/tasks/${params.taskId}`, + url: (params) => `https://api.attio.com/v2/tasks/${params.taskId.trim()}`, method: 'DELETE', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/delete_webhook.ts b/apps/sim/tools/attio/delete_webhook.ts index 17f1aa6d978..eaacde34eb6 100644 --- a/apps/sim/tools/attio/delete_webhook.ts +++ b/apps/sim/tools/attio/delete_webhook.ts @@ -34,7 +34,7 @@ export const attioDeleteWebhookTool: ToolConfig< }, request: { - url: (params) => `https://api.attio.com/v2/webhooks/${params.webhookId}`, + url: (params) => `https://api.attio.com/v2/webhooks/${params.webhookId.trim()}`, method: 'DELETE', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/get_comment.ts b/apps/sim/tools/attio/get_comment.ts index c32aa84f5aa..3bfa823697c 100644 --- a/apps/sim/tools/attio/get_comment.ts +++ b/apps/sim/tools/attio/get_comment.ts @@ -32,7 +32,7 @@ export const attioGetCommentTool: ToolConfig `https://api.attio.com/v2/comments/${params.commentId}`, + url: (params) => `https://api.attio.com/v2/comments/${params.commentId.trim()}`, method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/get_list.ts b/apps/sim/tools/attio/get_list.ts index cf6cbb7b0f4..440b28e81c2 100644 --- a/apps/sim/tools/attio/get_list.ts +++ b/apps/sim/tools/attio/get_list.ts @@ -32,7 +32,7 @@ export const attioGetListTool: ToolConfig `https://api.attio.com/v2/lists/${params.list}`, + url: (params) => `https://api.attio.com/v2/lists/${params.list.trim()}`, method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/get_list_entry.ts b/apps/sim/tools/attio/get_list_entry.ts index 8047a953e7e..22aa1c41481 100644 --- a/apps/sim/tools/attio/get_list_entry.ts +++ b/apps/sim/tools/attio/get_list_entry.ts @@ -39,7 +39,8 @@ export const attioGetListEntryTool: ToolConfig `https://api.attio.com/v2/lists/${params.list}/entries/${params.entryId}`, + url: (params) => + `https://api.attio.com/v2/lists/${params.list.trim()}/entries/${params.entryId.trim()}`, method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/get_member.ts b/apps/sim/tools/attio/get_member.ts index 3469856c5be..11f2c08c07d 100644 --- a/apps/sim/tools/attio/get_member.ts +++ b/apps/sim/tools/attio/get_member.ts @@ -32,7 +32,7 @@ export const attioGetMemberTool: ToolConfig `https://api.attio.com/v2/workspace_members/${params.memberId}`, + url: (params) => `https://api.attio.com/v2/workspace_members/${params.memberId.trim()}`, method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/get_note.ts b/apps/sim/tools/attio/get_note.ts index 7637edc40d7..0a9ad4a8e76 100644 --- a/apps/sim/tools/attio/get_note.ts +++ b/apps/sim/tools/attio/get_note.ts @@ -32,7 +32,7 @@ export const attioGetNoteTool: ToolConfig `https://api.attio.com/v2/notes/${params.noteId}`, + url: (params) => `https://api.attio.com/v2/notes/${params.noteId.trim()}`, method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/get_object.ts b/apps/sim/tools/attio/get_object.ts index 5f67495dda2..09ecc9c267f 100644 --- a/apps/sim/tools/attio/get_object.ts +++ b/apps/sim/tools/attio/get_object.ts @@ -32,7 +32,7 @@ export const attioGetObjectTool: ToolConfig `https://api.attio.com/v2/objects/${params.object}`, + url: (params) => `https://api.attio.com/v2/objects/${params.object.trim()}`, method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/get_record.ts b/apps/sim/tools/attio/get_record.ts index 979492c6aed..2ae04ddbad7 100644 --- a/apps/sim/tools/attio/get_record.ts +++ b/apps/sim/tools/attio/get_record.ts @@ -39,7 +39,7 @@ export const attioGetRecordTool: ToolConfig - `https://api.attio.com/v2/objects/${params.objectType}/records/${params.recordId}`, + `https://api.attio.com/v2/objects/${params.objectType.trim()}/records/${params.recordId.trim()}`, method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/get_task.ts b/apps/sim/tools/attio/get_task.ts new file mode 100644 index 00000000000..82ac333861c --- /dev/null +++ b/apps/sim/tools/attio/get_task.ts @@ -0,0 +1,78 @@ +import { createLogger } from '@sim/logger' +import type { ToolConfig } from '@/tools/types' +import type { AttioGetTaskParams, AttioGetTaskResponse } from './types' +import { TASK_OUTPUT_PROPERTIES } from './types' + +const logger = createLogger('AttioGetTask') + +export const attioGetTaskTool: ToolConfig = { + id: 'attio_get_task', + name: 'Attio Get Task', + description: 'Get a single task by ID from Attio', + version: '1.0.0', + + oauth: { + required: true, + provider: 'attio', + }, + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'The OAuth access token for the Attio API', + }, + taskId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The ID of the task to retrieve', + }, + }, + + request: { + url: (params) => `https://api.attio.com/v2/tasks/${params.taskId.trim()}`, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response) => { + const data = await response.json() + if (!response.ok) { + logger.error('Attio API request failed', { data, status: response.status }) + throw new Error(data.message || 'Failed to get task') + } + const task = data.data + const linkedRecords = (task.linked_records ?? []).map( + (r: { target_object_id?: string; target_record_id?: string }) => ({ + targetObjectId: r.target_object_id ?? null, + targetRecordId: r.target_record_id ?? null, + }) + ) + const assignees = (task.assignees ?? []).map( + (a: { referenced_actor_type?: string; referenced_actor_id?: string }) => ({ + type: a.referenced_actor_type ?? null, + id: a.referenced_actor_id ?? null, + }) + ) + return { + success: true, + output: { + taskId: task.id?.task_id ?? null, + content: task.content_plaintext ?? null, + deadlineAt: task.deadline_at ?? null, + isCompleted: task.is_completed ?? false, + linkedRecords, + assignees, + createdByActor: task.created_by_actor ?? null, + createdAt: task.created_at ?? null, + }, + } + }, + + outputs: TASK_OUTPUT_PROPERTIES, +} diff --git a/apps/sim/tools/attio/get_thread.ts b/apps/sim/tools/attio/get_thread.ts index 83bc0fec3c5..62f0a47f1d7 100644 --- a/apps/sim/tools/attio/get_thread.ts +++ b/apps/sim/tools/attio/get_thread.ts @@ -32,7 +32,7 @@ export const attioGetThreadTool: ToolConfig `https://api.attio.com/v2/threads/${params.threadId}`, + url: (params) => `https://api.attio.com/v2/threads/${params.threadId.trim()}`, method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/get_webhook.ts b/apps/sim/tools/attio/get_webhook.ts index 826899187e5..7cc76f9e1dc 100644 --- a/apps/sim/tools/attio/get_webhook.ts +++ b/apps/sim/tools/attio/get_webhook.ts @@ -32,7 +32,7 @@ export const attioGetWebhookTool: ToolConfig `https://api.attio.com/v2/webhooks/${params.webhookId}`, + url: (params) => `https://api.attio.com/v2/webhooks/${params.webhookId.trim()}`, method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/index.ts b/apps/sim/tools/attio/index.ts index 7212fc424af..978993b87de 100644 --- a/apps/sim/tools/attio/index.ts +++ b/apps/sim/tools/attio/index.ts @@ -20,6 +20,7 @@ export { attioGetMemberTool } from './get_member' export { attioGetNoteTool } from './get_note' export { attioGetObjectTool } from './get_object' export { attioGetRecordTool } from './get_record' +export { attioGetTaskTool } from './get_task' export { attioGetThreadTool } from './get_thread' export { attioGetWebhookTool } from './get_webhook' export { attioListListsTool } from './list_lists' diff --git a/apps/sim/tools/attio/list_records.ts b/apps/sim/tools/attio/list_records.ts index 7fae18d4437..39cfef28349 100644 --- a/apps/sim/tools/attio/list_records.ts +++ b/apps/sim/tools/attio/list_records.ts @@ -56,7 +56,7 @@ export const attioListRecordsTool: ToolConfig `https://api.attio.com/v2/objects/${params.objectType}/records/query`, + url: (params) => `https://api.attio.com/v2/objects/${params.objectType.trim()}/records/query`, method: 'POST', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/query_list_entries.ts b/apps/sim/tools/attio/query_list_entries.ts index d234c2aec37..6b0574d88b9 100644 --- a/apps/sim/tools/attio/query_list_entries.ts +++ b/apps/sim/tools/attio/query_list_entries.ts @@ -60,7 +60,7 @@ export const attioQueryListEntriesTool: ToolConfig< }, request: { - url: (params) => `https://api.attio.com/v2/lists/${params.list}/entries/query`, + url: (params) => `https://api.attio.com/v2/lists/${params.list.trim()}/entries/query`, method: 'POST', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/types.ts b/apps/sim/tools/attio/types.ts index cb7c7264262..0f2bb2a9c22 100644 --- a/apps/sim/tools/attio/types.ts +++ b/apps/sim/tools/attio/types.ts @@ -529,6 +529,26 @@ export interface AttioUpdateTaskResponse extends ToolResponse { } } +/** Params for getting a single task */ +export interface AttioGetTaskParams { + accessToken: string + taskId: string +} + +/** Response for getting a single task */ +export interface AttioGetTaskResponse extends ToolResponse { + output: { + taskId: string | null + content: string | null + deadlineAt: string | null + isCompleted: boolean + linkedRecords: Array<{ targetObjectId: string | null; targetRecordId: string | null }> + assignees: Array<{ type: string | null; id: string | null }> + createdByActor: unknown + createdAt: string | null + } +} + /** Response for deleting a task */ export interface AttioDeleteTaskResponse extends ToolResponse { output: { @@ -1093,6 +1113,7 @@ export type AttioResponse = | AttioListTasksResponse | AttioCreateTaskResponse | AttioUpdateTaskResponse + | AttioGetTaskResponse | AttioDeleteTaskResponse | AttioListObjectsResponse | AttioGetObjectResponse diff --git a/apps/sim/tools/attio/update_list.ts b/apps/sim/tools/attio/update_list.ts index e54176a128a..e36f74b2ece 100644 --- a/apps/sim/tools/attio/update_list.ts +++ b/apps/sim/tools/attio/update_list.ts @@ -58,7 +58,7 @@ export const attioUpdateListTool: ToolConfig `https://api.attio.com/v2/lists/${params.list}`, + url: (params) => `https://api.attio.com/v2/lists/${params.list.trim()}`, method: 'PATCH', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/update_list_entry.ts b/apps/sim/tools/attio/update_list_entry.ts index d6da7dc01e1..760e960cdfc 100644 --- a/apps/sim/tools/attio/update_list_entry.ts +++ b/apps/sim/tools/attio/update_list_entry.ts @@ -47,7 +47,8 @@ export const attioUpdateListEntryTool: ToolConfig< }, request: { - url: (params) => `https://api.attio.com/v2/lists/${params.list}/entries/${params.entryId}`, + url: (params) => + `https://api.attio.com/v2/lists/${params.list.trim()}/entries/${params.entryId.trim()}`, method: 'PATCH', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/update_object.ts b/apps/sim/tools/attio/update_object.ts index 1b8c0024a9a..0136bae05dd 100644 --- a/apps/sim/tools/attio/update_object.ts +++ b/apps/sim/tools/attio/update_object.ts @@ -51,7 +51,7 @@ export const attioUpdateObjectTool: ToolConfig `https://api.attio.com/v2/objects/${params.object}`, + url: (params) => `https://api.attio.com/v2/objects/${params.object.trim()}`, method: 'PATCH', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/update_record.ts b/apps/sim/tools/attio/update_record.ts index cf74d9a3b78..21d613f9292 100644 --- a/apps/sim/tools/attio/update_record.ts +++ b/apps/sim/tools/attio/update_record.ts @@ -46,7 +46,7 @@ export const attioUpdateRecordTool: ToolConfig - `https://api.attio.com/v2/objects/${params.objectType}/records/${params.recordId}`, + `https://api.attio.com/v2/objects/${params.objectType.trim()}/records/${params.recordId.trim()}`, method: 'PATCH', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/update_task.ts b/apps/sim/tools/attio/update_task.ts index 9b1e4e21e82..e55394b44ce 100644 --- a/apps/sim/tools/attio/update_task.ts +++ b/apps/sim/tools/attio/update_task.ts @@ -56,7 +56,7 @@ export const attioUpdateTaskTool: ToolConfig `https://api.attio.com/v2/tasks/${params.taskId}`, + url: (params) => `https://api.attio.com/v2/tasks/${params.taskId.trim()}`, method: 'PATCH', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, diff --git a/apps/sim/tools/attio/update_webhook.ts b/apps/sim/tools/attio/update_webhook.ts index 662691c4fde..659bb8f9648 100644 --- a/apps/sim/tools/attio/update_webhook.ts +++ b/apps/sim/tools/attio/update_webhook.ts @@ -34,41 +34,38 @@ export const attioUpdateWebhookTool: ToolConfig< }, targetUrl: { type: 'string', - required: true, + required: false, visibility: 'user-or-llm', description: 'HTTPS target URL for webhook delivery', }, subscriptions: { type: 'string', - required: true, + required: false, visibility: 'user-or-llm', description: 'JSON array of subscriptions, e.g. [{"event_type":"note.created"}]', }, }, request: { - url: (params) => `https://api.attio.com/v2/webhooks/${params.webhookId}`, + url: (params) => `https://api.attio.com/v2/webhooks/${params.webhookId.trim()}`, method: 'PATCH', headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, 'Content-Type': 'application/json', }), body: (params) => { - let subscriptions: unknown = [] + const data: Record = {} + if (params.targetUrl) data.target_url = params.targetUrl.trim() if (params.subscriptions) { try { - subscriptions = + data.subscriptions = typeof params.subscriptions === 'string' ? JSON.parse(params.subscriptions) : params.subscriptions } catch { - subscriptions = [] + data.subscriptions = [] } } - const data: Record = { - target_url: params.targetUrl, - subscriptions, - } return { data } }, }, diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 36bb3e2739e..d7f6e9c62d6 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -149,6 +149,7 @@ import { attioGetNoteTool, attioGetObjectTool, attioGetRecordTool, + attioGetTaskTool, attioGetThreadTool, attioGetWebhookTool, attioListListsTool, @@ -3911,6 +3912,7 @@ export const tools: Record = { attio_get_note: attioGetNoteTool, attio_get_object: attioGetObjectTool, attio_get_record: attioGetRecordTool, + attio_get_task: attioGetTaskTool, attio_get_thread: attioGetThreadTool, attio_get_webhook: attioGetWebhookTool, attio_list_lists: attioListListsTool, diff --git a/apps/sim/triggers/attio/index.ts b/apps/sim/triggers/attio/index.ts index f8c0e27f294..a6e77f3a634 100644 --- a/apps/sim/triggers/attio/index.ts +++ b/apps/sim/triggers/attio/index.ts @@ -2,9 +2,12 @@ export { attioCommentCreatedTrigger } from './comment_created' export { attioCommentDeletedTrigger } from './comment_deleted' export { attioCommentResolvedTrigger } from './comment_resolved' export { attioCommentUnresolvedTrigger } from './comment_unresolved' +export { attioListCreatedTrigger } from './list_created' +export { attioListDeletedTrigger } from './list_deleted' export { attioListEntryCreatedTrigger } from './list_entry_created' export { attioListEntryDeletedTrigger } from './list_entry_deleted' export { attioListEntryUpdatedTrigger } from './list_entry_updated' +export { attioListUpdatedTrigger } from './list_updated' export { attioNoteCreatedTrigger } from './note_created' export { attioNoteDeletedTrigger } from './note_deleted' export { attioNoteUpdatedTrigger } from './note_updated' @@ -16,3 +19,4 @@ export { attioTaskCreatedTrigger } from './task_created' export { attioTaskDeletedTrigger } from './task_deleted' export { attioTaskUpdatedTrigger } from './task_updated' export { attioWebhookTrigger } from './webhook' +export { attioWorkspaceMemberCreatedTrigger } from './workspace_member_created' diff --git a/apps/sim/triggers/attio/list_created.ts b/apps/sim/triggers/attio/list_created.ts new file mode 100644 index 00000000000..5f55567356f --- /dev/null +++ b/apps/sim/triggers/attio/list_created.ts @@ -0,0 +1,29 @@ +import { AttioIcon } from '@/components/icons' +import { buildAttioTriggerSubBlocks, buildListOutputs } from '@/triggers/attio/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Attio List Created Trigger + * + * Triggers when a list is created in Attio. + */ +export const attioListCreatedTrigger: TriggerConfig = { + id: 'attio_list_created', + name: 'Attio List Created', + provider: 'attio', + description: 'Trigger workflow when a list is created in Attio', + version: '1.0.0', + icon: AttioIcon, + + subBlocks: buildAttioTriggerSubBlocks('attio_list_created'), + + outputs: buildListOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Attio-Signature': 'hmac-sha256-signature', + }, + }, +} diff --git a/apps/sim/triggers/attio/list_deleted.ts b/apps/sim/triggers/attio/list_deleted.ts new file mode 100644 index 00000000000..9796cf257bb --- /dev/null +++ b/apps/sim/triggers/attio/list_deleted.ts @@ -0,0 +1,29 @@ +import { AttioIcon } from '@/components/icons' +import { buildAttioTriggerSubBlocks, buildListOutputs } from '@/triggers/attio/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Attio List Deleted Trigger + * + * Triggers when a list is deleted in Attio. + */ +export const attioListDeletedTrigger: TriggerConfig = { + id: 'attio_list_deleted', + name: 'Attio List Deleted', + provider: 'attio', + description: 'Trigger workflow when a list is deleted in Attio', + version: '1.0.0', + icon: AttioIcon, + + subBlocks: buildAttioTriggerSubBlocks('attio_list_deleted'), + + outputs: buildListOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Attio-Signature': 'hmac-sha256-signature', + }, + }, +} diff --git a/apps/sim/triggers/attio/list_updated.ts b/apps/sim/triggers/attio/list_updated.ts new file mode 100644 index 00000000000..005cab5f6fe --- /dev/null +++ b/apps/sim/triggers/attio/list_updated.ts @@ -0,0 +1,29 @@ +import { AttioIcon } from '@/components/icons' +import { buildAttioTriggerSubBlocks, buildListOutputs } from '@/triggers/attio/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Attio List Updated Trigger + * + * Triggers when a list is updated in Attio. + */ +export const attioListUpdatedTrigger: TriggerConfig = { + id: 'attio_list_updated', + name: 'Attio List Updated', + provider: 'attio', + description: 'Trigger workflow when a list is updated in Attio', + version: '1.0.0', + icon: AttioIcon, + + subBlocks: buildAttioTriggerSubBlocks('attio_list_updated'), + + outputs: buildListOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Attio-Signature': 'hmac-sha256-signature', + }, + }, +} diff --git a/apps/sim/triggers/attio/utils.ts b/apps/sim/triggers/attio/utils.ts index 11dfa89c309..9276f91ad46 100644 --- a/apps/sim/triggers/attio/utils.ts +++ b/apps/sim/triggers/attio/utils.ts @@ -19,6 +19,10 @@ export const attioTriggerOptions = [ { label: 'List Entry Created', id: 'attio_list_entry_created' }, { label: 'List Entry Updated', id: 'attio_list_entry_updated' }, { label: 'List Entry Deleted', id: 'attio_list_entry_deleted' }, + { label: 'List Created', id: 'attio_list_created' }, + { label: 'List Updated', id: 'attio_list_updated' }, + { label: 'List Deleted', id: 'attio_list_deleted' }, + { label: 'Workspace Member Created', id: 'attio_workspace_member_created' }, { label: 'Generic Webhook (All Events)', id: 'attio_webhook' }, ] @@ -235,6 +239,42 @@ export function buildCommentOutputs(): Record { } } +/** + * List event outputs. + */ +function buildListIdOutputs(): Record { + return { + workspaceId: { type: 'string', description: 'The workspace ID' }, + listId: { type: 'string', description: 'The list ID' }, + } +} + +/** List created/updated/deleted outputs. */ +export function buildListOutputs(): Record { + return { + ...buildBaseWebhookOutputs(), + ...buildListIdOutputs(), + } +} + +/** + * Workspace member event outputs. + */ +function buildWorkspaceMemberIdOutputs(): Record { + return { + workspaceId: { type: 'string', description: 'The workspace ID' }, + workspaceMemberId: { type: 'string', description: 'The workspace member ID' }, + } +} + +/** Workspace member outputs. */ +export function buildWorkspaceMemberOutputs(): Record { + return { + ...buildBaseWebhookOutputs(), + ...buildWorkspaceMemberIdOutputs(), + } +} + /** List entry created/deleted outputs. */ export function buildListEntryOutputs(): Record { return { @@ -276,7 +316,7 @@ export const TRIGGER_EVENT_MAP: Record = { attio_record_deleted: ['record.deleted'], attio_record_merged: ['record.merged'], attio_note_created: ['note.created'], - attio_note_updated: ['note.updated', 'note.content-updated'], + attio_note_updated: ['note.updated', 'note-content.updated'], attio_note_deleted: ['note.deleted'], attio_task_created: ['task.created'], attio_task_updated: ['task.updated'], @@ -288,6 +328,10 @@ export const TRIGGER_EVENT_MAP: Record = { attio_list_entry_created: ['list-entry.created'], attio_list_entry_updated: ['list-entry.updated'], attio_list_entry_deleted: ['list-entry.deleted'], + attio_list_created: ['list.created'], + attio_list_updated: ['list.updated'], + attio_list_deleted: ['list.deleted'], + attio_workspace_member_created: ['workspace-member.created'], } /** @@ -445,6 +489,35 @@ export function extractAttioListEntryUpdatedData( } } +/** + * Extracts formatted data from an Attio list event payload. + * Used for list.created, list.updated, list.deleted triggers. + */ +export function extractAttioListData(body: Record): Record { + const event = getAttioEvent(body) ?? {} + const id = (event.id as Record) ?? {} + return { + eventType: event.event_type ?? null, + workspaceId: id.workspace_id ?? null, + listId: id.list_id ?? null, + } +} + +/** + * Extracts formatted data from an Attio workspace-member.created event payload. + */ +export function extractAttioWorkspaceMemberData( + body: Record +): Record { + const event = getAttioEvent(body) ?? {} + const id = (event.id as Record) ?? {} + return { + eventType: event.event_type ?? null, + workspaceId: id.workspace_id ?? null, + workspaceMemberId: id.workspace_member_id ?? null, + } +} + /** * Extracts formatted data from a generic Attio webhook payload. * Passes through the first event with camelCase field mapping. diff --git a/apps/sim/triggers/attio/workspace_member_created.ts b/apps/sim/triggers/attio/workspace_member_created.ts new file mode 100644 index 00000000000..6d6d8145e62 --- /dev/null +++ b/apps/sim/triggers/attio/workspace_member_created.ts @@ -0,0 +1,29 @@ +import { AttioIcon } from '@/components/icons' +import { buildAttioTriggerSubBlocks, buildWorkspaceMemberOutputs } from '@/triggers/attio/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Attio Workspace Member Created Trigger + * + * Triggers when a new member is added to the Attio workspace. + */ +export const attioWorkspaceMemberCreatedTrigger: TriggerConfig = { + id: 'attio_workspace_member_created', + name: 'Attio Workspace Member Created', + provider: 'attio', + description: 'Trigger workflow when a new member is added to the Attio workspace', + version: '1.0.0', + icon: AttioIcon, + + subBlocks: buildAttioTriggerSubBlocks('attio_workspace_member_created'), + + outputs: buildWorkspaceMemberOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Attio-Signature': 'hmac-sha256-signature', + }, + }, +} diff --git a/apps/sim/triggers/registry.ts b/apps/sim/triggers/registry.ts index b0c61fe8c1c..4390bfeefff 100644 --- a/apps/sim/triggers/registry.ts +++ b/apps/sim/triggers/registry.ts @@ -12,9 +12,12 @@ import { attioCommentDeletedTrigger, attioCommentResolvedTrigger, attioCommentUnresolvedTrigger, + attioListCreatedTrigger, + attioListDeletedTrigger, attioListEntryCreatedTrigger, attioListEntryDeletedTrigger, attioListEntryUpdatedTrigger, + attioListUpdatedTrigger, attioNoteCreatedTrigger, attioNoteDeletedTrigger, attioNoteUpdatedTrigger, @@ -26,6 +29,7 @@ import { attioTaskDeletedTrigger, attioTaskUpdatedTrigger, attioWebhookTrigger, + attioWorkspaceMemberCreatedTrigger, } from '@/triggers/attio' import { calcomBookingCancelledTrigger, @@ -200,6 +204,10 @@ export const TRIGGER_REGISTRY: TriggerRegistry = { attio_list_entry_created: attioListEntryCreatedTrigger, attio_list_entry_updated: attioListEntryUpdatedTrigger, attio_list_entry_deleted: attioListEntryDeletedTrigger, + attio_list_created: attioListCreatedTrigger, + attio_list_updated: attioListUpdatedTrigger, + attio_list_deleted: attioListDeletedTrigger, + attio_workspace_member_created: attioWorkspaceMemberCreatedTrigger, calendly_webhook: calendlyWebhookTrigger, calendly_invitee_created: calendlyInviteeCreatedTrigger, calendly_invitee_canceled: calendlyInviteeCanceledTrigger,