aurabx/laravel-attio

A Laravel client for the Attio CRM REST API

Installs: 0

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/aurabx/laravel-attio

1.0.0 2025-12-15 23:06 UTC

This package is auto-updated.

Last update: 2025-12-15 23:08:51 UTC


README

A Laravel client for the Attio CRM REST API.

Installation

Install the package via Composer:

composer require aurabx/laravel-attio

The package will automatically register its service provider.

Publish Configuration

Publish the configuration file:

php artisan vendor:publish --tag=attio-config

Configuration

Add your Attio API key to your .env file:

ATTIO_API_KEY=your-api-key-here

You can generate an API key from your Attio workspace settings under the Developers tab.

Configuration Options

The following configuration options are available in config/attio.php:

return [
    'api_key' => env('ATTIO_API_KEY'),
    'base_url' => env('ATTIO_BASE_URL', 'https://api.attio.com/v2'),
    'timeout' => env('ATTIO_TIMEOUT', 30),
    'connect_timeout' => env('ATTIO_CONNECT_TIMEOUT', 10),
    'retry' => [
        'enabled' => env('ATTIO_RETRY_ENABLED', true),
        'max_attempts' => env('ATTIO_RETRY_MAX_ATTEMPTS', 3),
        'delay_ms' => env('ATTIO_RETRY_DELAY_MS', 1000),
    ],
];

Usage

Using the Facade

use Aurabox\LaravelAttio\Facades\Attio;

// Identify the current access token
$identity = Attio::identify();

// List all objects
$objects = Attio::objects()->list();

// Query people records
$people = Attio::records()->query('people', [
    'filter' => [
        'name' => 'Ada Lovelace',
    ],
    'limit' => 10,
]);

Using Dependency Injection

use Aurabox\LaravelAttio\AttioClient;

class ContactController extends Controller
{
    public function __construct(
        private AttioClient $attio
    ) {}

    public function index()
    {
        return $this->attio->records()->query('people');
    }
}

API Resources

Objects

// List all objects
Attio::objects()->list();

// Get a single object
Attio::objects()->get('people');

// Create a custom object
Attio::objects()->create([
    'api_slug' => 'projects',
    'singular_noun' => 'Project',
    'plural_noun' => 'Projects',
]);

// Update an object
Attio::objects()->update('projects', [
    'singular_noun' => 'Project',
]);

Attributes

// List attributes for an object
Attio::attributes()->list('people');

// Get a single attribute
Attio::attributes()->get('people', 'email_addresses');

// Create an attribute
Attio::attributes()->create('people', [
    'title' => 'Custom Field',
    'api_slug' => 'custom_field',
    'type' => 'text',
]);

// List attributes for a list
Attio::attributes()->listForList('sales-pipeline');

Records

// Query records with filtering and sorting
$records = Attio::records()->query('people', [
    'filter' => [
        'email_addresses' => [
            'email_address' => 'ada@example.com',
        ],
    ],
    'sorts' => [
        [
            'attribute' => 'name',
            'direction' => 'asc',
        ],
    ],
    'limit' => 100,
    'offset' => 0,
]);

// Get a single record
$record = Attio::records()->get('people', 'record-uuid');

// Create a record
$record = Attio::records()->create('people', [
    'values' => [
        'name' => [
            [
                'first_name' => 'Ada',
                'last_name' => 'Lovelace',
            ],
        ],
        'email_addresses' => [
            ['email_address' => 'ada@example.com'],
        ],
    ],
]);

// Update a record (overwrite multiselect values)
Attio::records()->update('people', 'record-uuid', [
    'values' => [
        'job_title' => [['value' => 'Engineer']],
    ],
]);

// Update a record (append multiselect values)
Attio::records()->patch('people', 'record-uuid', [
    'values' => [
        'tags' => [['value' => 'new-tag']],
    ],
]);

// Delete a record
Attio::records()->delete('people', 'record-uuid');

// List attribute values for a record
Attio::records()->listAttributeValues('people', 'record-uuid', 'email_addresses');

// List all entries for a record
Attio::records()->listEntries('people', 'record-uuid');

Lists

// List all lists
Attio::lists()->list();

// Get a single list
Attio::lists()->get('sales-pipeline');

// Create a list
Attio::lists()->create([
    'name' => 'Sales Pipeline',
    'api_slug' => 'sales-pipeline',
    'parent_object' => 'companies',
]);

// Update a list
Attio::lists()->update('sales-pipeline', [
    'name' => 'Updated Sales Pipeline',
]);

// Delete a list
Attio::lists()->delete('sales-pipeline');

Entries

// Query entries in a list
$entries = Attio::entries()->query('sales-pipeline', [
    'filter' => [
        'status' => 'In Progress',
    ],
    'limit' => 100,
]);

// Get a single entry
$entry = Attio::entries()->get('sales-pipeline', 'entry-uuid');

// Create an entry (add a record to a list)
Attio::entries()->create('sales-pipeline', [
    'parent_record_id' => 'company-record-uuid',
    'entry_values' => [
        'status' => [['status_id' => 'status-uuid']],
    ],
]);

// Update an entry
Attio::entries()->update('sales-pipeline', 'entry-uuid', [
    'entry_values' => [
        'status' => [['status_id' => 'new-status-uuid']],
    ],
]);

// Delete an entry
Attio::entries()->delete('sales-pipeline', 'entry-uuid');

