awaisjameel / didit-laravel-client
A Laravel client library for integrating with the DiDiT verification API. This client handles authentication, session management, PDF report generation, and webhook processing.
Package info
github.com/awaisjameel/didit-laravel-client
pkg:composer/awaisjameel/didit-laravel-client
Fund package maintenance!
Requires
- php: ^8.1
- illuminate/contracts: ^10.0||^11.0||^12.0||^13.0
- illuminate/http: ^10.0||^11.0||^12.0||^13.0
- illuminate/support: ^10.0||^11.0||^12.0||^13.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^2.9||^3.0
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.1.1||^7.10.0
- orchestra/testbench: ^10.0.0||^9.0.0||^8.22.0
- pestphp/pest: ^3.0
- pestphp/pest-plugin-arch: ^3.0
- pestphp/pest-plugin-laravel: ^3.0
- phpstan/extension-installer: ^1.3||^2.0
- phpstan/phpstan-deprecation-rules: ^1.1||^2.0
- phpstan/phpstan-phpunit: ^1.3||^2.0
This package is auto-updated.
Last update: 2026-06-23 20:25:06 UTC
README
A Laravel client library for integrating with the DiDiT verification API (v3). This client handles authentication, session management, PDF report generation, and webhook processing.
Features
- 🔐 API key authentication (
x-api-key), with a legacy OAuth2 fallback - 🔄 Session management (create, retrieve, update) on the Didit v3 API
- 🧩 Workflow-based sessions (
workflow_id) - 📄 PDF report generation
- 🔗 Webhook processing with multiple signature schemes (V2, Simple, legacy)
- 📣
DiditWebhookReceivedevent for listener-based webhook handling - 🛡️ Timing-attack-safe signature verification
- 🧯 Typed exception hierarchy (
DiditExceptionand friends) - 📝 Comprehensive logging options
Installation
You can install the package via composer:
composer require awaisjameel/didit-laravel-client
Configuration
Publish the configuration file:
php artisan vendor:publish --provider="AwaisJameel\DiditLaravelClient\DiditLaravelClientServiceProvider"
Add the following environment variables to your .env file:
# Authentication (recommended): grab your API key from https://business.didit.me DIDIT_API_KEY=your-api-key # Default workflow used when creating sessions (configured in the Didit console) DIDIT_WORKFLOW_ID=your-workflow-uuid # Endpoints DIDIT_BASE_URL=https://verification.didit.me DIDIT_API_VERSION=v3 # Webhooks DIDIT_WEBHOOK_SECRET=your-webhook-secret # Misc DIDIT_TIMEOUT=10 DIDIT_DEBUG=false # Legacy OAuth2 fallback — only needed if you are NOT using an API key # DIDIT_CLIENT_ID=your-client-id # DIDIT_CLIENT_SECRET=your-client-secret # DIDIT_AUTH_URL=https://apx.didit.me # DIDIT_TOKEN_EXPIRY_BUFFER=300
Authentication: The current Didit API authenticates with a single API key sent in the
x-api-keyheader — just setDIDIT_API_KEY. The legacy OAuth2client_credentialsflow is used automatically only when no API key is configured.
Usage
Basic Setup
use AwaisJameel\DiditLaravelClient\Facades\DiditLaravelClient; // or use AwaisJameel\DiditLaravelClient\DiditLaravelClient; // Resolve the shared instance from the container (reads config/.env) $client = app(DiditLaravelClient::class); // Or call methods statically through the facade DiditLaravelClient::createSession(/* ... */); // Or create a new instance with custom configuration $client = new DiditLaravelClient([ 'api_key' => 'your-api-key', // ... other config options ]);
Creating a Verification Session
A session is tied to a workflow (configured in the Didit console and identified by a UUID).
Provide it via the workflow_id option, or set a default with DIDIT_WORKFLOW_ID.
$session = $client->createSession( callbackUrl: 'https://your-app.com/verification/callback', // optional vendorData: 'user-123', // optional options: [ 'workflow_id' => 'your-workflow-uuid', // falls back to DIDIT_WORKFLOW_ID // Any other v3 session fields, e.g.: // 'callback_method' => 'both', // 'metadata' => json_encode(['plan' => 'pro']), // 'contact_details' => ['email' => 'jane@example.com'], // 'expected_details' => ['first_name' => 'Jane', 'last_name' => 'Doe'], ] ); // The session response contains: [ 'session_id' => 'xxx-xxx-xxx', 'url' => 'https://verify.didit.me/session/xxx', // ... ]
If you set
DIDIT_WORKFLOW_ID, you can simply call$client->createSession().
Retrieving Session Details
$sessionDetails = $client->getSession('session-id'); // Response contains the full verification decision: [ 'session_id' => 'xxx-xxx-xxx', 'status' => 'Approved', 'id_verifications' => [/* ... */], 'face_matches' => [/* ... */], // ... other decision data ]
Updating Session Status
$result = $client->updateSessionStatus( sessionId: 'session-id', newStatus: 'Approved', // 'Approved', 'Declined' or 'Resubmitted' comment: 'Verification approved by admin', options: [ // Optional extra fields, e.g.: // 'send_email' => true, // 'email_address' => 'jane@example.com', ] );
Generating PDF Reports
$pdfContent = $client->generateSessionPDF('session-id'); // Save to file file_put_contents('verification-report.pdf', $pdfContent); // Or return as download response return response($pdfContent) ->header('Content-Type', 'application/pdf') ->header('Content-Disposition', 'attachment; filename="report.pdf"');
Handling Webhooks
Set up your webhook route in routes/web.php:
Route::post('didit/webhook', function (Request $request) { $payload = DiditLaravelClient::processWebhook($request); // Handle different webhook events by status / type match($payload['status'] ?? null) { 'Approved' => handleApproved($payload), 'Declined' => handleDeclined($payload), default => handleOther($payload) }; return response()->json(['status' => 'processed']); });
processWebhook() automatically tries every signature scheme Didit sends
(x-signature-v2, x-signature-simple, then the legacy x-signature) and
validates the request freshness using x-timestamp.
Listening for webhook events
After a webhook is verified, processWebhook() dispatches a
DiditWebhookReceived event carrying the verified payload, so you can react in
a listener instead of handling everything inline:
use AwaisJameel\DiditLaravelClient\Events\DiditWebhookReceived; use Illuminate\Support\Facades\Event; Event::listen(function (DiditWebhookReceived $event) { match ($event->payload['status'] ?? null) { 'Approved' => handleApproved($event->payload), 'Declined' => handleDeclined($event->payload), default => handleOther($event->payload), }; });
Manual webhook signature verification:
$headers = [ 'x-signature' => $request->header('x-signature'), 'x-signature-v2' => $request->header('x-signature-v2'), 'x-signature-simple' => $request->header('x-signature-simple'), 'x-timestamp' => $request->header('x-timestamp'), ]; try { $payload = $client->verifyWebhookSignature($headers, $request->getContent()); // Process verified webhook payload } catch (Exception $e) { // Handle invalid signature return response()->json(['error' => $e->getMessage()], 400); }
Error Handling
The client throws a small, typed exception hierarchy so you can catch broadly or
narrowly. Every package exception extends DiditException, which itself extends
\Exception:
| Exception | When it's thrown |
|---|---|
DiditException |
Base class — catch this to handle any DiDiT failure |
DiditConfigurationException |
Missing config (API key/OAuth credentials, base URL, workflow_id, webhook secret) |
DiditAuthenticationException |
Legacy OAuth2 token request failed |
DiditRequestException |
An API request failed (non-2xx or transport error); exposes getResponse() and status() |
WebhookVerificationException |
Webhook body/signature/timestamp could not be verified |
Invalid method arguments (e.g. an empty session id or an unknown status) throw
\InvalidArgumentException.
use AwaisJameel\DiditLaravelClient\Exceptions\DiditException; use AwaisJameel\DiditLaravelClient\Exceptions\DiditRequestException; try { $session = $client->createSession(/* ... */); } catch (DiditRequestException $e) { // Inspect the HTTP response from Didit Log::error('DiDiT API Error', [ 'status' => $e->status(), 'body' => optional($e->getResponse())->json(), ]); } catch (DiditException $e) { // Any other DiDiT failure (config, auth, webhook, ...) Log::error('DiDiT Error: '.$e->getMessage()); }
Debugging
Enable debug mode in your configuration to get detailed logging:
// In your .env file DIDIT_DEBUG=true // Or in configuration $client = new DiditLaravelClient([ // ... other config 'debug' => true ]);
Debug logs will include:
- API requests and responses
- Token management events
- Webhook processing details
- Error details
⚠️ Debug logs may contain PII. When
DIDIT_DEBUG=true, verification payloads and API responses (which can include personal/identity data) are written to your application log. Keep debug mode off in production, or ensure your logs are access-controlled and retained appropriately.
Testing
The package includes comprehensive tests. Run them with:
composer test
Security
- All API requests use HTTPS
- Webhook signatures are verified using HMAC SHA-256 (V2, Simple and legacy schemes)
- Timing attack safe signature comparison
- API key sent via the
x-api-keyheader. On the legacy OAuth fallback, access tokens are cached through Laravel's cache store (shared across requests/workers) and refreshed automatically before expiry - Request timestamp validation (rejects stale webhooks older than 5 minutes)
Contributing
Please see CONTRIBUTING for details.
Credits
License
The MIT License (MIT). Please see License File for more information.