sevaske/zatca-api

Installs: 1 577

Dependents: 1

Suggesters: 0

Security: 0

Stars: 4

Watchers: 2

Forks: 2

Open Issues: 0

pkg:composer/sevaske/zatca-api

2.0.0 2025-11-28 11:05 UTC

This package is auto-updated.

Last update: 2025-12-25 15:32:29 UTC


README

php Vers ion Packagist Stars Packagist Downloads Packagist Version License

ZATCA API PHP Client

This is a simple PHP library to work with the ZATCA API. You can send invoice data and manage certificates easily.

⚠️ Note: This is an unofficial library and not maintained by ZATCA. I do not provide personal support or consulting.

If you’re looking for a library to generate XML invoices, you can use this one: https://github.com/sevaske/php-zatca-xml

Features

  • Full coverage of ZATCA API endpoints (reporting, clearance, compliance)
  • Authentication via certificate and secret or auth token
  • Supports middleware for request/response processing
  • Typed response objects for easy validation and error handling
  • Supports multiple environments: sandbox, simulation, production
  • Follows PSR standards (PSR-4, PSR-7, PSR-17, PSR-18)
  • Works with any PSR-18 compatible HTTP client (e.g., Guzzle)

Installation

composer require sevaske/zatca-api:^2.0

Usage

Client Initialization

Create HTTP client and factories for PSR-17 / PSR-18. For example, GuzzleHttp

use GuzzleHttp\Client;
use GuzzleHttp\Psr7\HttpFactory;
use Sevaske\ZatcaApi\ZatcaClient;

$httpClient = new Client();
$factory = new HttpFactory();

// Initialize ZatcaClient with sandbox environment
$client = new ZatcaClient(
    $httpClient,
    $factory, // RequestFactoryInterface
    $factory, // StreamFactoryInterface
    'sandbox' // environment: sandbox | simulation | production
);

Compliance Certificate Request

use Sevaske\ZatcaApi\Exceptions\ZatcaRequestException;
use Sevaske\ZatcaApi\Exceptions\ZatcaResponseException;

try {
    /**
    * @var $client \Sevaske\ZatcaApi\ZatcaClient 
    */
    $certificateResponse = $client->complianceCertificate('your .csr file content', '112233');
} catch (ZatcaRequestException|ZatcaResponseException $e) {
    // handle
}

Authorized requests

Create AuthToken from compliance certificate to make authorized requests.

/**
* @var $certificateResponse \Sevaske\ZatcaApi\Responses\CertificateResponse
* @var $client \Sevaske\ZatcaApi\ZatcaClient
 */
$authToken = new ZatcaAuth($certificateResponse->certificate(), $certificateResponse->secret());
$client->setAuthToken($authToken);

Submitting Invoices

Once you have a valid compliance certificate and auth token, you can submit invoices in the simulation environment.

Submitting 6 documents is required to switch to production mode.

use Sevaske\ZatcaApi\Exceptions\ZatcaRequestException;
use Sevaske\ZatcaApi\Exceptions\ZatcaResponseException;

try {
    // B2P
    $client->reportingInvoice('b2p invoice xml', 'hash', 'uuid');
    $client->reportingInvoice('b2p debit note xml', 'hash', 'uuid');
    $client->reportingInvoice('b2p credit note xml', 'hash', 'uuid');

    // B2B
    $client->clearanceInvoice('b2b invoice xml', 'hash', 'uuid');
    $client->clearanceInvoice('b2b debit note xml', 'hash', 'uuid');
    $client->clearanceInvoice('b2b credit note xml', 'hash', 'uuid');
} catch (ZatcaRequestException|ZatcaResponseException $e) {
    // handle
}

Production Onboarding

After submitting the required simulation invoices, you can request a production certificate.

This certificate allows you to submit real invoices in the production environment.

use Sevaske\ZatcaApi\Exceptions\ZatcaRequestException;
use Sevaske\ZatcaApi\Exceptions\ZatcaResponseException;

