Skip to content

fix(attio): automatic webhook lifecycle management and tool fixes - #3327

Merged
waleedlatif1 merged 14 commits into
stagingfrom
fix/tools
Feb 25, 2026
Merged

fix(attio): automatic webhook lifecycle management and tool fixes#3327
waleedlatif1 merged 14 commits into
stagingfrom
fix/tools

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Auto-create Attio webhooks on deploy and delete on undeploy via Attio API
  • Replace manual webhook setup (URL copy-paste, signing secret) with OAuth credential flow
  • Add HMAC-SHA256 signature verification for incoming Attio webhooks
  • Fix various Attio tool issues: wand prompts, null param handling, pagination, placeholder text, API slug auto-generation, required field defaults

Type of Change

  • Bug fix
  • New feature

Testing

Tested manually

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel

vercelBot commented Feb 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
docsSkippedSkippedFeb 25, 2026 1:28am

Request Review

@waleedlatif1

Copy link
Copy Markdown
CollaboratorAuthor

@greptile

@waleedlatif1

Copy link
Copy Markdown
CollaboratorAuthor

@cursor review

@greptile-apps

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR replaces the manual Attio webhook setup flow (copy-paste URL + signing secret) with automatic webhook lifecycle management via the Attio API. Webhooks are created on deploy and deleted on undeploy using OAuth credentials, with HMAC-SHA256 signature verification for incoming requests.

  • Automatic webhook lifecycle: createAttioWebhookSubscription and deleteAttioWebhook functions handle creation/deletion via Attio's v2 API, following established patterns from Airtable, Calendly, and Webflow providers
  • Signature verification: New validateAttioSignature function in utils.server.ts uses HMAC-SHA256 with timing-safe comparison, integrated into processor.ts
  • Trigger simplification: All 17 Attio trigger files refactored from buildTriggerSubBlocks + manual setup instructions to buildAttioTriggerSubBlocks with OAuth credential input, reducing boilerplate
  • Tool fixes: !== undefined replaced with != null across 8 tool files to properly handle null values from JSON parsing; JSON input fields changed from long-input to code type; pagination offset parameter added; create_list now always sends api_slug (auto-generated from name); update_webhook makes targetUrl and subscriptions required
  • TRIGGER_EVENT_MAP exported: Now used by provider-subscriptions.ts to map trigger IDs to Attio event types during webhook creation

Confidence Score: 4/5

  • This PR is safe to merge — it follows established provider patterns, has proper error handling, and uses timing-safe signature verification.
  • Score of 4 reflects that the changes are well-structured and follow existing patterns (Airtable, Calendly, Webflow), with proper OAuth credential flow, HMAC verification, and graceful error handling. The null-check fixes are correct improvements. Minor deduction for no automated tests and the silent signature bypass when Attio doesn't return a secret.
  • apps/sim/lib/webhooks/provider-subscriptions.ts contains the core webhook lifecycle logic and should be reviewed most carefully. apps/sim/lib/webhooks/processor.ts handles the signature verification path.

Important Files Changed

FilenameOverview
apps/sim/lib/webhooks/provider-subscriptions.tsAdds Attio webhook creation/deletion lifecycle functions and integrates them into the external subscription management flow. Well-structured, follows existing patterns for other providers.
apps/sim/lib/webhooks/processor.tsAdds HMAC-SHA256 signature verification for Attio webhooks, following the same pattern as Linear, Circleback, and other providers.
apps/sim/lib/webhooks/utils.server.tsAdds validateAttioSignature function using HMAC-SHA256 with timing-safe comparison via safeCompare. Follows existing validation patterns.
apps/sim/triggers/attio/utils.tsReplaces manual webhook setup (URL copy-paste + secret input) with OAuth credential flow and auto-managed webhooks. Exports TRIGGER_EVENT_MAP for use by provider-subscriptions. attioSetupInstructions is now exported but only used internally.
apps/sim/triggers/attio/webhook.tsSimplified to use buildAttioTriggerSubBlocks directly without dropdown (generic webhook catches all events). SubBlocks rely on selectedTriggerId condition which is infrastructure-managed.
apps/sim/triggers/attio/record_created.tsPrimary trigger now defines the dropdown inline and uses buildAttioTriggerSubBlocks for OAuth fields. Clean refactor from buildTriggerSubBlocks pattern.
apps/sim/blocks/blocks/attio.tsMultiple UI improvements: long-input to code type for JSON fields, improved wand prompts, pagination offset support, placeholder text cleanup, and more accurate Attio attribute format examples.
apps/sim/tools/attio/create_list.tsAlways sends api_slug (auto-generated from name if not provided), workspace_access defaults to null, workspace_member_access defaults to empty array. Ensures required fields are always sent.
apps/sim/tools/attio/create_list_entry.tsRestructured to always send entry_values (defaults to empty object), fixing potential API issues when the field was omitted.
apps/sim/tools/attio/update_webhook.tsMakes targetUrl and subscriptions required fields (previously optional). Always sends both fields in the request body rather than conditionally including them.
apps/docs/content/docs/en/tools/attio.mdxDocumentation updated to reflect targetUrl and subscriptions being required fields for update_webhook, matching the tool definition changes.

Sequence Diagram

