Error Handling
Every request failure throws an exception you can catch and inspect — the SDK never returns false or null to signal an error (aside from "not found" lookups documented per-resource, which return null).
Exception classes
Both live in BioTime\Exceptions:
| Exception | Extends | Thrown when |
|---|---|---|
ApiException | RuntimeException | Any non-2xx response from the API, or an unreachable/unsendable request |
AuthenticationException | ApiException | Authentication specifically fails — bad credentials, an unreachable device during authentication, or a missing token in the auth response |
Because AuthenticationException extends ApiException, catching ApiException also catches authentication failures. Catch AuthenticationException first if you want to handle it differently.
ApiException methods
use BioTime\Exceptions\ApiException;
try {
$biotime->devices()->reboot([999]);
} catch (ApiException $e) {
echo $e->getMessage(); // e.g. "BioTime POST /iclock/api/terminals/reboot/ failed (404)"
echo $e->getStatusCode(); // the HTTP status code, e.g. 404
echo $e->getResponseBody(); // the raw response body string from the device
}Catching authentication failures separately
use BioTime\Exceptions\ApiException;
use BioTime\Exceptions\AuthenticationException;
try {
$employees = $biotime->employees()->all();
} catch (AuthenticationException $e) {
// Bad credentials, or the device rejected re-authentication
} catch (ApiException $e) {
// Any other non-2xx response
}What triggers each exception
- A
GuzzleExceptionwhile sending any request (e.g. connection refused, DNS failure, timeout) is wrapped and re-thrown asAuthenticationExceptionbyClient::rawRequest(). - Any completed response with a status code
>= 400is thrown asApiExceptionbyClient::send()/Client::download(), carrying the status code and raw body. - A failed authentication call specifically (bad status, or a response with no
tokenfield) throwsAuthenticationExceptionfromTokenManager::authenticate(). - On a
401from an actual API call, the client automatically clears the cached token, re-authenticates once, and retries the original request — an exception is only thrown if that retry also fails. See Authentication.
"Not found" is not always an exception
Several find()-style methods return null instead of throwing when the device returns no matching row (e.g. Employees::find(), Employees::findById(), Attendances::find(), Areas::find(), Departments::find(), Positions::find()). Check the return value:
$employee = $biotime->employees()->find('DOES-NOT-EXIST');
if ($employee === null) {
// no matching employee
}Devices::get() and Resigns::find() do not have this null short-circuit in their signatures — a request to a resource ID that doesn't exist will surface as a ApiException from the underlying GET call instead.