auditrails / auditrails-php
Official PHP SDK for auditrails.io — tamper-proof audit logging as a service
Requires
- php: ^8.1
- psr/http-client: ^1.0
- psr/http-factory: ^1.0
- psr/log: ^2.0 || ^3.0
Requires (Dev)
- guzzlehttp/guzzle: ^7.0
- phpunit/phpunit: ^10.0 || ^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-14 15:37:44 UTC
README
Official PHP SDK for auditrails.io — tamper-proof audit logging as a service.
Install
composer require auditrails/auditrails-php
Requires PHP 8.1+ and a PSR-18 HTTP client (Guzzle, Symfony HTTP Client, etc.).
Quick Start
use AuditRails\AuditEvent; use AuditRails\AuditRails; use AuditRails\Config; use GuzzleHttp\Client; use GuzzleHttp\Psr7\HttpFactory; $audit = new AuditRails( config: new Config(apiKey: $_ENV['AUDITRAILS_API_KEY']), httpClient: new Client(['timeout' => 10]), requestFactory: new HttpFactory(), streamFactory: new HttpFactory(), ); // Fire-and-forget (buffered, auto-flushed at shutdown) $audit->log(new AuditEvent( action: ComplianceAction::AUTH_LOGIN, // typed compliance action constant actorId: 'user_123', resource: 'session/sess_456', metadata: ['ip' => '1.2.3.4'], )); // Events flush automatically via register_shutdown_function
That's it. Your first audit event in under 2 minutes.
Test mode (sandbox)
Every API key has a mode — live or test — set when the key is created in the dashboard. Test keys are designed for integration and CI:
- Prefix:
at_test_…(live keys useat_live_…). - Billing: Test traffic is free — never counted toward your monthly quota, never reaches Stripe.
- Rate limit: Test keys share a separate, smaller pool (default 60 req/s) so a leaked test key can't be used to exhaust your live capacity.
- Reports: Test events never appear in compliance reports, scheduled exports, or usage aggregates.
- Retention: 7 days in hot storage. Test data is non-durable by design; do not rely on it for evidence.
Use a test key in dev/staging and during your CI integration tests; switch to a live key in production. No SDK config changes — just pass whichever key the dashboard issued:
// Development / CI $audit = new AuditRails(config: new Config(apiKey: 'at_test_…'), /* ... */); // Production $audit = new AuditRails(config: new Config(apiKey: 'at_live_…'), /* ... */);
Compliance Action Constants
The SDK includes ComplianceAction class with typed constants for all 42 compliance actions:
use AuditRails\ComplianceAction; $audit->log(new AuditEvent(action: ComplianceAction::AUTH_LOGIN, actorId: 'user_1')); $audit->log(new AuditEvent(action: ComplianceAction::CONSENT_GIVEN, actorId: 'user_1')); $audit->log(new AuditEvent(action: ComplianceAction::PHI_ACCESSED, actorId: 'user_1', resource: 'patient/123'));
Raw strings are still accepted for backward compatibility.
PSR-18 HTTP Client
The SDK works with any PSR-18 compliant HTTP client. Pass your own ClientInterface, RequestFactoryInterface, and StreamFactoryInterface to the constructor:
use AuditRails\AuditRails; use AuditRails\Config; // With Guzzle $audit = new AuditRails( config: new Config(apiKey: '...'), httpClient: new \GuzzleHttp\Client(['timeout' => 10]), requestFactory: new \GuzzleHttp\Psr7\HttpFactory(), streamFactory: new \GuzzleHttp\Psr7\HttpFactory(), ); // With Symfony HTTP Client $audit = new AuditRails( config: new Config(apiKey: '...'), httpClient: new \Symfony\Component\HttpClient\Psr18Client(), requestFactory: new \Nyholm\Psr7\Factory\Psr17Factory(), streamFactory: new \Nyholm\Psr7\Factory\Psr17Factory(), );
API
new AuditRails(config, httpClient, requestFactory, streamFactory, logger?)
| Option | Type | Description |
|---|---|---|
config |
Config |
Configuration object (see below) |
httpClient |
ClientInterface |
PSR-18 HTTP client |
requestFactory |
RequestFactoryInterface |
PSR-17 request factory |
streamFactory |
StreamFactoryInterface |
PSR-17 stream factory |
logger |
?LoggerInterface |
Optional PSR-3 logger (defaults to NullLogger) |
Config
| Option | Type | Default | Description |
|---|---|---|---|
apiKey |
string |
required | Your API key (at_live_... or at_test_...) |
baseUrl |
string |
https://api.auditrails.io |
Ingestion API URL |
batchSize |
int |
100 |
Max events per batch (max 100) |
maxRetries |
int |
3 |
Retry attempts for 5xx errors |
timeout |
int |
10 |
Request timeout in seconds |
autoShutdown |
bool |
true |
Auto-flush via register_shutdown_function |
$audit->log(AuditEvent)
Buffer an event for batch sending. Never throws — errors are logged silently.
$audit->log(new AuditEvent( action: 'document.created', // required actorId: 'user_123', // who did it resource: 'document/doc-456', // what was affected metadata: ['key' => 'value'], // extra context (max 10 keys) ));
$audit->logDirect(AuditEvent): LogResponse
Send a single event immediately. Throws AuditRailsError on API errors.
$response = $audit->logDirect(new AuditEvent(action: 'user.deleted', actorId: 'admin_1')); echo $response->logId; // "01HX..." echo $response->requestId; // "req_01HX..."
$audit->logBatchDirect(AuditEvent[]): BatchResponse
Send a batch of events immediately. Throws on error.
$audit->flush(): void
Flush all buffered events immediately.
$audit->close(): void
Flush and shut down. After close(), log() calls are silently ignored.
Error Handling
The SDK never crashes your application:
log()never throws — errors are logged via PSR-3 loggerlogDirect()andlogBatchDirect()throwAuditRailsErroron API errors- 5xx errors are retried with exponential backoff
- 4xx errors fail immediately (no retry)
use AuditRails\AuditRailsError; try { $audit->logDirect(new AuditEvent(action: 'test')); } catch (AuditRailsError $e) { echo $e->errorCode; // 'validation/missing_action' echo $e->statusCode; // 422 echo $e->requestId; // 'req_...' echo $e->docUrl; // link to docs }
License
MIT