[{"data":1,"prerenderedAt":101},["ShallowReactive",2],{"doc:\u002Fdocs\u002Fsdks\u002Fphp":3},{"page":4,"toc":93,"updated":100},{"path":5,"title":6,"seoTitle":7,"description":8,"blocks":9},"\u002Fdocs\u002Fsdks\u002Fphp","PHP","PHP SDK: Read Events and Verify Webhooks","Read identification events with a secret key and verify signed webhooks from PHP 8.1 and newer, with Laravel and Symfony examples.",[10,13,18,23,26,33,36,38,43,45,48,50,54,57,59,63,67,70],{"type":11,"text":12},"p","The `fingerly\u002Ffingerly-php` package reads stored events by request ID and verifies webhook signatures. It uses any PSR-18 HTTP client and falls back to Guzzle.",{"type":14,"level":15,"text":16,"id":17},"heading",2,"Requirements","requirements",{"type":19,"items":20},"list",[21,22],"PHP 8.1 or newer.","A [secret key](\u002Fdocs\u002Fapi-keys), and a webhook signing secret if you receive [webhooks](\u002Fdocs\u002Fwebhooks).",{"type":14,"level":15,"text":24,"id":25},"Install","install",{"type":27,"samples":28},"code",[29],{"label":30,"lang":31,"code":32},"Terminal","bash","composer require fingerly\u002Ffingerly-php",{"type":14,"level":15,"text":34,"id":35},"Read an event","read-an-event",{"type":11,"text":37},"Create one client with your secret key and reuse it. The key decides the regional API and the environment the client reads.",{"type":27,"samples":39},[40],{"label":6,"lang":41,"code":42},"php","\u003C?php\n\n$fingerly = new \\Fingerly\\Client(getenv('FINGERLY_SECRET_KEY'));\n$event = $fingerly->events->get('01a0a84b-e6a2-7c09-9f51-0b3d7a26c8e4');",{"type":11,"text":44},"An event has the fields listed in [Get an event](\u002Freference\u002Fget-event#response). `suspect_score` is `null` when the request was not scored.",{"type":14,"level":15,"text":46,"id":47},"Verify a checkout","verify-a-checkout",{"type":11,"text":49},"Read the event your client identified, check it belongs to this action and is recent, then decide on its level. See [server-side verification](\u002Fdocs\u002Fserver-side-verification).",{"type":27,"samples":51},[52],{"label":6,"lang":41,"code":53},"\u003C?php\n\nuse Fingerly\\ApiException;\n\nfunction decide(string $orderId, string $requestId): string\n{\n    global $fingerly;\n\n    try {\n        $event = $fingerly->events->get($requestId);\n    } catch (ApiException $e) {\n        if ($e->getStatus() === 404) {\n            return 'refuse';\n        }\n        throw $e;\n    }\n\n    if ($event->tag !== \"checkout:{$orderId}\") {\n        return 'refuse';\n    }\n    if ($event->occurredAt \u003C new DateTimeImmutable('-2 minutes')) {\n        return 'refuse';\n    }\n\n    return match ($event->suspectLevel) {\n        'high' => 'review',\n        'medium' => 'challenge',\n        default => 'allow',\n    };\n}",{"type":14,"level":15,"text":55,"id":56},"Verify a webhook","verify-a-webhook",{"type":11,"text":58},"Check the signature over the raw request body before parsing it. The helper rejects timestamps more than five minutes from now.",{"type":27,"samples":60},[61],{"label":6,"lang":41,"code":62},"\u003C?php\n\nuse Fingerly\\Webhook;\nuse Illuminate\\Http\\Request;\n\nRoute::post('\u002Fwebhooks\u002Ffingerly', function (Request $request) {\n    $valid = Webhook::verify(\n        secret: config('services.fingerly.webhook_secret'),\n        payload: $request->getContent(),\n        timestamp: $request->header('x-fingerly-timestamp'),\n        signature: $request->header('x-fingerly-signature'),\n    );\n    abort_unless($valid, 400);\n\n    ProcessFingerlyEvent::dispatch($request->json()->all());\n    return response()->noContent();\n});",{"type":64,"tone":65,"text":66},"callout","note","Exclude the webhook route from CSRF verification. In Laravel, add it to the `except` list of the CSRF middleware.",{"type":14,"level":15,"text":68,"id":69},"API","api",{"type":71,"columns":72,"rows":76},"table",[73,74,75],"Member","Returns","Notes",[77,81,85,89],[78,79,80],"`new Client($secretKey)`","`Client`","A second argument takes `endpoint` and an HTTP client.",[82,83,84],"`$client->events->get($requestId)`","`Event`","Throws `ApiException` with `getStatus()` for a non-2xx response.",[86,87,88],"`$client->events->list([...])`","`EventPage`","Keys: `from`, `to`, `page`, `limit`, `visitor`, `level`.",[90,91,92],"`Webhook::verify(secret:, payload:, timestamp:, signature:)`","`bool`","Five minutes of tolerance.",[94,95,96,97,98,99],{"id":17,"text":16,"level":15},{"id":25,"text":24,"level":15},{"id":35,"text":34,"level":15},{"id":47,"text":46,"level":15},{"id":56,"text":55,"level":15},{"id":69,"text":68,"level":15},"2026-09-17T08:28:36.000Z",1789667797827]