Building on Attio's API?

Book a discovery call

""

Official Attio Expert Partner

""

Own your GTM stack

""

Built to drive revenue

""

Production-ready, not prototypes

""

Proven, hands-on experience

Build on the REST API. It is the right answer for roughly nine out of ten integrations, because it is the only surface you fully control and the only one with a stable contract. Reach for the MCP when the caller is an AI agent rather than your code, the App SDK when the thing you are building belongs inside Attio’s interface, and SQL when you need analytical reads and you are on Enterprise.

That is the short version, and most posts stop there. The part that decides whether your integration survives contact with real data is not which surface you pick. It is the rate limits, which are stranger than the published numbers suggest, and a handful of coverage gaps that do not appear until you are three weeks into the build. This post covers both.

The four surfaces, at a glance

Attio’s developer platform is usually described as three things. It is four, and the fourth one is the most useful and least discussed.

Surface

Build on it when

Auth

REST API

You own the code and the workflow is long-lived

OAuth 2.0 or workspace API key

MCP

The caller is an AI agent, not your program

OAuth only, no keys

App SDK

The experience lives inside Attio’s UI

Developer console app

SQL

You need analytical reads and joins

Enterprise plan only

These are not tiers. They are different products with different users, and Attio built them that way on purpose.

The question that actually decides it

Forget features for a moment. Ask who is calling.

If a program is calling, you want the REST API. Programs need a contract that does not move, predictable pagination, and errors they can retry. If an agent is calling, you want the MCP. Agents do not want a contract, they want fewer round trips and less context burned per answer.

Attio’s own engineering team put this better than I can. In their write-up on building the Attio MCP server, they describe the split directly: the user of a public API is a programmer whose code must be reliable and maintainable, while the user of an MCP server is an autonomous agent asking questions on the fly. They deliberately did not wrap the REST API to produce the MCP, because pagination that suits an ETL job pulling a million records is exactly the wrong shape for an agent that will blow its context window on page four.

That single decision explains most of the differences below. It is also why “the MCP is just the API with a different hat” is wrong, and why you occasionally need both in the same product.

The REST API, and the limits that actually bite

The base URL is https://api.attio.com/v2. Authentication is a bearer token, from one of two places: an OAuth 2.0 flow if your app serves multiple workspaces, or a workspace API key if it serves one. Tokens carry scopes, and every endpoint’s reference page lists what it needs. New tokens start with no scopes at all, which is the first thing that trips people up.

The published rate limits are simple:

Operation

Limit

Read requests

100 per second

Write requests

25 per second

Exceed either and you get a 429 with a Retry-After header. Read the header carefully, because this is where hand-rolled clients break. Attio’s Retry-After is a date, not a number of seconds. A retry helper that assumes an integer will parse it as NaN, fall through to a default, and either hammer the endpoint or sleep for an hour. Neither is what you want at 2am.

Want your Attio sync designed so it survives the rate limits?

Book a discovery call

Want your Attio sync designed so it survives the rate limits?

Book a discovery call


The score-based limit nobody writes about

Here is the part that is missing from every third-party guide currently on page one, and it is the thing most likely to break your sync.

List records and List entries do not just count requests. Each query also receives a complexity score, calculated from your sorts, your filters, and the total record or entry count for that object. The score can fail you in two separate ways. A single query can be too complex on its own. Or the summed scores of your queries can exceed the budget for a rolling ten-second window.

Now the part that matters architecturally: those scores are summed across all apps and access tokens hitting the workspace. Your nightly sync, your teammate’s Zap, and the enrichment job someone wired up in n8n are all drawing down the same budget. You can be well under 100 requests per second and still get throttled, because someone else’s filter is expensive and you happen to share a workspace with them.

The practical consequences are worth stating plainly. Deep path filters, the drill-down kind that traverse a record reference into a related object, are the most expensive queries you can write. Convenient in a one-off script, costly in a loop. If your sync is throttling and the request-per-second math says it should not be, stop looking at your own concurrency and start looking at what else is querying that workspace.

Pagination is not one thing

Pagination is limit/offset on some endpoints and cursor-based on others, and the docs specify which per endpoint. Cursor endpoints return pagination.next_cursor and expect your limit and filters to stay identical between calls. Change a filter mid-walk and your results go quietly wrong rather than loudly failing. Write your paginator against the specific endpoint, not against a generic assumption.

The MCP: built for agents, not for your code