// Assert an entry by parent record
Attio::entries()->assertByParent('sales-pipeline', [
    'parent_record_id' => 'company-record-uuid',
    'entry_values' => [
        'status' => [['status_id' => 'status-uuid']],
    ],
]);

Notes

// List all notes
Attio::notes()->list(['limit' => 100]);

// Get a single note
Attio::notes()->get('note-uuid');

// Create a note
Attio::notes()->create([
    'parent_object' => 'people',
    'parent_record_id' => 'record-uuid',
    'title' => 'Meeting Notes',
    'format' => 'plaintext',
    'content' => 'Discussion points from our call...',
]);

// Delete a note
Attio::notes()->delete('note-uuid');

Tasks

// List all tasks
Attio::tasks()->list([
    'assignee' => 'workspace-member-uuid',
    'is_completed' => false,
    'limit' => 100,
]);

// Get a single task
Attio::tasks()->get('task-uuid');

// Create a task
Attio::tasks()->create([
    'content' => 'Follow up with customer',
    'format' => 'plaintext',
    'deadline_at' => '2024-01-15',
    'linked_records' => [
        [
            'target_object' => 'people',
            'target_record_id' => 'record-uuid',
        ],
    ],
    'assignees' => [
        [
            'referenced_actor_type' => 'workspace-member',
            'referenced_actor_id' => 'member-uuid',
        ],
    ],
]);

// Update a task
Attio::tasks()->update('task-uuid', [
    'content' => 'Updated task content',
]);

// Complete a task
Attio::tasks()->complete('task-uuid');

// Mark task as incomplete
Attio::tasks()->incomplete('task-uuid');

// Delete a task
Attio::tasks()->delete('task-uuid');

Threads & Comments

// List all threads
Attio::threads()->list();

// Get a thread
Attio::threads()->get('thread-uuid');

// Get a comment
Attio::comments()->get('comment-uuid');

// Create a comment
Attio::comments()->create([
    'thread_id' => 'thread-uuid',
    'format' => 'plaintext',
    'content' => 'This is a comment',
]);

// Delete a comment
Attio::comments()->delete('comment-uuid');

Meetings

// List all meetings
Attio::meetings()->list(['limit' => 100]);

// Get a single meeting
Attio::meetings()->get('meeting-uuid');

Webhooks

// List all webhooks
Attio::webhooks()->list();

// Get a single webhook
Attio::webhooks()->get('webhook-uuid');

// Create a webhook
Attio::webhooks()->create([
    'target_url' => 'https://your-app.com/webhooks/attio',
    'subscriptions' => [
        ['event_type' => 'record.created', 'filter' => ['object' => 'people']],
        ['event_type' => 'record.updated', 'filter' => ['object' => 'people']],
    ],
]);

// Update a webhook
Attio::webhooks()->update('webhook-uuid', [
    'target_url' => 'https://your-app.com/webhooks/attio-v2',
]);

// Delete a webhook
Attio::webhooks()->delete('webhook-uuid');

Workspace Members

// List all workspace members
Attio::workspaceMembers()->list();

// Get a single workspace member
Attio::workspaceMembers()->get('member-uuid');

Raw API Requests

You can also make raw API requests:

// GET request
$response = Attio::get('/objects');

// POST request
$response = Attio::post('/objects/people/records/query', [
    'filter' => ['name' => 'Ada'],
]);

// PUT request
$response = Attio::put('/objects/people/records/record-uuid', [
    'data' => ['values' => ['name' => [['first_name' => 'Ada']]]],
]);

// PATCH request
$response = Attio::patch('/objects/people/records/record-uuid', [
    'data' => ['values' => ['job_title' => [['value' => 'Engineer']]]],
]);

// DELETE request
$response = Attio::delete('/objects/people/records/record-uuid');

Error Handling

The package throws specific exceptions for different error types:

use Aurabox\LaravelAttio\Exceptions\AttioException;
use Aurabox\LaravelAttio\Exceptions\AuthenticationException;
use Aurabox\LaravelAttio\Exceptions\NotFoundException;
use Aurabox\LaravelAttio\Exceptions\ValidationException;
use Aurabox\LaravelAttio\Exceptions\RateLimitException;

try {
    $record = Attio::records()->get('people', 'non-existent-uuid');
} catch (NotFoundException $e) {
    // Record not found (404)
    $message = $e->getMessage();
} catch (AuthenticationException $e) {
    // Authentication failed (401)
} catch (ValidationException $e) {
    // Validation error (422)
    $errors = $e->getErrors();
} catch (RateLimitException $e) {
    // Rate limit exceeded (429)
    $retryAfterSeconds = $e->getRetryAfterSeconds();
} catch (AttioException $e) {
    // Other API errors
    $response = $e->getResponse();
    $errorData = $e->getErrorData();
}

Rate Limiting

The package automatically handles rate limiting with exponential backoff. You can configure the retry behavior:

ATTIO_RETRY_ENABLED=true
ATTIO_RETRY_MAX_ATTEMPTS=3
ATTIO_RETRY_DELAY_MS=1000

Testing

For testing, you can mock the AttioClient:

use Aurabox\LaravelAttio\AttioClient;

$this->mock(AttioClient::class
    $mock->shouldReceive('records->query')
        ->with('people', [])
        ->andReturn(['data' => []]);
});

License

The MIT License (MIT). Please see License File for more information.