pyrx / synapse
Official PHP SDK for PYRX Synapse - CRM, email, and event tracking API
v0.1.0
2026-05-01 16:18 UTC
Requires
- php: >=8.1
- ext-curl: *
- ext-json: *
Requires (Dev)
- phpunit/phpunit: ^10.0
README
Official PHP SDK for PYRX Synapse -- CRM, email, and event tracking API.
Zero runtime dependencies. Uses PHP's built-in curl, json, and hash extensions.
Requirements
- PHP >= 8.1
- ext-curl
- ext-json
Installation
composer require pyrx/synapse
Quick Start
use PyrxSynapse\Client; $client = new Client( apiKey: 'psk_live_your_api_key', workspaceId: 'ws_your_workspace_id', ); // Track an event $result = $client->track( externalId: 'user_123', eventName: 'purchase', attributes: ['amount' => 99.99, 'currency' => 'USD'], ); echo $result['event_id']; // "evt_..." // Identify a contact $contact = $client->identify( externalId: 'user_123', email: 'jane@example.com', firstName: 'Jane', lastName: 'Doe', properties: ['plan' => 'pro'], tags: ['paying', 'onboarded'], ); // Send a transactional email $email = $client->sendEmail( templateSlug: 'welcome', to: ['email' => 'jane@example.com'], attributes: ['name' => 'Jane'], );
Configuration
$client = new Client( apiKey: 'psk_live_...', // Required workspaceId: 'ws_...', // Required baseUrl: 'https://synapse-api.pyrx.tech', // Optional (default) timeout: 30, // Optional, seconds (default: 30) maxRetries: 3, // Optional (default: 3) ); // Environment is auto-detected from the API key prefix echo $client->environment; // "live", "test", or "unknown"
Tracking Events
// Single event $result = $client->track( externalId: 'user_123', eventName: 'page_view', attributes: ['page' => '/pricing'], idempotencyKey: 'idk_unique_123', occurredAt: '2026-01-15T10:30:00Z', ); // Batch events $result = $client->trackBatch([ ['external_id' => 'user_1', 'event_name' => 'login'], ['external_id' => 'user_2', 'event_name' => 'signup'], ]); echo $result['accepted']; // 2
Managing Contacts
// Identify (create or update) $contact = $client->identify( externalId: 'user_123', email: 'jane@example.com', firstName: 'Jane', ); // Batch identify $result = $client->identifyBatch( contacts: [ ['external_id' => 'u1', 'email' => 'a@example.com'], ['external_id' => 'u2', 'email' => 'b@example.com'], ], onConflict: 'update', ); // List contacts $list = $client->contacts->list(page: 1, perPage: 20, search: 'jane'); // Get a contact $contact = $client->contacts->get('contact_id'); // Update a contact $updated = $client->contacts->update('user_123', ['email' => 'new@example.com']); // Delete a contact $client->contacts->delete('user_123');
Email Templates
// List templates $templates = $client->templates->list(); // Get a template $template = $client->templates->get('welcome'); // Create a template $template = $client->templates->create([ 'name' => 'Welcome Email', 'slug' => 'welcome', 'subject' => 'Welcome, {{name}}!', 'body_html' => '<h1>Hello {{name}}</h1>', ]); // Update a template $updated = $client->templates->update('welcome', ['subject' => 'Hey {{name}}!']); // Preview a template $preview = $client->templates->preview('welcome', [ 'attributes' => ['name' => 'Jane'], ]); echo $preview['html']; // Delete a template $client->templates->delete('old-template');
Webhook Verification
Verify incoming webhooks from Synapse using HMAC-SHA256 (Svix format):
use PyrxSynapse\Webhooks; $payload = file_get_contents('php://input'); $headers = [ 'svix-id' => $_SERVER['HTTP_SVIX_ID'] ?? '', 'svix-timestamp' => $_SERVER['HTTP_SVIX_TIMESTAMP'] ?? '', 'svix-signature' => $_SERVER['HTTP_SVIX_SIGNATURE'] ?? '', ]; try { $event = Webhooks::verify($payload, $headers, 'whsec_your_webhook_secret'); // $event is the parsed JSON payload echo $event['type']; // e.g., "contact.created" } catch (\InvalidArgumentException $e) { http_response_code(400); echo $e->getMessage(); }
Error Handling
use PyrxSynapse\Errors\SynapseError; use PyrxSynapse\Errors\SynapseAuthError; use PyrxSynapse\Errors\SynapseRateLimitError; use PyrxSynapse\Errors\SynapsePlanLimitError; use PyrxSynapse\Errors\SynapseValidationError; try { $client->track('user_1', 'event'); } catch (SynapseAuthError $e) { // 401 or 403 (not plan limit) echo "Auth error: {$e->getMessage()} (status: {$e->status})"; } catch (SynapseRateLimitError $e) { // 429 echo "Rate limited. Retry after {$e->retryAfter} seconds."; } catch (SynapsePlanLimitError $e) { // 403 with code "plan_limit_reached" echo "Plan limit: {$e->current}/{$e->maximum} {$e->limitType} on {$e->plan} plan"; } catch (SynapseValidationError $e) { // 422 foreach ($e->errors as $error) { echo "{$error['field']}: {$error['message']}\n"; } } catch (SynapseError $e) { // Any other API error echo "Error: {$e->getMessage()} (status: {$e->status}, code: {$e->errorCode})"; }
Retry Behavior
The client automatically retries on:
- HTTP 429, 500, 502, 503, 504
- curl connection errors (timeout, connection refused)
Backoff: min(1.0 * 2^attempt, 30s) + random jitter (0-0.5s). For 429 responses, the Retry-After header value is used instead.
Non-retryable errors (401, 403, 422, etc.) are raised immediately.
License
MIT