The MCP server lives at https://mcp.attio.com/mcp. There is no API key. Authentication is OAuth, and Attio chose dynamic client registration so that clients can register themselves without a developer pre-configuring anything. You authenticate as yourself, and your existing Attio permissions apply, which is the security answer most teams are looking for when they ask whether an agent should touch the CRM.

The rate limits are tiered per workspace, with tools in each tier sharing a bucket:

Tier

Limit

Read

100 per second

Write

25 per second

Merge

5 per second

Search

300 per minute

Semantic search

2 per second

Reporting and SQL

2 per second

Read and write mirror the REST limits. The two that surprise people are semantic search at 2 per second and search at 300 per minute. For conversational use you will never notice them. For anything scripted, semantic search is the tightest ceiling on the platform, and it is the tool agents reach for most enthusiastically.

One detail from Attio’s engineering post is worth knowing if you are debugging token spend rather than latency: MCP responses are rendered in TOON rather than JSON, a compact encoding that declares field names once and streams rows in a CSV-like layout. Same information, a fraction of the tokens. If you are wondering why your agent’s Attio calls are cheaper than your Attio API calls, that is why.

We wrote up the setup path and the prompts that actually earn their keep in our guide to connecting Claude and AI agents to Attio, so this post stays on the build decision.

The App SDK is not a client library

This is the most common mix-up I see, and it costs people an afternoon.

The App SDK is not an SDK for calling the REST API. It is a framework for building apps that run inside Attio, on Attio’s infrastructure. You scaffold one with npm create attio@latest [your-app-slug] after creating a developer account at build.attio.com, and what you get is the ability to add record actions, embed custom widgets on record pages, add custom triggers and steps to the Workflows builder, and give admins a settings page.

Apps can call the REST API from server functions, subscribe to events, manage webhooks, and store key-value data. So the SDK is a superset in one direction and irrelevant in the other. If your product has its own frontend, the SDK gives you nothing. If your product’s value is that a salesperson never leaves Attio, it is the only surface that gets you there. It is also the route to custom triggers and steps inside the Workflows builder, which is where most teams actually want their integration to show up.

For an actual REST client, Attio publishes an OpenAPI specification. Generate from that rather than hunting for a first-party library.

SQL: read-only, Enterprise, and underrated

SQL access exposes your workspace as two queryable schemas, objects and lists, and it is the cleanest way to answer analytical questions that filters and reports cannot. Joins across objects, aggregates, ad-hoc analysis.

Three constraints decide whether it is available to you. It is Enterprise plan only. It is read-only, so SELECT and nothing else. And there is a 30-second query timeout with a limit of 2 queries per second.

You can reach it three ways: the REST query endpoint, the query-particle-sql MCP tool, or data connectors that let external tools query over the PostgreSQL protocol. That last one is the quiet win. If your reporting stack already speaks Postgres, you may not need to build a sync at all, which is a better outcome than the one most teams arrive with. Check your plan before you design around it, because on Pro this option does not exist and the answer becomes the REST API plus a warehouse.

Webhooks decide whether your sync is real-time

If you are syncing data in, you will want webhooks rather than polling, and there are four numbers to design around.

Attio enforces a 5 second timeout on your endpoint. Acknowledge fast and process asynchronously; anything that does real work inline will start failing under load. Delivery is at-least-once with an Idempotency-Key header that stays constant across retries, so your handler must be idempotent, not merely hopeful. Non-2xx responses are retried up to 10 times with exponential backoff across roughly three days, after which the webhook is marked degraded and you get an email. And delivery to a single target URL is capped at 25 requests per second.

Every request is signed with an Attio-Signature header, a SHA256 HMAC of the raw body using your webhook secret, hex encoded. Verify it against the raw body. If your framework parses and re-serializes JSON before you compute the HMAC, key ordering changes and every signature fails. Attio does publish a fixed set of egress IPs, but they recommend signature validation over IP allowlisting, and so do I, because the IP list changes and your firewall rules will not.

Webhook filters are worth setting up early. They run server-side against the event payload and support $and and $or with equals and not_equals, so you can subscribe to changes on one list, or one attribute on one list, instead of receiving everything and discarding 95% of it. Filters are only editable over the API, not in the settings UI.

Four gotchas that cost me time

These are the ones I would want someone to have told me.

Referenced records must already exist. Write a person with a reference to a company that is not in Attio yet and the request fails. Attio will not create the target for you. Order your writes in reverse: companies first, then the people who point at them. Batch importers that process a flat CSV row by row hit this immediately.

