> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fingerprint.com/llms.txt
> Use this file to discover all available pages before exploring further.

# PHP Server Quickstart

> Get started using the PHP Server SDK

<Warning>
  **Deprecation Notice**

  This page demonstrates the PHP Server SDK for Server API v3. The PHP Server
  SDK now supports Server API v4. Please use the
  [latest PHP Server quickstart](/docs/php-server-quickstart) instead.
</Warning>

## Overview

In this quickstart, you'll add Fingerprint to a [PHP](https://www.php.net/) server to prevent fraudulent account creation.

The example use case in this quickstart is stopping new account fraud, where attackers create multiple fake accounts to abuse promotions, exploit systems, or evade bans. However, the steps you'll follow apply to most use cases. You can flag and block suspicious users by identifying the device behind each sign-up attempt, login, or transaction.

In this quickstart, you'll learn how to:

* Set up a PHP server with a Fingerprint integration
* Retrieve visitor identification data using the Server API
* Block bots and suspicious devices
* Prevent multiple signups from the same device

This guide focuses on the backend integration and must be completed after identifying a visitor and generating a request ID. **Before starting this quickstart, start with one of the [frontend](/docs/v3/web-quickstarts-overview) or [mobile](/docs/v3/mobile-quickstarts-overview) quickstarts to see how to identify a visitor in your frontend.**

> Estimated time: \< 10 minutes

## Prerequisites

Before you begin, make sure you have the following:

