Read and write Attio CRM records, list entries, attributes, notes, tasks and workspace members through the Attio REST API v2.
Attio ships in the w6w first-party pack. It declares 29 actions, 2 health checks, and the host runs its code in a sandbox that never sees the credential.
io.w6w.attioAttio is a CRM built around a flexible, user-defined data model — objects, records, attributes and lists — rather than a fixed schema, so this app reaches whatever structure a workspace has actually built, including custom objects a team invented on its own.
This app covers the full data surface: create, read, update, upsert and delete records on any standard or custom object (people, companies, deals, or one a workspace defined itself) through a single set of object-parameterised actions rather than a separate action per object type. Lists and list entries are exposed alongside records, so a workflow can query which lists a record belongs to and manage its membership directly. Notes, tasks, workspace members and schema lookups (attributes, select options, statuses) round out the coverage, so a caller can inspect a workspace’s own structure before writing to it.
Good for syncing leads and companies into Attio from web forms, other CRMs or product tools; keeping sales and account data current without a manual copy step; and triggering downstream steps off new notes, tasks or record changes.
Three routes to the same 29 actions. The Workflow tab is generated from Attio's own manifest and carries its real ids, so it is copy-pasteable; the Code and CLI examples are the same call for any action on any app, so every app-specific value in them is a blank you fill in.
create-entry Add a record to a list as a new entry. **Not idempotent** — Attio explicitly allows several entries for the same parent record, so calling this twice creates two entries. Use Upsert Entry in anything that can run more than once.
create-note Attach a note to any record. Markdown is supported but only a named subset — headings 1–3, lists, bold/italic/strikethrough/highlight and links. No images, tables or code blocks.
create-record Create a record on any object. **Fails with a conflict** if a unique attribute already matches an existing record — use Upsert Record if you would rather update in that case.
create-task Create a task, optionally assigned to workspace members and linked to records. Content is plaintext only — links and @mentions are not supported, so records are attached through the Linked records field rather than typed into the text.
delete-entry Remove a record from a list by deleting its entry. **The record itself is untouched** — only the list membership and the entry's own values are deleted, and that part is not reversible.
delete-note Permanently delete a note. Notes cannot be archived and Attio publishes no update endpoint for them, so this is the only way to remove one.
delete-record Permanently delete a record. **Not reversible and not archiving** — Attio has no archive state for records, so the data is gone. A second call on the same id returns 404.
delete-task Permanently delete a task. Also the only way to correct a task's text, since its content cannot be updated.
get-entry Fetch one list entry by id. Returns the entry's own attribute values (the list's attributes, not the parent record's) plus a flattened scalar view of them.
get-identity Identify the connected token: which workspace it belongs to and exactly which scopes it was granted. Use it to check a permission before a write rather than discovering the gap as a 403. Fails loudly if Attio reports the token as inactive — which it does with HTTP 200.
get-record Fetch a single record by its `record_id`, on any object. Returns Attio's raw attribute values plus a flattened scalar view of them.
list-attributes The schema of an object or a list: every attribute with its slug, UUID, type, and the `is_multiselect` / `is_unique` flags that decide how you write to it and whether you can upsert on it. Returned in the order the UI sorts them.
list-entries Query entries on a list with the same filter and sort language as List Records, plus the `parent_record` path filter that lets you select entries by properties of the record behind them.
list-lists Every list this access token can see, in sidebar order. Gives you the `api_slug` and UUID the entry actions need. A list missing here is usually a scope problem, not an empty workspace.
list-notes List notes, optionally for a single record. **Attio defaults this endpoint to 10 results and caps it at 50** — far lower than the other listings here, so page explicitly if you need them all.
list-objects Every object in the workspace, system-defined and custom. Where the `api_slug` and UUID that every record action needs come from. Use slugs for standard objects (stable forever) and UUIDs for custom ones (slugs are mutable).
list-record-attribute-values Read one attribute's value(s) on one record — and, with Historic on, every value it has ever held, oldest first. The only endpoint that exposes value history.
list-record-entries List every list entry, across all lists, whose parent is this record. The reverse lookup for "which pipelines is this company in" — a question the record itself cannot answer.
list-records Query records on any object — people, companies, deals or a custom object — with Attio's full filter and sort language. Strongly consistent; use this rather than Search Records when the result has to be up to date.
list-select-options The available options of a select attribute, with each option's title and UUID. Read this before writing select values: an unknown title is rejected, not created, and titles change while ids do not.
list-statuses The statuses of a status attribute — the stages of a pipeline — with each one's title and UUID. Read before writing a stage: an unknown title is rejected, not created.
list-tasks List tasks, filtered by linked record, assignee or completion. Note the default order is **oldest first** — set a sort if you want the newest.
list-workspace-members Everyone with a seat in the Attio workspace, with their member id, email and access level. The id source for deal owners, task assignees and any other actor-reference attribute — these are seats, not person records.
search-records Fuzzy-search records across one or more objects, the same way Attio's own search box does — names, domains, emails, phone numbers and social handles. Beta, capped at 25 results, and eventually consistent: use List Records when the answer has to be current.
update-entry Update a list entry's own attribute values. **Choose how multi-select attributes are handled**: append (PATCH) can never remove a value; overwrite (PUT) makes the supplied values the complete set. The parent record cannot be changed here.
update-record Update a record by id. **Choose how multi-select attributes are handled**: append (PATCH) adds values and can never remove one; overwrite (PUT) makes the supplied values the complete set and is the only way to clear one. Picking the wrong mode still returns 200.
update-task Update a task's deadline, completion, assignees or linked records. **The task's text cannot be changed** — Attio publishes no way to edit it. Assignees and linked records are replaced wholesale, not merged.
upsert-entry Put a record on a list, updating the existing entry if there already is one. The repeat-safe counterpart to Create Entry. Fails with MULTIPLE_MATCH_RESULTS if the record already has more than one entry on that list.
upsert-record Create a record, or update the existing one that matches on a unique attribute. The standard integration shape for lead intake and syncs. Note the asymmetry: values of the matching attribute are ADDED, while every other multi-select attribute is set to exactly what you supply.
A workflow step names the app and the action, and the editor fills in the
connection when you pick one. This is the Step shape from the
workflow spec, carrying Attio's real ids.
{
"manifestVersion": "2",
"name": "attio-example",
"steps": [
{
"id": "create-entry",
"uses": {
"app": "io.w6w.attio",
"action": "create-entry",
"connection": "conn_YOUR_CONNECTION_ID"
},
"with": {
"list": "<list>",
"parentObject": "<parentObject>",
"parentRecordId": "<parentRecordId>"
}
}
]
}create-entry create-note create-record create-task get-entry +24 more actions available
Every app-specific value here is a blank you have to fill in. An
app action is reached through the connection that authenticates it, so the
address is a connection id, not the app id — and connections belong to your account,
so a public page cannot know yours. Create one for Attio, then fill in
the three blanks: conn_YOUR_CONNECTION_ID, the action key, and the
parameters that action declares. The call itself is real — the shape is transcribed
from the studio's own snippet builder, which prints the same kind of blanks — but
nothing in it is specific to Attio. The Workflow tab is where this app's
real ids are.
npm install @w6w/sdkyarn add @w6w/sdkpnpm add @w6w/sdkdeno add npm:@w6w/sdkimport { W6wClient, isActionRun } from "@w6w/sdk";
// Reads W6W_BASE_URL and W6W_TOKEN from the environment when omitted.
const client = new W6wClient();
const envelope = await client.run({
urn: "conn_YOUR_CONNECTION_ID",
action: "create-record",
payload: {
object: "<value>",
values: "<value>",
},
});
if (isActionRun(envelope)) console.log(envelope.value); npm install -g @w6w/cli w6w run conn_YOUR_CONNECTION_ID --action create-record --payload '{"object":"<value>","values":"<value>"}' Give an AI agent Attio — without giving it Attio's credentials. One MCP endpoint exposes every app, function and workflow the caller is entitled to, as tools it can discover and run. Access is granted per team while we onboard.
One tool call{
"name": "w6w_invoke",
"arguments": {
"ref": "app:io.w6w.attio#create-entry",
"input": {
"list": "<list>",
"parentObject": "<parentObject>",
"parentRecordId": "<parentRecordId>"
}
}
}
Every tool names its target with a single ref. The
app: form above doesn't name a connection at all — the
host resolves which of the caller's Attio connections to sign
with, and refuses rather than guesses when the answer is ambiguous.
The token is attached host-side, at the moment of the call. It is never a tool argument, never in the model's context, and never in a transcript — so a prompt injection has nothing to exfiltrate.
Tools are derived per end user from what that person has actually connected and is entitled to — not one shared bot identity carrying the union of everyone's access.
Multi-step work runs on the workflow engine and returns a run handle the agent can poll — retries, branching and state survive the conversation that started them.
Attio's declared health checks are on the surface too, so an agent can tell "the vendor is down" from "your credential expired" before it burns a retry on either.
The MCP surface is part of the hosted platform. Attio itself is MIT, and the runtime that executes it is source-available (FSL).
Attio declares its own checks, so its health is a property of the app rather than something the host guesses at.
Atlassian Statuspage at status.attio.com. The reported state tracks the **Attio Cloud** component specifically — the one Attio describes as powering its APIs, and the only surface this app calls — while the web client, helpdesk, cloud storage and background tasks are reported alongside it for context. Unauthenticated and unsigned.