Search by

Official PHP SDK for the Jobcelis Event Infrastructure Platform

v1.4.0 2026-11-08 23:45 UTC

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 an X-Idempotency-Key header, the same on every retry. Pass ['idempotency_key' => '...'] in $extra to use your own key; otherwise a UUID is generated.
  • sendEvents() adds an idempotency_key to 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).