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
Requires
- php: ^8.4
- guzzlehttp/guzzle: ^7.0
- illuminate/support: ^11.0
Requires (Dev)
- orchestra/testbench: ^9.0
- phpunit/phpunit: ^11.0
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.