An overview of the functionality provided by the App SDK
This only covers apps from the perspective of the App SDK, apps can also use the REST API
An app is a way to extend the existing functionality of Attio, typically by pulling data into Attio from a third party source, or of extracting data out of Attio to use with some tool. Apps can provide custom UI directly inside of Attio’s user interface using custom React components.
Specifically you can add custom actions (buttons) to record pages inside Attio. When clicked you can trigger a server function, and/or display a modal to users with custom UI to complete a form or view information.
Let’s look at an example.
Let’s imagine a hypothetical service called Acme Lead Checker (ALC) that has an API to receive potential leads, an AI agent initiates an SMS chat with the lead, and then needs to update the lead’s record in Attio about how interested the person is in whatever product we are selling.
Our app needs:
App UI components cannot directly communicate with the outside world. They can only call custom
app server functions, which can communicate with the outside world via
fetch()
, and communicate with Attio’s REST API via
attioFetch()
.
The general sequence of how the app will work is:
connection-added
event handler the app
registered is fired.createWebhookHandler()
to register a webhook handler.onTrigger()
function provided by the record actionshowToast()
.runQuery()
. - If no phone numbers are found, the user is notified via an alert()
.
Otherwise…sendToALC()
.fetch()
to send a POST
request to api.acmeleadchecker.ai
.attioFetch()
to mark the record
as “Pending”.hideToast()
.showToast()
.…some time later…
attioFetch()
to mark the record
as “Complete”.Record action files can have any name, but they
MUST have a named export called recordAction
.
Now let’s write that GraphQL query we’re importing.
Server function file names MUST:
.server.ts
(or .server.js
) suffixexport default async function
The suffix is how Attio knows to execute them on the server. However, they are imported as if they were in the same bundle as the client side code, even though they are not.
Because they live in different bundles and runtimes, everything passed to, returned from, or thrown by server functions MUST be serializable.
Our webhook handler is going to be called by Acme Lead Checker when they have processed our lead that we sent them.
Webhook handler files MUST:
src/webhooks
directory.webhook.ts
(or .webhook.js
) suffix.export default async function
that:
In order to let Acme Lead Checker know how to call our app’s webhook, we need to tell them as soon as our user creates an authorized connection; we accomplish this with event handlers.
Connection Event Handler files MUST:
src/events
.event.ts
(or .event.js
) suffix.export default async function
that:
{ connection: Connection }
argumentvoid
When a connection is added, we need to:
When a connection is removed, we need to:
An overview of the functionality provided by the App SDK
This only covers apps from the perspective of the App SDK, apps can also use the REST API
An app is a way to extend the existing functionality of Attio, typically by pulling data into Attio from a third party source, or of extracting data out of Attio to use with some tool. Apps can provide custom UI directly inside of Attio’s user interface using custom React components.
Specifically you can add custom actions (buttons) to record pages inside Attio. When clicked you can trigger a server function, and/or display a modal to users with custom UI to complete a form or view information.
Let’s look at an example.
Let’s imagine a hypothetical service called Acme Lead Checker (ALC) that has an API to receive potential leads, an AI agent initiates an SMS chat with the lead, and then needs to update the lead’s record in Attio about how interested the person is in whatever product we are selling.
Our app needs:
App UI components cannot directly communicate with the outside world. They can only call custom
app server functions, which can communicate with the outside world via
fetch()
, and communicate with Attio’s REST API via
attioFetch()
.
The general sequence of how the app will work is:
connection-added
event handler the app
registered is fired.createWebhookHandler()
to register a webhook handler.onTrigger()
function provided by the record actionshowToast()
.runQuery()
. - If no phone numbers are found, the user is notified via an alert()
.
Otherwise…sendToALC()
.fetch()
to send a POST
request to api.acmeleadchecker.ai
.attioFetch()
to mark the record
as “Pending”.hideToast()
.showToast()
.…some time later…
attioFetch()
to mark the record
as “Complete”.Record action files can have any name, but they
MUST have a named export called recordAction
.
Now let’s write that GraphQL query we’re importing.
Server function file names MUST:
.server.ts
(or .server.js
) suffixexport default async function
The suffix is how Attio knows to execute them on the server. However, they are imported as if they were in the same bundle as the client side code, even though they are not.
Because they live in different bundles and runtimes, everything passed to, returned from, or thrown by server functions MUST be serializable.
Our webhook handler is going to be called by Acme Lead Checker when they have processed our lead that we sent them.
Webhook handler files MUST:
src/webhooks
directory.webhook.ts
(or .webhook.js
) suffix.export default async function
that:
In order to let Acme Lead Checker know how to call our app’s webhook, we need to tell them as soon as our user creates an authorized connection; we accomplish this with event handlers.
Connection Event Handler files MUST:
src/events
.event.ts
(or .event.js
) suffix.export default async function
that:
{ connection: Connection }
argumentvoid
When a connection is added, we need to:
When a connection is removed, we need to: