clickfix / sdk
ClickFix public API client for PHP 8.1+: PSR-18 transport, typed errors, bounded retries, pagination, webhook signature verification and widget identity hashes.
Requires
- php: >=8.1
- ext-json: *
- php-http/discovery: ^1.20
- psr/http-client: ^1.0
- psr/http-factory: ^1.0
- psr/http-message: ^1.1 || ^2.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.75
- guzzlehttp/guzzle: ^7.9
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^10.5
Suggests
- guzzlehttp/guzzle: PSR-18 client with request timeouts; any PSR-18 client works
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-11-11 11:45:13 UTC
README
ClickFix public API client for PHP 8.1+. PSR-18 transport (bring any client; Guzzle recommended), PSR-17 factories via php-http/discovery, typed errors, bounded retries, offset pagination, webhook signature verification and widget identity hashes. MIT.
composer require clickfix/sdk guzzlehttp/guzzle
Full walkthrough (identity, external ids, custom fields, company, events, API channel, webhooks): https://getclickfix.com/docs/integration-guide. Changes: CHANGELOG.md. Laravel: the clickfix/laravel package wraps this client.
use ClickFix\Client; $client = new Client('https://api.getclickfix.com', getenv('CLICKFIX_API_KEY')); $contact = $client->contacts()->upsertByExternalId('1001', [ 'name' => 'Ayşe Yılmaz', 'email' => 'ayse@example.com', ], idempotencyKey: 'user-1001-sync-42'); foreach ($client->contacts()->all(['q' => 'acme']) as $item) { // every matching contact, page by page }
Keys stay on your server, are organization-bound and scope-limited. Writes carry an Idempotency-Key; pass a stable key naming the logical action (order number, your event id) and send the same value on a retry, or let the SDK generate one. GETs and keyed writes retry three total attempts by default (cap five) on 429/502/503/504 and network errors, with exponential backoff and a bounded Retry-After. The API stores completed write responses, including errors; use a new key when correcting failed input.
Error responses throw a subclass of ClickFix\Exception\ApiException with status, errorCode, requestId, details and the decoded body: AuthenticationException (401), ForbiddenException (403), NotFoundException (404), ConflictException (409), ValidationException (400/422), RateLimitException (429, retryAfter), ServerException (5xx). Network failures throw TransportException. All implement ClickFix\Exception\ClickFixException.
use ClickFix\UserHash; use ClickFix\Webhooks; $userHash = UserHash::make($identitySecret, $authenticatedUserId); // send only this to the widget $ok = Webhooks::verify($secret, $headers['ClickFix-Webhook-Timestamp'], $headers['ClickFix-Webhook-Signature'], $rawBody);
Webhook verification is HMAC-SHA256 over the exact timestamp.body bytes with a five-minute window on both sides; verify before JSON decoding and deduplicate on ClickFix-Webhook-Id before acting. The identity hash and the webhook check produce the same bytes as @getclickfix/node and the Go module.
Source of truth is sdks/php in the ClickFix monorepo; the public ClickSolveMainTR/clickfix-php repository is a read-only mirror tagged vX.Y.Z for Packagist.
ClickFix\Endpoints is generated from backend/docs/public-api.yaml (make sdks); the resource classes are checked against it. Develop with composer install && composer check (php-cs-fixer, PHPStan level 8, PHPUnit).