Skip to content

sevaske/zatca-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

55 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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

About

Zatca API Client

Resources

License

Stars

Watchers

Forks

Languages