# Zactonz PHP SDK: Errors & retries

> PHP client for the Zactonz APIs: QR codes and barcodes, screenshots and PDFs, social card images, image conversion, link previews, page to Markdown, SSL, DNS, WHOIS, email checks and translation.

Page: https://developers.zactonz.com/tools/zactonz-php/errors/

Complete documentation for this product: https://developers.zactonz.com/tools/zactonz-php.md

## Exceptions

| Exception | Meaning |
|---|---|
| `AuthenticationException` | The key is missing, unknown or expired. |
| `PermissionException` | The key belongs to another product, or the account is suspended. |
| `InvalidRequestException` | The request was understood and refused: a missing argument, an unreachable URL, a file that is too large. |
| `RateLimitException` | A rate limit or quota was reached. `$e->retryAfter` holds the seconds to wait, when known. |
| `ServerException` | The API or a service it depends on failed. |
| `UnexpectedResponseException` | The response was not what the endpoint documents. |
| `ConnectionException` | The API could not be reached. Nothing was sent. |
| `TimeoutException` | No response arrived in time. The request may still have been processed. |
| `ConfigurationException` | A key is missing (`MissingKeyException`) or malformed (`InvalidKeyException`). |

The first six extend `ApiException`, which carries `status`, the decoded `body`, the response `headers` and `requestId()`. `ConnectionException` and `TimeoutException` extend `TransportException`. All of them extend `ZactonzException`. Passing an argument that cannot be sent, such as a path that does not exist, throws PHP's `InvalidArgumentException`.

```php
use Zactonz\Exception\ApiException;
use Zactonz\Exception\RateLimitException;

try {
    $shot = $zactonz->screenshot()->capture(url: 'https://example.com');
} catch (RateLimitException $e) {
    $retryIn = $e->retryAfter;
} catch (ApiException $e) {
    error_log(sprintf('%d %s (%s)', $e->status, $e->getMessage(), $e->requestId()));
}
```

Some endpoints report a problem with the input using status `401` or `403` in the reply body, for example a QR image that cannot be loaded. The SDK raises those as `InvalidRequestException`; `AuthenticationException` and `PermissionException` are reserved for the key itself. A body whose `status` is not a number is treated as a failure, never as success.

## Retries

A request is sent again, up to `maxRetries` times (default 2), only when doing so cannot repeat work:

- after a `429`, once the `Retry-After` period has passed;
- after a `502`, `503` or `504`, for `GET` requests only;
- when the connection could not be made;
- once, ten seconds later, when the API host's request burst guard rejected the call. That guard answers with an HTML `403` when one address sends more than 20 requests to one endpoint within two seconds; see [rate limits](https://developers.zactonz.com/apis/rate-limits/).

One call waits at most 30 seconds in total between attempts. A longer `Retry-After`, such as a spent daily quota, is thrown as `RateLimitException` without waiting. Timeouts are never retried, because the request may have been processed.

## Timeouts

The default timeout is 90 seconds, because rendering a page or verifying an address can take most of a minute. Both the timeout and the retry count are constructor arguments:

```php
$zactonz = new Client($keys, timeout: 30, maxRetries: 0);
```

## Reporting a problem

Bugs and feature requests go to the [issue tracker](https://github.com/zactonz/zactonz-php/issues). Report a vulnerability privately by email as described in the repository's [security policy](https://github.com/zactonz/zactonz-php/blob/main/SECURITY.md); do not open a public issue for it.
