# Laravel / PHP Integration

Protect a Laravel (or plain PHP) application with Guardian in three short steps.

1. Load the Guardian agent on your frontend and get a `requestId`.
2. Send that `requestId` to your backend.
3. From PHP, fetch the processed event by id and decide what to do.

### 1. Frontend

#### Option A: JavaScript / TypeScript

If your frontend uses a bundler (Vite, webpack, Mix, etc.), install the SDK and call it where it matters.

```bash
npm install @guardianstack/guardian-js
```

```ts
// frontend/guardian.ts
import { loadAgent } from '@guardianstack/guardian-js';

// 1) Initialize once at app startup
const guardian = await loadAgent({
  siteKey: 'site_XXXXXXXX',
});

// 2) Trigger an identification exactly where it matters (login, signup, checkout)
const res = await guardian.get();

// 3) Extract the requestId and send it to your backend for risk evaluation
const requestId = res?.requestId;
```

#### Option B: Blade or plain PHP (no bundler)

If you do not use a JavaScript bundler, load the `@guardianstack/guardian-js` package directly from jsDelivr. It serves the published npm build, no local install required.

```blade
{{-- resources/views/layouts/app.blade.php --}}
<script src="https://cdn.jsdelivr.net/npm/@guardianstack/guardian-js" defer></script>
```

Then, on the page where you want to protect an action:

```html
<script>
  document.getElementById('signup-form').addEventListener('submit', async (e) => {
    e.preventDefault();

    // 1) Initialize the Guardian SDK (loaded via jsDelivr above)
    const guardian = await window.FraudDetectionSDK.loadAgent({
      siteKey: 'site_XXXXXXXX',
    });

    // 2) Trigger identification
    const res = await guardian.get();

    // 3) Forward the requestId to your backend
    const form = e.target;
    const hidden = document.createElement('input');
    hidden.type = 'hidden';
    hidden.name = 'guardian_request_id';
    hidden.value = res?.requestId ?? '';
    form.appendChild(hidden);
    form.submit();
  });
</script>
```

You can pin to an exact version for reproducible builds:

```html
<script src="https://cdn.jsdelivr.net/npm/@guardianstack/guardian-js@0.2.7" defer></script>
```

### 2. Backend (Laravel / PHP)

Your backend receives the `requestId` and calls Guardian to fetch the processed event.

Guardian processes events asynchronously, so the first fetch can return `404` for a moment. Retry a few times with a short delay until the event is ready.

Add your secret to `.env`:

```dotenv
GUARDIAN_SECRET=sec_XXXXXXXX
```

Fetch the event with Laravel's HTTP client:

```php
use Illuminate\Support\Facades\Http;

function getGuardianEvent(string $requestId): array
{
    $secret = config('services.guardian.secret'); // or env('GUARDIAN_SECRET')
    $url    = "https://api.guardianstack.ai/request/event/{$requestId}";

    // Retry a few times while the event is still being processed
    for ($attempt = 0; $attempt < 10; $attempt++) {
        $response = Http::withToken($secret)
            ->acceptJson()
            ->timeout(10)
            ->get($url);

        if ($response->successful()) {
            return $response->json();
        }

        if ($response->status() === 404) {
            usleep(250_000); // 250ms, then retry
            continue;
        }

        // Any other error is final
        abort($response->status(), $response->body());
    }

    abort(504, 'Guardian event not ready');
}
```

Use it in a controller:

```php
public function signup(Request $request)
{
    $event = getGuardianEvent($request->input('guardian_request_id'));

    $isBot       = $event['botDetection']['detected'] ?? false;
    $isVpn       = $event['vpn']['detected']          ?? false;
    $isTampering = $event['tampering']['detected']    ?? false;

    if ($isBot || $isTampering || $isVpn) {
        abort(403, 'Request blocked');
    }

    // proceed with signup
}
```

#### Which signals should you gate on?

The example above blocks on bot, VPN and tampering, but the right combination of signals depends on what you are actually protecting. We publish a dedicated guide for each common use case, with recommended thresholds and decision logic:

* [New account fraud prevention](https://docs.guardianstack.ai/documentation/protect-your-implementation/new-account-fraud-prevention)
* [Payment fraud prevention](https://docs.guardianstack.ai/documentation/protect-your-implementation/payment-fraud-prevention)
* [Account takeover prevention](https://docs.guardianstack.ai/documentation/protect-your-implementation/account-takeover-prevention)
* [Returning user experience](https://docs.guardianstack.ai/documentation/protect-your-implementation/returning-user-experience)
* [Web3 fraud prevention](https://docs.guardianstack.ai/documentation/protect-your-implementation/web3-fraud-prevention)
* [Employee device trust](https://docs.guardianstack.ai/documentation/protect-your-implementation/employee-device-trust)

Pick the guide closest to your use case and adapt the PHP checks above to match its recommendations.

#### Plain PHP (no Laravel)

If you are not using Laravel, the same call with cURL:

```php
function getGuardianEvent(string $requestId): array
{
    $secret = getenv('GUARDIAN_SECRET');
    $url    = "https://api.guardianstack.ai/request/event/{$requestId}";

    for ($attempt = 0; $attempt < 10; $attempt++) {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => 10,
            CURLOPT_HTTPHEADER     => [
                "Authorization: Bearer {$secret}",
                'Accept: application/json',
            ],
        ]);

        $body   = curl_exec($ch);
        $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($status >= 200 && $status < 300) {
            return json_decode($body, true);
        }

        if ($status === 404) {
            usleep(250_000);
            continue;
        }

        throw new \RuntimeException("Guardian error {$status}: {$body}");
    }

    throw new \RuntimeException('Guardian event not ready');
}
```

### That's it

* Frontend gets a `requestId` from `guardian.get()`.
* Backend fetches the event with `Authorization: Bearer <secret>`, retrying on `404`.
* Check the detection fields (`botDetection`, `vpn`, `tampering`, etc.) and decide.

Your secret stays on the server. The site key is safe on the frontend.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.guardianstack.ai/documentation/integrations/laravel-php-integration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
