Claude-code-plugins-plus-skills attio-install-auth

install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/attio-pack/skills/attio-install-auth" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-skills-attio-install-auth && rm -rf "$T"
manifest: plugins/saas-packs/attio-pack/skills/attio-install-auth/SKILL.md
source content

Attio Install & Auth

Overview

Configure authentication for the Attio REST API (

https://api.attio.com/v2
). Attio offers two auth methods: access tokens (scoped to a single workspace) and OAuth 2.0 (for multi-workspace integrations). There is no official first-party Node SDK -- use
fetch
or a community client like
attio-js
.

Prerequisites

  • Node.js 18+ or Python 3.10+
  • Attio account at app.attio.com
  • API access enabled in workspace settings

Instructions

Step 1: Generate an Access Token

  1. Open Settings > Developers > Access tokens in your Attio workspace
  2. Click Create token and name it (e.g.,
    my-integration-dev
    )
  3. Configure scopes (tokens have no scopes by default -- you must add them):
ScopeGrants access to
object_configuration:read
List/get objects and attributes
record_permission:read
Read records (people, companies, deals)
record_permission:read-write
Create/update/delete records
list_entry:read
Read list entries
list_entry:read-write
Create/update/delete list entries
note:read-write
Create and read notes
task:read
/
task:read-write
Read or manage tasks
user_management:read
Read workspace members
webhook:read-write
Manage webhooks
  1. Copy the token -- it starts with
    sk_
    and never expires (but can be revoked)

Step 2: Configure Environment

# .env (add to .gitignore immediately)
ATTIO_API_KEY=sk_your_token_here

# .gitignore
.env
.env.local
.env.*.local

Step 3: Initialize the Client

// src/attio/client.ts
const ATTIO_BASE = "https://api.attio.com/v2";

interface AttioRequestOptions {
  method?: string;
  path: string;
  body?: Record<string, unknown>;
}

export async function attioFetch<T>({
  method = "GET",
  path,
  body,
}: AttioRequestOptions): Promise<T> {
  const res = await fetch(`${ATTIO_BASE}${path}`, {
    method,
    headers: {
      Authorization: `Bearer ${process.env.ATTIO_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: body ? JSON.stringify(body) : undefined,
  });

  if (!res.ok) {
    const error = await res.json();
    throw new Error(
      `Attio ${res.status}: ${error.code} - ${error.message}`
    );
  }

  return res.json() as Promise<T>;
}

Step 4: Verify Connection

// Verify by listing workspace objects
const objects = await attioFetch<{ data: Array<{ api_slug: string }> }>({
  path: "/objects",
});

console.log(
  "Connected! Objects:",
  objects.data.map((o) => o.api_slug)
);
// Output: Connected! Objects: ["people", "companies", "deals", ...]
# Quick verification with curl
curl -s https://api.attio.com/v2/objects \
  -H "Authorization: Bearer ${ATTIO_API_KEY}" | jq '.data[].api_slug'

OAuth 2.0 Flow (Multi-Workspace)

For apps that other workspaces install, use OAuth 2.0 Authorization Code Grant (RFC 6749 section 4.1).

// Step 1: Redirect user to authorize
const authUrl = new URL("https://app.attio.com/authorize");
authUrl.searchParams.set("client_id", process.env.ATTIO_CLIENT_ID!);
authUrl.searchParams.set("redirect_uri", "https://yourapp.com/callback");
authUrl.searchParams.set("response_type", "code");

// Step 2: Exchange code for access token
const tokenRes = await fetch("https://app.attio.com/oauth/token", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    grant_type: "authorization_code",
    client_id: process.env.ATTIO_CLIENT_ID,
    client_secret: process.env.ATTIO_CLIENT_SECRET,
    code: authorizationCode,
    redirect_uri: "https://yourapp.com/callback",
  }),
});

const { access_token } = await tokenRes.json();
// Store access_token securely per workspace

Error Handling

ErrorHTTP StatusCauseSolution
invalid_grant
401Bad or expired auth codeRe-authorize the user
insufficient_scopes
403Token missing required scopeAdd scope in dashboard, regenerate
invalid_request
400Malformed Authorization headerUse
Bearer <token>
format
not_found
404Token revoked or workspace deletedGenerate new token

Attio Error Response Format

All Attio errors return JSON with a consistent structure:

{
  "status_code": 403,
  "type": "authorization_error",
  "code": "insufficient_scopes",
  "message": "Token requires 'record_permission:read' scope"
}

Resources

Next Steps

After verifying auth, proceed to

attio-hello-world
for your first real API call.