Every event uses one envelope:
{
"id": "evt_01j...",
"session_id": "ses_01j...",
"run_id": "run_01j...",
"sequence": 42,
"type": "tool.call.requested",
"occurred_at": "2026-08-24T21:15:12.381Z",
"payload": {
"tool_call_id": "call_01j...",
"tool": "dataforseo.keyword_ideas",
"arguments": { "keyword": "AI receptionist" }
}
}
The core types:
run.created · run.queued · run.started · text.delta · reasoning.delta · step.started · step.completed · tool.call.requested · tool.call.completed · tool.call.failed · approval.requested · approval.resolved · artifact.created · usage.updated · checkpoint.created · run.awaiting_approval · run.completed · run.failed · run.cancelled · run.budget_exceeded
Listen through Laravel events, with no dependency on the transport:
use Clutch\Laravel\Events\ClutchEventRecorded;
Event::listen(ClutchEventRecorded::class, function (ClutchEventRecorded $event) {
// Audit, analytics, metering, notifications, or your own broadcasting.
});
Redaction
Redaction runs before persistence, not before display, so a configured key never reaches the database:
'events' => [
'redact' => ['authorization', 'api_key', 'token', 'password', 'secret'],
],
Tool arguments often carry business sensitive values that are not secrets. Register a serializer that keeps only the fields you approve:
class EmailEventSerializer implements EventSerializer
{
public function serialize(array $payload): array
{
return [
'tool' => $payload['tool'],
'arguments' => ['recipient_count' => count($payload['arguments']['to'])],
];
}
}
'events' => [
'serializers' => ['send_email' => EmailEventSerializer::class],
],