jobcelis / sdk
Official PHP SDK for the Jobcelis Event Infrastructure Platform
Requires
- php: >=8.1
- ext-curl: *
- ext-json: *
Requires (Dev)
- phpunit/phpunit: ^10.5 || ^11.0 || ^12.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-11-08 23:45:21 UTC
README
Official PHP SDK for the Jobcelis Event Infrastructure Platform.
All API calls go to https://jobcelis.com by default -- you only need your API key to get started.
Installation
composer require jobcelis/sdk
Quick Start
use Jobcelis\Client; // Only your API key is required -- connects to https://jobcelis.com automatically $client = new Client(apiKey: 'your_api_key');
Custom URL: If you're self-hosting Jobcelis, you can override the base URL:
$client = new Client(apiKey: 'your_api_key', baseUrl: 'https://your-instance.example.com');
Authentication
The auth methods do not require an API key. Use them to register, log in, and manage JWT tokens.
use Jobcelis\Client; $client = new Client(apiKey: ''); // Register a new account $user = $client->register('alice@example.com', 'SecurePass123!', name: 'Alice'); // Log in -- returns JWT access token and refresh token $session = $client->login('alice@example.com', 'SecurePass123!'); $accessToken = $session['token']; $refreshToken = $session['refresh_token']; // Set the JWT for subsequent authenticated calls $client->setAuthToken($accessToken); // Refresh an expired token $newSession = $client->refreshToken($refreshToken); $client->setAuthToken($newSession['token']); // Verify MFA (requires Bearer token already set) $result = $client->verifyMfa(token: $accessToken, code: '123456');
Events
// Send a single event $event = $client->sendEvent('order.created', ['order_id' => '123', 'amount' => 99.99]); // Send batch events (up to 1000) $batch = $client->sendEvents([ ['topic' => 'order.created', 'payload' => ['order_id' => '1']], ['topic' => 'order.created', 'payload' => ['order_id' => '2']], ]); // List events with pagination $events = $client->listEvents(limit: 25); $nextPage = $client->listEvents(limit: 25, cursor: $events['cursor']); // Get / delete a single event $event = $client->getEvent('evt_abc123'); $client->deleteEvent('evt_abc123');
Webhooks
// Create a webhook $webhook = $client->createWebhook( url: 'https://example.com/webhook', extra: ['topics' => ['order.*']], ); // List, get, update, delete $webhooks = $client->listWebhooks(); $wh = $client->getWebhook('wh_abc123'); $client->updateWebhook('wh_abc123', ['url' => 'https://new-url.com/hook']); $client->deleteWebhook('wh_abc123'); // Health and templates $health = $client->webhookHealth('wh_abc123'); $templates = $client->webhookTemplates();
Deliveries
$deliveries = $client->listDeliveries(limit: 20, filters: ['status' => 'failed']); $client->retryDelivery('del_abc123');
Dead Letters
$deadLetters = $client->listDeadLetters(); $dl = $client->getDeadLetter('dlq_abc123'); $client->retryDeadLetter('dlq_abc123'); $client->resolveDeadLetter('dlq_abc123');
Replays
$replay = $client->createReplay( topic: 'order.created', fromDate: '2026-01-01T00:00:00Z', toDate: '2026-01-31T23:59:59Z', webhookId: 'wh_abc123', // optional ); $replays = $client->listReplays(); $r = $client->getReplay('rpl_abc123'); $client->cancelReplay('rpl_abc123');
Scheduled Jobs
// Create a job $job = $client->createJob( name: 'daily-report', queue: 'default', cronExpression: '0 9 * * *', extra: ['payload' => ['type' => 'daily']], ); // CRUD $jobs = $client->listJobs(limit: 10); $job = $client->getJob('job_abc123'); $client->updateJob('job_abc123', ['cron_expression' => '0 10 * * *']); $client->deleteJob('job_abc123'); // List runs for a job $runs = $client->listJobRuns('job_abc123', limit: 20); // Preview cron schedule $preview = $client->cronPreview('0 9 * * *', count: 10);
Pipelines
$pipeline = $client->createPipeline( name: 'order-processing', topics: ['order.created'], steps: [ ['type' => 'filter', 'config' => ['field' => 'amount', 'gt' => 100]], ['type' => 'transform', 'config' => ['add_field' => 'priority', 'value' => 'high']], ], ); $pipelines = $client->listPipelines(); $p = $client->getPipeline('pipe_abc123'); $client->updatePipeline('pipe_abc123', ['name' => 'order-processing-v2']); $client->deletePipeline('pipe_abc123'); // Test a pipeline with a sample payload $result = $client->testPipeline('pipe_abc123', [ 'topic' => 'order.created', 'payload' => ['id' => '1'], ]);
Event Schemas
$schema = $client->createEventSchema( topic: 'order.created', schema: [ 'type' => 'object', 'properties' => [ 'order_id' => ['type' => 'string'], 'amount' => ['type' => 'number'], ], 'required' => ['order_id', 'amount'], ], ); $schemas = $client->listEventSchemas(); $s = $client->getEventSchema('sch_abc123'); $client->updateEventSchema('sch_abc123', ['schema' => ['type' => 'object']]); $client->deleteEventSchema('sch_abc123'); // Validate a payload against a topic's schema $result = $client->validatePayload('order.created', ['order_id' => '123', 'amount' => 50]);
Sandbox
// Create a temporary endpoint for testing $endpoint = $client->createSandboxEndpoint(name: 'my-test'); $endpoints = $client->listSandboxEndpoints(); // Inspect received requests $requests = $client->listSandboxRequests('sbx_abc123', limit: 20); $client->deleteSandboxEndpoint('sbx_abc123');
Analytics
$eventsChart = $client->eventsPerDay(days: 30); $deliveriesChart = $client->deliveriesPerDay(days: 7); $topics = $client->topTopics(limit: 5); $stats = $client->webhookStats();
Project and Token Management
// Current project $project = $client->getProject(); $client->updateProject(['name' => 'My Project v2']); // Topics $topics = $client->listTopics(); // API token $token = $client->getToken(); $newToken = $client->regenerateToken(); // Limit the token to scopes and client IPs (empty allowedIps = any IP) $client->updateTokenRestrictions(['events:read', 'events:write'], ['203.0.113.10']);
Multi-Project Management
$projects = $client->listProjects(); $newProject = $client->createProject('staging-env'); $p = $client->getProjectById('proj_abc123'); $client->updateProjectById('proj_abc123', ['name' => 'production-env']); $client->setDefaultProject('proj_abc123'); $client->deleteProject('proj_abc123');
Team Members
$members = $client->listMembers('proj_abc123'); $member = $client->addMember('proj_abc123', 'alice@example.com', role: 'admin'); $client->updateMember('proj_abc123', 'mem_abc123', role: 'viewer'); $client->removeMember('proj_abc123', 'mem_abc123');
Invitations
// List pending invitations $invitations = $client->listPendingInvitations(); // Accept or reject $client->acceptInvitation('inv_abc123'); $client->rejectInvitation('inv_def456');
Audit Logs
$logs = $client->listAuditLogs(limit: 100); $nextPage = $client->listAuditLogs(cursor: $logs['cursor']);
Data Export
Export methods return raw strings (CSV or JSON).
// Export as CSV $csvData = $client->exportEvents(format: 'csv'); file_put_contents('events.csv', $csvData); // Export as JSON $jsonData = $client->exportDeliveries(format: 'json'); // Other exports $client->exportJobs(format: 'csv'); $client->exportAuditLog(format: 'csv');
Simulate
// Dry-run an event to see which webhooks would fire $result = $client->simulateEvent('order.created', ['order_id' => 'test']);
GDPR / Privacy
// Consent management $consents = $client->getConsents(); $client->acceptConsent('marketing'); // Data portability $myData = $client->exportMyData(); // Processing restrictions $client->restrictProcessing(); $client->liftRestriction(); // Right to object $client->objectToProcessing(); $client->restoreConsent();
Health Check
$health = $client->health(); $status = $client->status();
Error Handling
use Jobcelis\Client; use Jobcelis\JobcelisException; $client = new Client(apiKey: 'your_api_key'); try { $event = $client->getEvent('nonexistent'); } catch (JobcelisException $e) { echo "Status: " . $e->statusCode . "\n"; // 404 echo "Detail: " . print_r($e->detail, true) . "\n"; }
Retries
The client retries a request automatically when the connection fails (refused or reset connection, DNS or TLS failure, timeout) or the API answers 429, 502, 503 or 504, for example while Jobcelis is being deployed. It waits 1 s, 2 s, 4 s, 8 s, 16 s and 30 s between attempts (with ±20 % jitter), or what the Retry-After header asks for, up to 60 s. By default it makes up to 6 retries, about 60 s in total. Other errors, such as 400 or 500, are thrown immediately as JobcelisException; after the last retry you get the same exception you would get without retries.
GET, PUT, PATCH and DELETE are retried in all of these cases. POST is retried on 429/502/503/504, and after a connection failure only when it carries an idempotency key, so a request can never be applied twice:
sendEvent()sends anX-Idempotency-Keyheader, the same on every retry. Pass['idempotency_key' => '...']in$extrato use your own key; otherwise a UUID is generated.sendEvents()adds anidempotency_keyto every event that does not have one.
Change or disable retries when you create the client:
$client = new Client(apiKey: 'your_api_key', maxRetries: 3); $client = new Client(apiKey: 'your_api_key', maxRetries: 0); // no retries
Webhook Signature Verification
use Jobcelis\WebhookVerifier; // In your webhook handler $body = file_get_contents('php://input'); $signature = $_SERVER['HTTP_X_SIGNATURE'] ?? ''; $isValid = WebhookVerifier::verify( secret: 'your_webhook_secret', body: $body, signature: $signature, ); if (!$isValid) { http_response_code(401); echo 'Invalid signature'; exit; } $event = json_decode($body, true); echo "Received: " . $event['topic']; http_response_code(200);
License
BSL-1.1 (Business Source License)
Releasing
Merge to main: the Release workflow publishes every change to the package as the next patch version (1.3.1 → 1.3.2) to Packagist (through the vX.Y.Z tag), writes the version into VERSION and tags the commit. Changes to docs, tests or CI publish nothing. For a minor or major version, raise it in VERSION in the same pull request. Every pull request runs CI, which also runs the tests (composer install && vendor/bin/phpunit).