Best practices for using the Ploi PHP SDK to interact with the Ploi.io server management API
Scanned 9/9/2026
Install to Claude Code
npx -y skills add ploi/ploi-php-sdk --skill skills --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Ploi PHP SDK Expert?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/ploi-ploi-php-sdk-expert)More formats (shields.io, HTML) on the badges page.
---
name: Ploi PHP SDK Expert
description: Best practices for using the Ploi PHP SDK to interact with the Ploi.io server management API
compatible_agents:
- Claude Code
- Cursor
- Windsurf
- GitHub Copilot
tags:
- php
- laravel
- ploi
- server-management
- api
- sdk
---
# Ploi PHP SDK Expert
## Context
This skill covers the **Ploi PHP SDK** (`ploi/ploi-php-sdk`), a PHP wrapper around the [Ploi.io](https://ploi.io) server management REST API. It uses Guzzle HTTP under the hood and provides a fluent, chainable interface for managing servers, sites, databases, deployments, and more.
**Scope:** Initializing the SDK client, chaining resources, performing CRUD operations on all Ploi API resources, handling pagination, error handling, and understanding the resource hierarchy.
## Rules
### Initialization
- Always instantiate the client with an API token: `$ploi = new \Ploi\Ploi($apiToken);`
- The token can also be set after construction: `$ploi->setApiToken($token);`
- The SDK auto-configures a Guzzle client pointing at `https://ploi.io/api/` with JSON content headers.
### Fluent Resource Chaining
- Access resources using the fluent parent-child chain. Always start from the `$ploi` instance and drill down:
- `$ploi->server($serverId)` to target a server
- `$ploi->server($serverId)->sites($siteId)` to target a site on a server
- `$ploi->server($serverId)->sites($siteId)->certificates()` to access certificates on a site
- Pass the resource ID when you first access the resource in the chain, not as a separate call.
- Singular and plural method names are interchangeable on the entry point: `$ploi->server()` and `$ploi->servers()` both return a `Server` resource.
### Resource Hierarchy
- **Server-level resources** (accessed from `$ploi->server($id)->`): `sites()`, `databases()`, `cronjobs()`, `daemons()`, `sshKeys()`, `services()`, `networkRules()`, `systemUsers()`, `opcache()`, `insights()`, `loadBalancer()`
- **Site-level resources** (accessed from `->sites($id)->`): `certificates()`, `repository()`, `queues()`, `deployment()`, `app()`, `environment()`, `alias()`, `redirects()`, `fastCgi()`, `authUser()`, `robots()`, `tenants()`, `monitors()`, `nginxConfiguration()`
- **Database-level resources** (accessed from `->databases($id)->`): `backups()`, `users()`
- **Top-level resources** (accessed from `$ploi->`): `project()`, `scripts()`, `statusPage()`, `user()`, `webserverTemplates()`, `fileBackup()`
### Fetching Data
- Use `->get()` to list all resources or fetch a single one by ID.
- `->get()` returns a `Ploi\Http\Response` object. Use `->getJson()` for a `stdClass`, `->getData()` for the `data` property, or `->toArray()` for the full structure.
- When calling `->get($id)`, the ID parameter is optional if you already passed it during chaining.
### Creating Resources
- Each resource has a `create()` method with named parameters matching the API. Always check the method signature for required vs. optional parameters.
- Pass options as method arguments, not as raw arrays (unless the method signature accepts one).
### Pagination
- Resources with `HasPagination` support `->page($pageNumber, $perPage)` and `->perPage($amount)`.
- Example: `$ploi->server($id)->sites()->page(2, 15);`
### Error Handling
- Wrap API calls in try/catch blocks. The SDK throws typed exceptions based on HTTP status codes:
- `Ploi\Exceptions\Http\Unauthenticated` (401)
- `Ploi\Exceptions\Http\NotFound` (404)
- `Ploi\Exceptions\Http\NotAllowed` (405)
- `Ploi\Exceptions\Http\NotValid` (422)
- `Ploi\Exceptions\Http\TooManyAttempts` (429)
- `Ploi\Exceptions\Http\InternalServerError` (500)
- `Ploi\Exceptions\Http\PerformingMaintenance` (503)
- A `Ploi\Exceptions\Resource\RequiresId` is thrown when a resource method needs an ID but none was provided.
### Deployment
- Use the `deployment()` resource on a site: `$ploi->server($id)->sites($siteId)->deployment()->deploy();`
- Access and update deploy scripts: `->deployment()->deployScript()` and `->deployment()->updateDeployScript($script)`.
- Quick deploy toggle is on the repository resource: `->repository()->toggleQuickDeploy()`.
### API Call Options
- When making raw API calls or extending the SDK, pass body data as `['body' => json_encode([...])]` (Guzzle options format).
- Only `get`, `post`, `patch`, and `delete` HTTP methods are supported.
## Examples
### Initialize the client
```php
use Ploi\Ploi;
$ploi = new Ploi('your-api-token');
```
### List all servers with pagination
```php
$response = $ploi->servers()->page(1, 10);
$servers = $response->getData();
```
### Get a single server
```php
$server = $ploi->server(123)->get();
echo $server->getData()->name;
```
### Create a site on a server
```php
$response = $ploi->server(123)->sites()->create(
domain: 'example.com',
webDirectory: '/public',
projectRoot: '/',
systemUser: 'ploi'
);
```
### Install a repository and deploy
```php
$ploi->server(123)->sites(456)->repository()->install(
provider: 'github',
branch: 'main',
name: 'owner/repo'
);
$ploi->server(123)->sites(456)->deployment()->deploy();
```
### Manage SSL certificates
```php
// List certificates
$certs = $ploi->server(123)->sites(456)->certificates()->get();
// Create a Let's Encrypt certificate
$ploi->server(123)->sites(456)->certificates()->create(
certificate: 'example.com',
type: 'letsencrypt'
);
```
### Database management
```php
// Create a database
$ploi->server(123)->databases()->create(
name: 'my_app',
user: 'my_user',
password: 'secret'
);
// Set up automated backups
$ploi->server(123)->databases(789)->backups()->create(
interval: 1440,
type: 'to_server'
);
```
### Queue and worker management
```php
$ploi->server(123)->sites(456)->queues()->create(
connection: 'redis',
queue: 'default',
maximumSeconds: 60,
sleep: 30,
processes: 3,
maximumTries: 3
);
```
### Update environment variables
```php
$ploi->server(123)->sites(456)->environment()->update(
content: "APP_ENV=production\nAPP_DEBUG=false\nAPP_KEY=base64:..."
);
```
### Error handling
```php
use Ploi\Exceptions\Http\NotFound;
use Ploi\Exceptions\Http\NotValid;
use Ploi\Exceptions\Http\Unauthenticated;
try {
$server = $ploi->server(999)->get();
} catch (Unauthenticated $e) {
// Invalid API token
} catch (NotFound $e) {
// Server not found
} catch (NotValid $e) {
// Validation error - check the response body for details
}
```
### Manage daemons
```php
// Create a daemon
$ploi->server(123)->daemons()->create(
command: 'php artisan horizon',
systemUser: 'ploi',
processes: 1,
directory: '/home/ploi/example.com'
);
// Restart a daemon
$ploi->server(123)->daemons(789)->restart();
```
### Manage cron jobs
```php
$ploi->server(123)->cronjobs()->create(
command: 'php /home/ploi/example.com/artisan schedule:run',
frequency: '* * * * *',
user: 'ploi'
);
```
### Service management
```php
// Restart nginx
$ploi->server(123)->services('nginx')->restart();
// Restart MySQL
$ploi->server(123)->services('mysql')->restart();
```
## Anti-patterns
### Do not re-fetch the client for every call
```php
// Bad - creating multiple instances
$servers = (new Ploi($token))->servers()->get();
$sites = (new Ploi($token))->server(1)->sites()->get();
// Good - reuse the client
$ploi = new Ploi($token);
$servers = $ploi->servers()->get();
$sites = $ploi->server(1)->sites()->get();
```
### Do not manually build API URLs
```php
// Bad - constructing URLs by hand
$ploi->makeAPICall('servers/123/sites/456/certificates', 'get');
// Good - use the fluent chain
$ploi->server(123)->sites(456)->certificates()->get();
```
### Do not ignore typed exceptions
```php
// Bad - catching generic exceptions
try {
$ploi->server(123)->get();
} catch (\Exception $e) {
echo "Something went wrong";
}
// Good - catch specific exceptions for proper handling
try {
$ploi->server(123)->get();
} catch (TooManyAttempts $e) {
sleep(60); // Wait and retry for rate limiting
} catch (NotFound $e) {
// Handle missing resource
} catch (Unauthenticated $e) {
// Handle invalid token
}
```
### Do not pass IDs twice
```php
// Bad - redundant ID passing
$ploi->server(123)->sites(456)->certificates()->get(789);
// And then again:
$ploi->server(123)->sites(456)->certificates(789)->get(789);
// Good - pass the ID once, either in the chain or in the method
$ploi->server(123)->sites(456)->certificates(789)->get();
// or
$ploi->server(123)->sites(456)->certificates()->get(789);
```
### Do not access raw Guzzle responses when the SDK provides helpers
```php
// Bad - decoding manually
$response = $ploi->servers()->get();
$body = json_decode($response->getResponse()->getBody()->getContents());
// Good - use the Response helper methods
$response = $ploi->servers()->get();
$data = $response->getData(); // Parsed data property
$json = $response->getJson(); // Full parsed JSON
$array = $response->toArray(); // Array with json + response
```
## References
- [Ploi API Documentation](https://developers.ploi.io)
- [Ploi PHP SDK GitHub Repository](https://github.com/ploi/ploi-php-sdk)
- [Ploi.io](https://ploi.io)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!