> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getimmutable.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel SDK

> First-party Laravel package for the Immutable API.

## Installation

```bash theme={null}
composer require getimmutable/laravel
```

**Requirements:** PHP 8.2+, Laravel 10+

## Configuration

Add your credentials to `.env`:

```env theme={null}
GETIMMUTABLE_API_KEY=imk_your_api_key_here
GETIMMUTABLE_BASE_URL=https://getimmutable.dev
GETIMMUTABLE_ASYNC=false
```

| Variable                | Required | Description                                        |
| ----------------------- | -------- | -------------------------------------------------- |
| `GETIMMUTABLE_API_KEY`  | Yes      | Your `imk_` prefixed API key                       |
| `GETIMMUTABLE_BASE_URL` | Yes      | Base domain URL                                    |
| `GETIMMUTABLE_ASYNC`    | No       | Set `true` to dispatch tracking via Laravel queues |

### Service Provider

The package auto-discovers `GetImmutable\GetImmutableServiceProvider`. No manual registration needed.

### Facade

```php theme={null}
use GetImmutable\AuditLog;
```

## Tracking Events

### Basic Usage

```php theme={null}
use GetImmutable\AuditLog;

AuditLog::track('document.created', 'document', [
    'actor_id' => 'user_2hG9kLm',
    'actor_name' => 'Sarah Chen',
    'actor_type' => 'user',
    'resource_id' => 'doc_8nXpQr3',
    'resource_name' => 'Q4 Financial Report',
    'metadata' => ['folder' => 'reports', 'template' => 'quarterly'],
]);
```

### Fluent Builder

```php theme={null}
use GetImmutable\AuditLog;

AuditLog::actor($user)
    ->idempotencyKey('unique_key_123')
    ->version(1)
    ->session('sess_4kN8pLm')
    ->actionCategory('documents')
    ->target('folder', 'folder_3mK9pLq', 'Shared Reports')
    ->target('team', 'team_5bR7cNx', 'Engineering')
    ->track('document.created', 'document', [
        'folder' => 'reports',
        'template' => 'quarterly',
    ]);

// Or use the currently authenticated user
AuditLog::fromAuth()
    ->track('document.created', $document, [
        'folder' => 'reports',
    ]);
```

#### PendingEvent Methods

| Method                                   | Parameters               | Description              |
| ---------------------------------------- | ------------------------ | ------------------------ |
| `idempotencyKey($key)`                   | string                   | Set deduplication key    |
| `version($v)`                            | int                      | Set event schema version |
| `session($id)`                           | string                   | Set session identifier   |
| `actionCategory($cat)`                   | string                   | Set action category      |
| `target($type, $id?, $name?)`            | string, string?, string? | Add a single target      |
| `targets($arr)`                          | array                    | Set all targets at once  |
| `track($action, $resource?, $metadata?)` | string, string?, array?  | Send the event           |

## Batch Ingestion

```php theme={null}
use GetImmutable\AuditLog;

AuditLog::trackBatch([
    [
        'actor_id' => 'user_2hG9kLm',
        'actor_name' => 'Sarah Chen',
        'action' => 'document.created',
        'resource_id' => 'doc_8nXpQr3',
        'resource_name' => 'Q4 Financial Report',
    ],
    [
        'actor_id' => 'user_2hG9kLm',
        'actor_name' => 'Sarah Chen',
        'action' => 'document.shared',
        'resource_id' => 'doc_8nXpQr3',
        'targets' => [
            ['type' => 'team', 'id' => 'team_5bR7cNx', 'name' => 'Engineering'],
        ],
    ],
]);
```

## Querying Events

```php theme={null}
$response = AuditLog::getEvents([
    'actor_id' => 'user_2hG9kLm',
    'action' => 'document.*',
    'from' => '2026-03-01T00:00:00Z',
    'limit' => 25,
]);

// $response['data'] -- array of events
// $response['pagination']['has_more'] -- boolean
// $response['pagination']['next_cursor'] -- string|null
```

## Retrieving a Single Event

```php theme={null}
$event = AuditLog::getEvent('9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d');

$event['integrity']['event_hash'];
$event['integrity']['previous_event_hash'];
```

## Verification

```php theme={null}
$result = AuditLog::verify();

if (!$result['data']['valid']) {
    Log::critical('Audit log integrity violation', [
        'breaks' => $result['data']['breaks'],
    ]);
}

// With date range
$result = AuditLog::verify('2026-03-01T00:00:00Z', '2026-03-31T23:59:59Z');

// With custom limit (default: 10000)
$result = AuditLog::verify(null, null, 1000);
```

## Viewer Tokens

```php theme={null}
$token = AuditLog::createViewerToken([
    'tenantId' => 'org_7rT2xBc',
    'actorId' => 'user_2hG9kLm',
    'ttl' => 7200,
]);

$token['token'];      // JWT string
$token['expires_at']; // Unix timestamp (integer)
```

## Alerts

```php theme={null}
$alerts = AuditLog::getAlerts([
    'rule_type' => 'new_country',
    'limit' => 25,
]);
```

## Exports

```php theme={null}
$export = AuditLog::createExport([
    'actor_id' => 'user_2hG9kLm',
    'from' => '2026-03-01T00:00:00Z',
]);

$status = AuditLog::getExport($export['data']['id']);
// $status['data']['status'] -- 'pending', 'processing', 'completed', or 'failed'
```

## Anchors

```php theme={null}
// List blockchain anchors
$anchors = AuditLog::client()->getAnchors(10);

foreach ($anchors['data'] as $anchor) {
    echo "{$anchor['merkle_root']} — {$anchor['status']} — {$anchor['explorer_url']}";
}

// Get anchor details
$anchor = AuditLog::client()->getAnchor('anchor-uuid');
$anchor['data']['first_event_hash'];
$anchor['data']['last_event_hash'];

// Verify anchor integrity
$result = AuditLog::client()->verifyAnchor('anchor-uuid');
$result['data']['valid'];       // Merkle root matches events
$result['data']['chain_valid']; // Anchor chain is intact
```

## Auto-Session Tracking

The Laravel SDK can automatically attach the current Laravel session ID to every tracked event. Enable this in your configuration:

```php theme={null}
// Auto-session reads from Laravel's session store
// No explicit ->session() calls needed
```

## Eloquent Observer Example

Track model events automatically using an Eloquent observer:

```php theme={null}
namespace App\Observers;

use App\Models\Document;
use GetImmutable\AuditLog;

class DocumentObserver
{
    public function created(Document $document): void
    {
        AuditLog::fromAuth()
            ->track('document.created', $document, [
                'size' => $document->size,
                'mime_type' => $document->mime_type,
            ]);
    }

    public function updated(Document $document): void
    {
        AuditLog::fromAuth()
            ->track('document.updated', $document, [
                'changed_fields' => array_keys($document->getDirty()),
            ]);
    }

    public function deleted(Document $document): void
    {
        AuditLog::fromAuth()
            ->track('document.deleted', $document);
    }
}
```

Register the observer in your `AppServiceProvider`:

```php theme={null}
use App\Models\Document;
use App\Observers\DocumentObserver;

public function boot(): void
{
    Document::observe(DocumentObserver::class);
}
```

## Queue Integration

Set `GETIMMUTABLE_ASYNC=true` in your `.env` to dispatch tracking calls via Laravel's queue system instead of making synchronous HTTP requests. This prevents audit logging from blocking your application's response time.

```env theme={null}
GETIMMUTABLE_ASYNC=true
```

Ensure your queue worker is running to process the dispatched jobs.
