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

# PHP SDK

> Run prompts and workflows, manage knowledge bases, and verify webhooks from PHP.

The PromptJuggler PHP SDK is a thin, typed wrapper over the public REST API. You
call flat, synchronous methods and get back typed objects — authentication,
request building, and JSON (de)serialization are handled for you.

## Requirements

* PHP 8.2 or newer

## Installation

```bash theme={null}
composer require promptjuggler/sdk
```

## Set up the client

Create an API key in [Settings](https://promptjuggler.com/settings), then construct
the client once and reuse it:

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

$pj = new PromptJuggler('your-api-key');
```

The key is sent as a Bearer token, scoped to `promptjuggler.com` so it is never
attached to requests bound elsewhere.

## Per-endpoint usage

Every endpoint in the [API reference](/api/overview) includes a **PHP SDK** code
sample showing the exact call — that's the place to look for how to invoke each
operation and what it returns. A typical flow:

```php theme={null}
// Trigger a run (async — returns immediately with the run ID)
$created = $pj->runPrompt('greeting', 'production', inputs: ['name' => 'Ada']);

// Poll for the result
use PromptJuggler\Client\Models\RunStatus;

$run = $pj->getPromptRun($created->getId());
if ($run->getStatus()?->is(RunStatus::COMPLETED)) {
    echo $run->getOutput();
}
```

<Note>
  Methods return generated model objects (`PromptJuggler\Client\Models\…`) with
  typed getters. They are read-only data — call getters, don't set values back.
</Note>

## Error handling

When the API responds with an error status, the SDK throws a
`PromptJuggler\Client\Exception\ApiException` carrying the HTTP status code and the
server's message. Every SDK exception implements the `PromptJugglerException` marker
interface, so you can catch the whole surface at once.

```php theme={null}
use PromptJuggler\Client\Exception\ApiException;

try {
    $run = $pj->getPromptRun('does-not-exist');
} catch (ApiException $e) {
    $e->statusCode;     // e.g. 404
    $e->getMessage();   // the server's error message
}
```

You never catch a `Microsoft\Kiota\…` type — the SDK translates the underlying
client's errors into its own.

## Webhooks

PromptJuggler signs every webhook with the `PromptJuggler-Signature` header. Verify
it against the **raw** request body, before any JSON decoding:

```php theme={null}
use PromptJuggler\Client\Webhook\WebhookSignature;

$payload   = file_get_contents('php://input');
$signature = $_SERVER['HTTP_PROMPTJUGGLER_SIGNATURE'] ?? '';

if (!WebhookSignature::isValid($payload, $signature, 'your-webhook-secret')) {
    http_response_code(403);
    exit;
}

$event = json_decode($payload, true);
```

`isValid` recomputes the HMAC-SHA256 of `{timestamp}.{raw_body}`, compares it in
constant time, and rejects deliveries whose timestamp falls outside a tolerance
window (default 300s) to prevent replay. Widen or narrow it with the `tolerance:`
argument.