/**
* @var $client \Sevaske\ZatcaApi\ZatcaClient
*/

try {
    $productionCertificateResponse = $client->productionCertificate($certificateResponse->requestId());
} catch (ZatcaRequestException|ZatcaResponseException $e) {
    // handle
}

Submitting Production Invoices

Once the client is configured with the production certificate and environment, you can submit real invoices to ZATCA.

use Sevaske\ZatcaApi\ZatcaAuth;
use Sevaske\ZatcaApi\Exceptions\ZatcaRequestException;
use Sevaske\ZatcaApi\Exceptions\ZatcaResponseException;

/**
* @var $client \Sevaske\ZatcaApi\ZatcaClient
* @var $productionCertificateResponse \Sevaske\ZatcaApi\Responses\ProductionCertificateResponse
*/
$productionClient = $client->withEnvironment('production');
$productionAuth = ZatcaAuth($productionCertificateResponse->certificate(), $productionCertificateResponse->secret());
$productionClient->setAuthToken($productionAuth);

try {
    // submitting production invoices
    $productionClient->reportingInvoice('my real B2P invoice xml', 'hash', 'uuid');
    $productionClient->clearanceInvoice('my real B2P invoice xml', 'hash', 'uuid');
} catch (ZatcaRequestException|ZatcaResponseException $e) {
    // handle
}

Middleware

Middleware in ZatcaClient allows you to inspect, modify, or wrap HTTP requests and responses. It works as a pipeline, meaning that multiple middleware can be chained together, each receiving the request and a $next callable that continues to the next middleware and ultimately to the HTTP client.

ZatcaClient provides four ways to manage middleware:

  1. withMiddleware($middleware) – returns a new cloned instance with the provided middleware. Existing middleware in the original client is replaced in the clone.
  2. setMiddleware($middleware)mutates the current instance, replacing its middleware with the given ones.
  3. attachMiddleware($middleware)mutates the current instance, adding the given middleware to the end of the existing middleware stack.
  4. withoutMiddleware - returns a new cloned instance with no middleware attached.

All middleware must implement the MiddlewareInterface:

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

interface MiddlewareInterface
{
    /**
     * @param RequestInterface $request The incoming request
     * @param callable $next Callable to forward the request to the next middleware or the HTTP client
     * @return ResponseInterface
     */
    public function handle(RequestInterface $request, callable $next): ResponseInterface;
}

Example

For example, implementation of "logging" requests and responses:

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Sevaske\ZatcaApi\Interfaces\MiddlewareInterface;

// Attach a custom middleware to inspect requests and responses
$client = $client->withMiddleware(new class implements MiddlewareInterface
{
    public function handle(\Psr\Http\Message\RequestInterface $request, callable $next): ResponseInterface
    {
        // request
        $this->info('URL: ');
        $this->info((string) $request->getUri());
        $this->info('Body: ');
        $this->info($this->safeStreamContents($request->getBody()));

        /**
         * @var $response \Psr\Http\Message\ResponseInterface
         */
        $response = $next($request);

        // response
        $this->info('Response:');
        $this->info($this->safeStreamContents($response->getBody()));

        return $response;
    }

    private function safeStreamContents(\Psr\Http\Message\StreamInterface $stream): string
    {
        if (! $stream->isSeekable()) {
            return '[unseekable stream]';
        }

        // Save original cursor position
        $pos = $stream->tell();

        // Read from beginning
        $stream->rewind();
        $content = $stream->getContents();

        // Restore original cursor
        $stream->seek($pos);

        return $content;
    }

    private function info(string $text): void
    {
        echo "\n\r".$text;
    }
});

Exception handling

The library throws the following exceptions which you can catch and handle:

  • ZatcaException — general exception class
  • ZatcaRequestException — errors during the HTTP request
  • ZatcaResponseException — errors processing the API response