sequenceDiagram
participant User
participant Sim as Sim Platform
participant Attio as Attio API
Note over User, Attio: Deploy Workflow (Webhook Creation)
User->>Sim: Deploy workflow with Attio trigger
Sim->>Sim: Resolve OAuth credentials (credentialId)
Sim->>Sim: Refresh access token if needed
Sim->>Sim: Map triggerId → event types via TRIGGER_EVENT_MAP
Sim->>Attio: POST /v2/webhooks (target_url, subscriptions)
Attio-->>Sim: {webhook_id, secret}
Sim->>Sim: Store externalId + webhookSecret in providerConfig
Note over User, Attio: Incoming Webhook Event
Attio->>Sim: POST /api/webhooks/trigger/{path} + Attio-Signature header
Sim->>Sim: Retrieve webhookSecret from providerConfig
Sim->>Sim: HMAC-SHA256 verify (secret, signature, body)
alt Valid signature
Sim->>Sim: Process webhook event → trigger workflow
else Invalid signature
Sim-->>Attio: 401 Unauthorized
end
Note over User, Attio: Undeploy Workflow (Webhook Deletion)
User->>Sim: Undeploy workflow
Sim->>Sim: Resolve OAuth credentials
Sim->>Attio: DELETE /v2/webhooks/{externalId}
Attio-->>Sim: 200 OK
Loading

Last reviewed commit: 1df1933

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

37 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

{ attioWebhookId: webhookId }
)

return { externalId: webhookId, webhookSecret: secret || '' }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Silent signature bypass on empty secret

When Attio doesn't return a secret, this stores '' (empty string). Downstream in processor.ts:604, if (secret) evaluates to false for empty string, which silently skips all signature verification for that webhook. While this is consistent with how other providers handle it and there's a warning log during creation, it's worth noting this means an Attio webhook could operate without any request authentication if the API doesn't return a secret.

Consider logging a warning in the verification path as well (in processor.ts) when webhookSecret is present but empty, to make debugging easier if unauthenticated requests come through.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@cursorcursorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

'list_webhooks',
],
},
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Offset field missing search_records operation condition

Medium Severity

The new offset sub-block's condition.value array omits search_records, while the limit sub-block includes it. The Attio search records API supports offset-based pagination, so users won't be able to paginate search results using offset, creating an inconsistency between the two pagination controls.

Additional Locations (1)

Fix in CursorFix in Web

Comment threadapps/sim/tools/attio/create_list.ts
`[${requestId}] Exception during Attio webhook creation for webhook ${webhookData.id}.`,
{ message }
)
throw error

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Webhook creation throws instead of returning undefined on failure

High Severity

createAttioWebhookSubscription declares a return type of Promise<... | undefined> and the caller in handleExternalWebhookSubscriptions checks if (result) expecting undefined on failure. However, every error path in the function throws, and the catch block re-throws with throw error. Since handleExternalWebhookSubscriptions has no try/catch around the Attio call, the exception propagates unhandled — potentially crashing the deploy endpoint instead of gracefully skipping webhook creation like other providers do.

Additional Locations (1)

Fix in CursorFix in Web

@waleedlatif1
waleedlatif1 merged commit d06459f into stagingFeb 25, 2026
6 checks passed
@waleedlatif1
waleedlatif1 deleted the fix/tools branch February 25, 2026 01:30
@waleedlatif1
waleedlatif1 restored the fix/tools branch February 25, 2026 02:54
waleedlatif1 added a commit that referenced this pull request Feb 25, 2026
)
* fix(attio): use code subblock type for JSON input fields
* fix(attio): correct people name attribute format in wand prompt example
* fix(attio): improve wand prompt with correct attribute formats for all field types
* fix(attio): use array format with full_name for personal-name attribute in wand prompt
* fix(attio): use loose null checks to prevent sending null params to API
* fix(attio): add offset param and make pagination fields advanced mode
* fix(attio): remove redundant (optional) from placeholders
* fix(attio): always send required workspace_access and workspace_member_access in create list
* fix(attio): always send api_slug in create list, auto-generate from name if not provided
* fix(attio): update api slug placeholder text
* fix(tools): manage lifecycle for attio tools
* updated docs
* fix(attio): remove incorrect save button reference from setup instructions
* fix(attio): log debug message when signature verification is skipped
@waleedlatif1
waleedlatif1 deleted the fix/tools branch February 25, 2026 03:16
royceP2 pushed a commit to arenadeveloper02/p2-sim that referenced this pull request Mar 3, 2026
…mstudioai#3327)
* fix(attio): use code subblock type for JSON input fields
* fix(attio): correct people name attribute format in wand prompt example
* fix(attio): improve wand prompt with correct attribute formats for all field types
* fix(attio): use array format with full_name for personal-name attribute in wand prompt
* fix(attio): use loose null checks to prevent sending null params to API
* fix(attio): add offset param and make pagination fields advanced mode
* fix(attio): remove redundant (optional) from placeholders
* fix(attio): always send required workspace_access and workspace_member_access in create list
* fix(attio): always send api_slug in create list, auto-generate from name if not provided
* fix(attio): update api slug placeholder text
* fix(tools): manage lifecycle for attio tools
* updated docs
* fix(attio): remove incorrect save button reference from setup instructions
* fix(attio): log debug message when signature verification is skipped
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@waleedlatif1