* [PHP](https://www.php.net/downloads.php) 8.0 or later
* [Composer](https://getcomposer.org/download/) (PHP package manager) installed
* SQLite3 installed
* **A completed frontend or mobile Fingerprint implementation (See the quickstarts)**

## 1. Get your secret API key

<Note>
  Before starting this quickstart, you should already have a frontend Fingerprint implementation
  that sends the `requestId` to your server. If not, pause here and check out one of the
  [frontend](/docs/v3/web-quickstarts-overview) or [mobile](/docs/v3/mobile-quickstarts-overview)
  quickstarts first.
</Note>

If you're ready:

1. Sign in and go to the [**API keys**](https://dashboard.fingerprint.com/api-keys) page in the Fingerprint dashboard.
2. Create a new **secret API key**.
3. Copy it somewhere safe so you can use it to retrieve full visitor identification data from the Server API.

## 2. Set up your project

Start by creating a PHP server that exposes a POST endpoint for account creation. If you already have a project you want to use, skip to the next section.

1. Create a project folder, move into it, and set up Composer with the required packages:

```bash Terminal theme={"theme":"github-dark-dimmed"}
mkdir fingerprint-php-quickstart && cd fingerprint-php-quickstart
composer init -n --name="demo/fp-php" --type=project
composer require fingerprint/fingerprint-pro-server-api-sdk:^6.10 vlucas/phpdotenv
```

2. Create a `.env` file to store your Fingerprint secret API key (replace with your actual key):

```bash Terminal theme={"theme":"github-dark-dimmed"}
FINGERPRINT_SECRET_API_KEY=SECRET_API_KEY
```

3. Create a new file called `index.php` and load your dependencies:

```php index.php theme={"theme":"github-dark-dimmed"}
<?php

require __DIR__ . '/vendor/autoload.php';

use Dotenv\Dotenv;

$dotenv = Dotenv::createImmutable(__DIR__);
$dotenv->load();
```

4. Then create a POST route for `/api/create-account`. For now, this will just return a placeholder message so you can confirm the server is running:

```php index.php theme={"theme":"github-dark-dimmed"}
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

if ($_SERVER['REQUEST_METHOD'] === 'POST' && $path === '/api/create-account') {
    header('Content-Type: application/json');
    echo json_encode(['status' => 'Account created!']);
    exit;
}

http_response_code(404);
header('Content-Type: application/json');
echo json_encode(['error' => 'Not found']);
```

## 3. Initialize Fingerprint and retrieve visitor data

Now you'll configure the Fingerprint PHP Server SDK using your secret API key and use it to fetch detailed visitor data for each signup attempt.

When making the initial visitor identification request in the frontend, you received a `requestId`. This ID is unique to each identification event. Your server can then use the [Fingerprint Events API](/reference/v3/server-api-get-event) to retrieve complete identification data, including the trusted visitor ID and other actionable insights like whether they are using a VPN or are a bot.

1. Import the Fingerprint PHP Server SDK classes and the Guzzle HTTP client at the top of `index.php` (after your other use statements):

```php index.php theme={"theme":"github-dark-dimmed"}
use Fingerprint\ServerAPI\Api\FingerprintApi;
use Fingerprint\ServerAPI\Configuration;
use GuzzleHttp\Client as HttpClient;
```

2. Initialize the Fingerprint PHP Server SDK using your secret API key and your [specific workspace region](https://github.com/fingerprintjs/php-sdk/tree/api-v3?tab=readme-ov-file#getting-started). (After loading your .env variables):

```php index.php theme={"theme":"github-dark-dimmed"}
$config = Configuration::getDefaultConfiguration($_ENV['FINGERPRINT_SECRET_API_KEY'], Configuration::REGION_GLOBAL);
$fp = new FingerprintApi(new HttpClient(), $config);
```

3. In your `/api/create-account route`, retrieve the inputs sent from your frontend and fetch the full visitor identification details with `getEvent()`:

<Note>
  **requestId vs event\_id:** Depending on which quickstart you completed, your frontend may send
  either `requestId` (older SDKs) or `event_id` (v4 and newer). Both refer to the same
  identification event and work with the Server API in the same way. Use whichever value your
  frontend sends (`requestId` or `event_id`) as the `requestId` you pass to getEvent() below.
</Note>

```php index.php theme={"theme":"github-dark-dimmed"}
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

if ($_SERVER['REQUEST_METHOD'] === 'POST' && $path === '/api/create-account') {
    header('Content-Type: application/json');

    $input = json_decode(file_get_contents('php://input'), true) ?? [];
    $username  = $input['username']  ?? null;
    $password  = $input['password']  ?? null;
    $requestId = $input['requestId'] ?? null;

    if (!$username || !$password || !$requestId) {
        http_response_code(400);
        echo json_encode(['error' => 'Missing required fields.']);
        exit;
    }

    try {
        // Retrieve full identification details for this request
        [$model, $response] = $fp->getEvent($requestId);
        $event = json_decode($response->getBody()->getContents());
    } catch (Throwable $e) {
        http_response_code(500);
        error_log("Error retrieving event: " . $e->getMessage());
        echo json_encode(['error' => 'Failed to create account.']);
        exit;
    }

    echo json_encode(['status' => 'Account created!']);
    exit;
}
```

Using the `requestId` the Fingerprint server client will retrieve the full data for the visitor identification request. The returned object will contain the visitor ID, IP address, device and browser details, and Smart Signals like bot detection, incognito mode detection, and detections for VPN or virtual machine use.

You can see a full example of the event structure, and test it with your own device, in the [demo playground](https://demo.fingerprint.com/playground).

For additional checks to ensure the validity of the data coming from your frontend view [how to protect from client-side tampering and replay attacks](/docs/protecting-from-client-side-tampering).

## 4. Block bots and suspicious devices

<Note>
  This optional step uses the Bot Detection Smart Signal which is available only on paid plans.
</Note>

A simple but powerful way to prevent fraudulent account creation is to block automated signups that come from bots. The `event` object includes the [Bot Detection Smart Signal](https://fingerprint.com/products/bot-detection/) that flags automated activity, making it easy to reject bot traffic.

1. Continuing in your `/api/create-account` route, after the `try/catch` where you fetch the event, extract the bot detection signal and decide whether to allow the signup:

```php index.php theme={"theme":"github-dark-dimmed"}
$botResult = $event->products->botd->data->bot->result;

// Block automated signups
if ($botResult !== 'notDetected') {
    error_log("Account creation blocked: bot detection result = {$botResult}");
    http_response_code(403);
    echo json_encode(['error' => 'Failed to create account.']);
    exit;
}
```

This signal returns `good` for known bots like search engines, `bad` for automation tools, headless browsers, or other signs of automation, and `notDetected` when no bot activity is found. You can also layer in other Smart Signals to catch more suspicious devices. For example, you can use Fingerprint's [Suspect Score](/docs/suspect-score) to determine when to add additional friction to create an account.

## 5. Prevent multiple signups from the same device

To catch repeated signups from the same device, you can use the visitor ID (`visitorId`) from the Fingerprint identification event. By saving this ID alongside each created account, you can detect and block duplicate signups from the same device. This quickstart uses SQLite because it's a simple database with little setup.

1. Create a file called `setup.php` with the following code to initialize a simple SQLite table:

```php setup.php theme={"theme":"github-dark-dimmed"}
<?php
$db = new PDO('sqlite:database.sqlite');
$db->exec("
CREATE TABLE IF NOT EXISTS accounts (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    username TEXT NOT NULL,
    password TEXT NOT NULL,
    visitorId TEXT NOT NULL
)");
echo "Database ready.";
```

2. Run the script once to create the database file and table:

```bash Terminal theme={"theme":"github-dark-dimmed"}
php setup.php
```

3. In `index.php`, open a SQLite connection after loading your environment variables:

```php index.php theme={"theme":"github-dark-dimmed"}
$db = new PDO('sqlite:database.sqlite');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
```

4. In your `/api/create-account` route, after the bot check, extract the trusted visitor ID from the event:

```php index.php theme={"theme":"github-dark-dimmed"}
$visitorId = $event->products->identification->data->visitorId;
```

5. Check if this device has already created an account:

```php index.php theme={"theme":"github-dark-dimmed"}
$check = $db->prepare("SELECT COUNT(*) FROM accounts WHERE visitorId = ?");
$check->execute([$visitorId]);
$alreadyExists = $check->fetchColumn() > 0;

if ($alreadyExists) {
    http_response_code(429);
    error_log("Account already exists: visitorId = {$visitorId}");
    echo json_encode(['error' => 'Failed to create account.']);
    exit;
}
```

6. Insert the new account with the visitor ID and return success:

```php index.php theme={"theme":"github-dark-dimmed"}
$insert = $db->prepare("INSERT INTO accounts (username, password, visitorId) VALUES (?, ?, ?)");
$insert->execute([$username, $password, $visitorId]);

echo json_encode(['status' => 'Account created!']); // Was already there
exit; // Was already there
```

This gives you a basic system to detect and block repeat signups. You can expand on this by allowing a limited number of accounts per device, adjusting your response based on business rules, only evaluating recent signups, etc.

<Info>
  This is a minimal example to show how to use the Fingerprint PHP Server SDK. In a real
  application, make sure to implement proper security practices, especially around password handling
  and storage.
</Info>

## 6. Test your implementation

Now that everything is set up, you can test the full flow using your existing frontend.

### Before you test

If your frontend is running on a different port (like localhost:5173 or localhost:3000), you may run into CORS issues for testing. To quickly fix this for local development & testing:

1. Add the following at the top of `index.php`, right after your require and use statements:

```php theme={"theme":"github-dark-dimmed"}
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type");

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(204);
    exit;
}
```

### Test the implementation

1. Start your PHP server:

```bash Terminal theme={"theme":"github-dark-dimmed"}
php -S localhost:8000
```

2. In your frontend, trigger a sign-up request that sends the `requestId`, `username`, and `password` to your server's `/api/create-account` endpoint. To see the reply messages make sure to parse and display or console log the response from your server.
3. Within your frontend, input a username and password to create a user. Then try to create another user and see that the second attempt will be rejected.
4. Bonus: Try creating an account using a headless browser.

## Next steps

You now have a working backend fraud check using Fingerprint. From here, you can expand your logic with more Smart Signals, adjust thresholds based on your risk tolerance, or introduce additional checks for suspicious users.

These same techniques apply to a wide range of fraud prevention use cases, from detecting fake reviews to blocking payment abuse or preventing account takeovers.

To go further, check out the use case tutorials for step-by-step guides tailored to specific problems you can solve with Fingerprint.

Check out these related resources:

* [PHP SDK Reference](https://github.com/fingerprintjs/php-sdk/tree/api-v3)
* [Vue frontend quickstart](/docs/v3/vue-quickstart)
* [APIv3 reference for the Events endpoint](/reference/v3/server-api-get-event)
* [Use case tutorial: Detecting new account fraud](/docs/v3/new-account-fraud-use-case-tutorial)
* [Low-latency identification with Sealed Client Results](/docs/v3/sealed-client-results)
