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

# PHP

> A PHP client for the StockShift API. It has a method for every operation in the API reference, generated from the API's OpenAPI document, with PHPStan types for each request and response.

It needs PHP 8.2 or later and any [PSR-18](https://www.php-fig.org/psr/psr-18/) HTTP client.

## Install

```bash theme={null}
composer require stockshift/sdk-php
```

If your project has no PSR-18 client yet, add one, such as Guzzle:

```bash theme={null}
composer require guzzlehttp/guzzle
```

## Quickstart

Create an item, then list stock on hand:

```php theme={null}
use StockShift\Sdk\StockShift;

$stockshift = new StockShift(getenv('STOCKSHIFT_TOKEN'));

$stockshift->catalog()->createItem(['sku' => 'BOLT-M4', 'name' => 'M4 hex bolt', 'type' => 'stocked', 'make_or_buy' => 'buy']);

foreach ($stockshift->inventory()->listStockOnHandAll() as $row) {
    echo $row['sku'], ' ', $row['location_code'], ' ', $row['available_to_promise'], "\n";
}
```

## Authentication

Pass an API key or an OAuth access token as the first argument. Create an API key in the app under Settings > Access > API keys. The key acts as the member who made it, and a call needs both the member's permission and one of the key's scopes.

For an OAuth token that expires, pass a closure. The client calls it before each request:

```php theme={null}
$stockshift = new StockShift(fn (): string => $tokens->current());
```

Other arguments, all named:

| Argument | Default | Meaning |
| - | - | - |
| `baseUrl` | `https://app.stockshift.io/api/v1` | Where the API is. |
| `maxRetries` | `2` | Retries for a call that can be retried. |
| `maxRetryAfter` | `60` | The longest `Retry-After`, in seconds, worth waiting for. |
| `headers` | none | Headers sent on every call. |
| `httpClient` | found for you | The PSR-18 client. Set timeouts on it. |
| `requestFactory`, `streamFactory` | found for you | PSR-17 factories. |

The client and factories are found with [php-http/discovery](https://github.com/php-http/discovery) when you leave them out.

## Making calls

Each area of the API has a method, such as `catalog()` or `inventory()`, and each operation a method on it. Path parameters come first, then the body, then the query string:

```php theme={null}
$item = $stockshift->catalog()->getItem('01J8QZ4M...');
echo $item['data']['sku'];

$page = $stockshift->catalog()->listItems(['search' => 'bolt', 'status' => 'active']);
```

Every method's doc comment names its path, such as `GET /catalog/items/{item}`. You can also call a path directly:

```php theme={null}
$item = $stockshift->get('/catalog/items/{item}', ['path' => ['item' => '01J8QZ4M...']]);
```

A call returns the decoded JSON body as an array. An empty response returns `null`, a CSV export its text and a file the PSR-7 response.

To check your own code against the types, import them from `Schemas` in a PHPStan doc comment:

```php theme={null}
/** @phpstan-import-type ItemResource from \StockShift\Sdk\Generated\Schemas */
```

## Pagination

A list that can grow returns one page at a time. Each paged list has a second method ending in `All` that follows the cursors and yields each record:

```php theme={null}
foreach ($stockshift->catalog()->listItemsAll(['search' => 'bolt']) as $item) {
    echo $item['sku'], "\n";
}
```

`$stockshift->paginate('/catalog/items')` does the same by path. To page by hand, send each page's `next_cursor` back as the `after` query parameter until it is `null`.

## Errors

A failed call throws an `ApiException` that holds the RFC 9457 problem details body. Branch on `errorCode`, which is stable. The detail is written for people and may change.

```php theme={null}
use StockShift\Sdk\Exception\ApiException;

try {
    $stockshift->catalog()->createItem($item);
} catch (ApiException $error) {
    if ($error->errorCode === 'validation_failed') {
        print_r($error->errors()); // ['sku' => ['Another item already has the SKU BOLT-M4.']]
    }
}
```

`ApiException` also has `status`, `problem` and `response`. A call that gets no answer, because the network failed, throws a `ConnectionException`. Both extend `StockShiftException`.

## Retries and idempotency keys

The client retries a `429` after the time in `Retry-After`. It does this for every method, because the API did not run the call. If `Retry-After` is longer than `maxRetryAfter`, it throws instead.

A `5xx` or a network failure is retried for `GET`, `PUT` and `DELETE`, with a short backoff. A `POST` or `PATCH` is retried only when you give it an idempotency key, so a retry cannot make the change twice:

```php theme={null}
$stockshift->integrations()->pushStockNow($connectionId, ['idempotencyKey' => bin2hex(random_bytes(16))]);
```

Use a new key for each change you mean to make. The endpoints that honor the key say so in the API reference.

## Webhooks

Check the `StockShift-Signature` header before you trust a delivery. `Webhook::verify()` needs the raw body, exactly as it arrived:

```php theme={null}
use StockShift\Sdk\Exception\WebhookVerificationException;
use StockShift\Sdk\Webhook;

try {
    $event = Webhook::verify(
        file_get_contents('php://input'),
        $_SERVER['HTTP_STOCKSHIFT_SIGNATURE'] ?? null,
        getenv('STOCKSHIFT_WEBHOOK_SECRET'),
    );
} catch (WebhookVerificationException) {
    http_response_code(400);
    exit;
}

if ($event['type'] === 'inventory.stock.adjusted') {
    echo $event['data']['item_id'], ' ', $event['data']['quantity'], "\n";
}
http_response_code(204);
```

It refuses a delivery more than five minutes old. Pass `tolerance`, in seconds, to change that. Retries of an event keep its `id`, so store it and skip events you have handled.

Each event has a PHPStan type in `Schemas`, such as `InventoryStockAdjustedEvent`. To test your own receiver, `Webhook::sign()` signs a payload the same way StockShift does.

## Versions

The major version moves when the API changes in a way that can break your code, such as a removed field or a new required parameter. New endpoints and fields come in minor versions. `StockShift\Sdk\Generated\Api::VERSION` holds the version of the API reference the package was built from.


## Related topics

- [SDKs](https://docs.stockshift.io/sdks/index.md)
- [Laravel](https://docs.stockshift.io/sdks/laravel.md)
- [StockShift for developers](https://docs.stockshift.io/index.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.