agent-swarm
Install, self-host, deploy, operate, or use agent-swarm. Covers Docker Compose, Kubernetes,…
Generic Attio CRM REST API v2 recipes for querying records, upserting companies/people/deals, writing notes/tasks/comments, managing lists, and handling webhooks.
$ npx -y skills add desplega-ai/agent-swarm --skill attio-interaction --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/attio-interactionContext preview
The summary Claude sees to decide when to auto-load this skill.
Generic Attio CRM REST API v2 recipes for querying records, upserting companies/people/deals, writing notes/tasks/comments, managing lists, and handling webhooks.
name: attio-interaction description: Generic Attio CRM REST API v2 recipes for querying records, upserting companies/people/deals, writing notes/tasks/comments, managing lists, and handling webhooks. user-invocable: false
Use this skill to read and write your Attio CRM through the REST API v2. Every read or write is a direct API call; agent-swarm does not maintain a separate Attio sync.
1. Resolve `ATTIO_API_KEY` from swarm config before making calls. 2. Base URL: `https://api.attio.com/v2/` 3. Use `Authorization: Bearer $ATTIO_API_KEY`, `Content-Type: application/json`, and `Accept: application/json`. 4. Prefer upsert over create for People, Companies, and Deals: `PUT /v2/objects/{slug}/records` with `matching_attribute`. 5. Rate limits: 100 reads/sec, 25 writes/sec. Pace write bursts to roughly 15-20/sec. 6. Attribute values are arrays, even for scalar values: `[{ "value": 42 }]`, never `42`.
ATTIO_API_KEY=$(get-config key="ATTIO_API_KEY" includeSecrets=true) curl -sS "https://api.attio.com/v2/objects" \ -H "Authorization: Bearer $ATTIO_API_KEY" \ -H "Accept: application/json"
If calls return `401`, re-fetch the key from config. If it still fails, notify the Lead; the key may need rotation. Do not retry silently.
| Object | API slug | Primary matching attribute | |---|---|---| | Companies | `companies` | `domains` | | People | `people` | `email_addresses` | | Deals | `deals` | Usually no global dedupe key; link to company/person records |
Custom objects use their configured API slug. Discover them with `GET /v2/objects`.
curl -sS "https://api.attio.com/v2/objects" \
-H "Authorization: Bearer $ATTIO_API_KEY" \
-H "Accept: application/json" \
| jq '.data[] | {slug: .api_slug, name: .title}'curl -sS -X POST "https://api.attio.com/v2/objects/companies/records/query" \
-H "Authorization: Bearer $ATTIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filter": {
"stage": { "$not_equal": "Won" }
},
"limit": 100,
"offset": 0
}' | jq '.data[] | {record_id: .id.record_id, name: .values.name[0].value}'Paginate by increasing `offset` until `data` is empty. For no filter, omit the `filter` key.
curl -sS "https://api.attio.com/v2/objects/companies/records/{RECORD_ID}" \
-H "Authorization: Bearer $ATTIO_API_KEY" \
-H "Accept: application/json" \
| jq '.data.values'Use `PUT` with `matching_attribute`. It creates if not found and updates if found, so it is safe to call repeatedly.
curl -sS -X PUT "https://api.attio.com/v2/objects/companies/records" \
-H "Authorization: Bearer $ATTIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"values": {
"name": [{ "value": "Acme Corp" }],
"domains": [{ "domain": "acme.com" }],
"employee_count": [{ "value": 150 }]
}
},
"matching_attribute": "domains"
}' | jq '{record_id: .data.id.record_id}'curl -sS -X PUT "https://api.attio.com/v2/objects/people/records" \
-H "Authorization: Bearer $ATTIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"values": {
"name": [{ "first_name": "Jane", "last_name": "Doe" }],
"email_addresses": [{ "email_address": "jane@acme.com" }],
"job_title": [{ "value": "CTO" }]
}
},
"matching_attribute": "email_addresses"
}' | jq '{record_id: .data.id.record_id}'An upsert returns HTTP `200` when it updates an existing record and `201` when it creates one. The response body has the same shape in both cases.
curl -sS -X PATCH "https://api.attio.com/v2/objects/companies/records/{RECORD_ID}" \
-H "Authorization: Bearer $ATTIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"values": {
"icp_score": [{ "value": 85 }],
"icp_tier": [{ "value": "Tier 1" }]
}
}
}'Notes are concise free-text entries linked to a record. Use them to preserve useful interaction context, enrichment findings, or an agent result that should remain visible in the CRM.
curl -sS -X POST "https://api.attio.com/v2/notes" \
-H "Authorization: Bearer $ATTIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"parent_object": "companies",
"parent_record_id": "{RECORD_ID}",
"title": "Enrichment - 2026-06-02",
"content": "Employee count: 150. Funding stage: Series A. Tech stack: Node.js, React."
}
}' | jq '{note_id: .data.id.note_id}'curl -sS "https://api.attio.com/v2/workspace_members" \
-H "Authorization: Bearer $ATTIO_API_KEY" \
-H "Accept: application/json" \
| jq '.data[] | {member_id: .id.workspace_member_id, name: .name, email: .email_address}'
curl -sS -X POST "https://api.attio.com/v2/tasks" \
-H "Authorization: Bearer $ATTIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"content": "Follow up - no contact in 21 days",
"is_completed": false,
"assignees": [
{ "referenced_actor_type": "workspace-member", "referenced_actor_id": "{MEMBER_ID}" }
],
"linked_records": [
{ "target_object": "deals", "target_record_id": "{DEAL_RECORD_ID}" }
]
}
}' | jq '{task_id: .data.id.task_id}'curl -sS -X POST "https://api.attio.com/v2/comments" \
-H "Authorization: Bearer $ATTIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"record": { "target_object": "companies", "target_recRepo: desplega-ai/agent-swarm
Install, self-host, deploy, operate, or use agent-swarm. Covers Docker Compose, Kubernetes,…
Rebuild the feel of a reference motion-design clip (camera, depth of field, easing, captions,…
Reverse-engineer a short motion-design / product-update video (animation technique, timing…
Make a design-led motion-graphics video (showreel, eval comparison, feature or bug-hunt…
How to generate repo-committed video content (README hero videos, case-study clips, landing…
Read the task-digest extension's output. Use when someone asks how many tasks completed or…