phphttpintegration

PHP Integration

Send logs from PHP applications to ScryWatch using plain HTTP — no SDK required.

PHP Integration

ScryWatch accepts logs over HTTP — no PHP SDK required. Use curl, Guzzle, or any HTTP client to send events to the ingest endpoint.

What you’ll need

Endpoint

POST https://ingest.scrywatch.com/v1/ingest
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

Step 1: Send a log event

<?php

function scrywatch_log(string $apiKey, string $level, string $message, array $metadata = []): void {
    $payload = json_encode([
        'events' => [[
            'timestamp'   => (int) (microtime(true) * 1000),
            'level'       => $level,         // 'info' | 'warn' | 'error' | 'debug'
            'type'        => 'custom',
            'message'     => $message,
            'service'     => $_ENV['APP_SERVICE'] ?? 'php-app',
            'environment' => $_ENV['APP_ENV'] ?? 'production',
            'metadata'    => $metadata ?: null,
        ]],
    ]);

    $ch = curl_init('https://ingest.scrywatch.com/v1/ingest');
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => $payload,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER     => [
            'Authorization: Bearer ' . $apiKey,
            'Content-Type: application/json',
        ],
        CURLOPT_TIMEOUT        => 5,
    ]);
    curl_exec($ch);
    curl_close($ch);
}

// Usage
scrywatch_log('YOUR_API_KEY', 'info', 'User signed up', ['user_id' => '123']);
scrywatch_log('YOUR_API_KEY', 'error', 'Payment failed', ['order_id' => '456', 'reason' => 'card_declined']);

Step 2: Batch multiple events

Send up to 250 events in one request to reduce overhead:

<?php

function scrywatch_batch(string $apiKey, array $events): array {
    $payload = json_encode(['events' => $events]);

    $ch = curl_init('https://ingest.scrywatch.com/v1/ingest');
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => $payload,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER     => [
            'Authorization: Bearer ' . $apiKey,
            'Content-Type: application/json',
        ],
        CURLOPT_TIMEOUT        => 10,
    ]);
    $body = curl_exec($ch);
    curl_close($ch);
    return json_decode($body, true) ?? [];
    // Returns: ['accepted_count' => N, 'rejected_count' => N, ...]
}

// Build and send a batch
$events = [];
foreach ($errors as $err) {
    $events[] = [
        'timestamp'   => (int) (microtime(true) * 1000),
        'level'       => 'error',
        'type'        => 'custom',
        'message'     => $err->getMessage(),
        'service'     => 'php-app',
        'environment' => 'production',
        'metadata'    => [
            'file' => $err->getFile(),
            'line' => $err->getLine(),
        ],
    ];
}
scrywatch_batch('YOUR_API_KEY', $events);

Step 3: Laravel — log channel integration

Add a custom log channel to config/logging.php:

'channels' => [
    'scrywatch' => [
        'driver'  => 'monolog',
        'handler' => \App\Logging\ScryWatchHandler::class,
        'with'    => [
            'apiKey' => env('SCRYWATCH_API_KEY'),
        ],
    ],
],

Create app/Logging/ScryWatchHandler.php:

<?php

namespace App\Logging;

use Monolog\Handler\AbstractProcessingHandler;
use Monolog\LogRecord;

class ScryWatchHandler extends AbstractProcessingHandler
{
    public function __construct(private string $apiKey, int $level = 0)
    {
        parent::__construct($level);
    }

    protected function write(LogRecord $record): void
    {
        scrywatch_log(
            $this->apiKey,
            strtolower($record->level->name),
            $record->message,
            $record->context
        );
    }
}

Set in .env:

SCRYWATCH_API_KEY=your_key_here
LOG_CHANNEL=scrywatch

Event fields reference

FieldTypeRequiredDescription
timestampnumberUnix milliseconds — use (int)(microtime(true) * 1000)
levelstringinfo | warn | error | debug
typestringcustom | crash | session | navigation | api_call
messagestringLog message
servicestringService name
environmentstringe.g. production, staging
user_idstringUser identifier
session_idstringSession identifier
metadataobjectAny additional key/value pairs

OpenTelemetry note

If you are already running an OpenTelemetry Collector, you can route traces to ScryWatch via the OTLP endpoint. For logs, use the HTTP ingest endpoint above — OTLP log ingestion is not yet supported.

See the OpenTelemetry guide for Collector pipeline configuration.

← All guides