ZatcaX
Home Documentation Error Handling

Error Handling

The client converts transport and non-success HTTP responses into typed exceptions before returning a Response.

Exception hierarchy

Exception
└── ZatcaException
    └── ZatcaApiException
        ├── ZatcaValidationException       // HTTP 422
        └── ZatcaDomainUnauthorizedException // domain-related HTTP 403

Complete handling pattern

use ZatcaX\SDK\Exceptions\ZatcaApiException;
use ZatcaX\SDK\Exceptions\ZatcaDomainUnauthorizedException;
use ZatcaX\SDK\Exceptions\ZatcaValidationException;

try {
    $response = Zatca::invoice()->submit($invoice);
    $data = $response->getData();
} catch (ZatcaDomainUnauthorizedException $e) {
    // Fix the configured domain or its allowlist. Do not retry unchanged.
    logger()->warning($e->getMessage());
} catch (ZatcaValidationException $e) {
    // Map field-level errors back to the source record.
    $errors = $e->getErrors();
} catch (ZatcaApiException $e) {
    // Includes cURL failures and all other HTTP 4xx/5xx responses.
    logger()->error('ZatcaX request failed', [
        'status' => $e->getStatusCode(),
        'response' => $e->getResponseBody(),
    ]);
}

Behavior by failure type

ConditionExceptionRecommended action
cURL, DNS, timeout, or TLS failureZatcaApiException (status 400)Retry with bounded backoff after checking network and TLS.
Domain-related HTTP 403ZatcaDomainUnauthorizedExceptionCorrect ZATCAX_CLIENT_DOMAIN or the dashboard allowlist.
HTTP 422ZatcaValidationExceptionRead getErrors(), correct the payload, then resubmit.
Other HTTP 4xxZatcaApiExceptionCorrect credentials or request; do not blindly retry.
HTTP 5xxZatcaApiExceptionLog a correlation identifier and retry using backoff.

Response inspection

Successful HTTP calls return Response. Use dot notation for nested values:

$requestId = $response->json('data.request_id');
$message = $response->getMessage();
$status = $response->getStatusCode();
$all = $response->toArray();

Retry and idempotency guidance

  • Persist the generated invoice UUID before the first submission and reuse it for a retry.
  • A reported invoice is final and the server rejects attempts to modify it.
  • A rejected invoice can be corrected and resubmitted with the same UUID.
  • Never regenerate the invoice UUID merely because the network response was lost.
  • Log response status and safe identifiers, but never the secret, private key, authorization token, or OTP.