You cannot create relationship attributes over the API. Record reference attributes can be created programmatically, but true two-way relationship attributes, the paired kind where updating one side updates the other, can only be set up in the web app and then used via the API. If your onboarding flow provisions a customer’s schema automatically, this is a hard stop you need to design around rather than discover.

There is no $neq. Attio does not ship negative comparison operators. To express “not equal”, wrap the condition in $not. It reads oddly the first time and it is the single most common filter bug I see.

V1 webhooks are deprecated. If you inherited an integration using entry.created, entry-attribute.updated, or entry.deleted, those are V1 and slated for removal. The V2 equivalents are list-entry.created, list-entry.updated, and list-entry.deleted, with different payload shapes. Migrate before it is decided for you.

So which one?

If you are building

Use

Why

A product integration or data sync

REST API

Stable contract, full control, portable

An agent that operates the CRM

MCP

Fewer round trips, no key management

An experience for people inside Attio

App SDK

Only surface that renders in the UI

Reporting and analytics

SQL, else REST

Joins and aggregates, if you are on Enterprise

Most real products end up using two. A typical shape is REST for the sync that runs on a schedule, webhooks for the events that cannot wait, and the MCP bolted on later once someone asks why the AI assistant cannot see the pipeline. That is a reasonable architecture, not a sign you chose wrong at the start.

The mistake worth avoiding is building an agent workflow on the REST API because you already had a token. You will spend a month rebuilding pagination, search, and summarisation that the MCP hands you, and your agent will still burn context.

Honest limitations

Two things are worth knowing before you commit.

High-volume writes are per-record work. A large sync is many single-record upserts against PUT /v2/objects/{object}/records, each one drawing on the same 25 writes per second, which means backoff, idempotency, and concurrency control are not optional extras, they are the job. Plan for a queue rather than a loop and your first full load will not take the workspace down with it.

And the surfaces are gated differently by plan. SQL is Enterprise. Custom objects are Pro and above. If your integration assumes a custom object exists in the customer’s workspace, that assumption has a price tag attached to it, and it is better to find that out during design than during a sales call.

Neither is a reason to build elsewhere. Attio’s developer platform is the most coherent of any CRM I work in, and the constraints above are the normal cost of a system that gives you this much control over the data model. They are just cheaper to design around than to discover. The teams that get the most out of it are the ones who settled the data model before the first write, not after the first rewrite. That sequencing is most of what an Attio implementation actually buys you: the schema decided first, so the integration gets built once.

Frequently asked questions

What is the difference between the Attio API and the Attio MCP?

The REST API is for programs: a stable contract, explicit pagination, and errors your code retries. The MCP is for AI agents: OAuth instead of keys, aggregated and semantic search instead of paging, and responses encoded compactly to save tokens. Attio built the MCP separately rather than wrapping the API.

Do I need an API key to use the Attio MCP?

No. The MCP uses OAuth only. You add https://mcp.attio.com/mcp as a remote server in Claude, ChatGPT, Cursor, or any MCP client, then complete the login. You are authenticated as your own Attio user, with your existing workspace permissions applied to everything the agent does.

What are Attio’s API rate limits?

100 requests per second for reads and 25 for writes, returning HTTP 429 with a Retry-After header that contains a date rather than a delay in seconds. Separately, List records and List entries carry a complexity score based on filters, sorts, and record count, summed across every app hitting the workspace.

Does Attio have an official SDK for calling the API?

The App SDK is for building apps that run inside Attio, not a client library for the REST API. For a REST client, generate one from Attio’s published OpenAPI specification. Scaffold an in-Attio app instead with npm create attio@latest after creating a developer account in the console at build.attio.com.

Is the Attio API included in every pricing plan?

Two gates matter most. SQL access is Enterprise only, and custom objects require Pro or above, so an integration that provisions custom objects in a customer’s workspace carries a plan requirement they may not have. Confirm current plan gating on Attio’s pricing page before you design around any surface.

Can I use the Attio API with Python?

Yes. The API is JSON over HTTPS with bearer token authentication, so any HTTP client works, requests or httpx included. Generate a typed client from the OpenAPI specification if you want one. Just make sure your retry logic parses Retry-After as a date, not an integer.

Sparsh Gupta, Founder of Automation Jinn and an Official Attio Expert Partner, helps seed to Series B B2B SaaS teams build AI-native GTM systems on Attio. If you want your integration architected once, by someone who has already hit the limits you are about to, book a discovery call.

Pick the right surface, then build it once

Book a discovery call

Pick the right surface, then build it once

Book a discovery call