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

# PHP SDK

> Test email flows in PHPUnit, Pest and Laravel Dusk — OTPs and magic links auto-extracted.

## Install

```bash theme={null}
composer require --dev zerodrop/zerodrop
```

PHP 8.1+ · ext-curl · ext-json — no other dependencies.

## Quick start

```php theme={null}
use ZeroDrop\Client;

$mail = new Client();
$inbox = $mail->generateInbox();
// => "swift-x7k29ab@zerodrop-sandbox.online"

// Trigger your app's email flow with the inbox address...

$email = $mail->waitForLatest($inbox, timeout: 15);

$email->otp;       // "123456" — auto-extracted, no regex
$email->magicLink; // "https://..." — auto-extracted
```

## Laravel Dusk

```php theme={null}
use Laravel\Dusk\Browser;
use ZeroDrop\Client;

public function testSignupEmailVerification(): void
{
    $mail = new Client();
    $inbox = $mail->generateInbox();

    $this->browse(function (Browser $browser) use ($mail, $inbox) {
        $browser->visit('/signup')
                ->type('email', $inbox)
                ->type('password', 'TestPassword123!')
                ->press('Create account');

        $email = $mail->waitForLatest($inbox, timeout: 15);

        $browser->type('otp', $email->otp)
                ->press('Verify')
                ->assertPathIs('/dashboard');
    });
}
```

## Pest

```php theme={null}
use ZeroDrop\Client;

it('verifies the account via emailed OTP', function () {
    $mail = new Client();
    $inbox = $mail->generateInbox();

    // Trigger signup with $inbox...

    $email = $mail->waitForLatest($inbox, timeout: 15);

    expect($email->otp)->not->toBeNull();
});
```

## Filtering

```php theme={null}
use ZeroDrop\Filter;

$email = $mail->waitForLatest(
    $inbox,
    timeout: 15,
    filter: new Filter(
        from: 'noreply@yourapp.com',
        hasOtp: true,
    ),
);
```

All string filters are case-insensitive partial matches.

## Parallel tests

`generateInbox()` runs locally — safe with Paratest and parallel Dusk runs. Every call returns a unique isolated inbox.

## Error handling

```php theme={null}
use ZeroDrop\Exception\TimeoutException;
use ZeroDrop\Exception\AuthException;
use ZeroDrop\Exception\NetworkException;

try {
    $email = $mail->waitForLatest($inbox, timeout: 15);
} catch (TimeoutException $e) {
    // No email arrived
} catch (AuthException $e) {
    // Invalid API key
} catch (NetworkException $e) {
    // Transport failure
}
```

## Workspaces & self-hosting

```php theme={null}
$mail = new Client(
    apiKey: getenv('ZERODROP_API_KEY'),
    baseUrl: 'https://your-instance.yourdomain.com',
);
```

## Links

* [Packagist](https://packagist.org/packages/zerodrop/zerodrop)
* [GitHub](https://github.com/zerodrop-dev/zerodrop-php)
