gabrielecorio/fiscozen-wrapper

Un wrapper elegante per l'API Fiscozen

Maintainers

Package info

github.com/GabrieleCorio/fiscozen-wrapper

pkg:composer/gabrielecorio/fiscozen-wrapper

Transparency log

Statistics

Installs: 3

Dependents: 0

Suggesters: 0

Stars: 3

Open Issues: 0

v0.0.2 2026-07-22 16:52 UTC

This package is auto-updated.

Last update: 2026-07-22 16:52:58 UTC


README

An unofficial PHP wrapper for the Fiscozen web application API.

Disclaimer: This is an unofficial, reverse-engineered client. It is not affiliated with, endorsed by, or supported by Fiscozen. Use at your own risk. The underlying API may change at any time without notice.

Requirements

  • PHP >= 8.1
  • Composer

Installation

composer require gabrielecorio/fiscozen-wrapper

Authentication flow

Fiscozen uses a two-factor authentication flow:

  1. Submit credentials → the API sends an OTP to your registered phone number.
  2. Submit the OTP → session cookies are persisted to disk for reuse.

The wrapper exposes two approaches depending on your use case.

Two-step (web application)

Credentials and OTP arrive in separate HTTP requests, so each step is called independently. Session cookies are written to disk between the two calls.

use GabrieleCorio\FiscozenWrapper\FiscozenClient;
use GabrieleCorio\FiscozenWrapper\Exceptions\AuthenticationException;

$client = new FiscozenClient(
    email: 'you@example.com',
    password: 'your-password',
    sessionDir: '/path/to/sessions', // optional; defaults to sys_get_temp_dir()/fiscozen_sessions
);

// --- Request 1: submit credentials ---
try {
    $phoneNumber = $client->startLogin(); // returns the masked phone number
    // Store $phoneNumber in your session and show the OTP input to the user
} catch (AuthenticationException $e) {
    // handle error
}

// --- Request 2: submit OTP ---
try {
    $client->submitOtp($otpFromUser);
} catch (AuthenticationException $e) {
    // handle error
}

Single-step (CLI / scripts)

Provide an OTP callback that blocks until the user types the code. The library handles the full flow synchronously. If a valid session already exists on disk it is reused and the callback is never called.

$client->login(function (string $phoneNumber): string {
    echo "OTP sent to {$phoneNumber}: ";
    return trim(fgets(STDIN));
});

Checking and destroying a session

$client->isAuthenticated(); // bool — makes a lightweight API call to verify the session
$client->logout();          // deletes the cookie file and invalidates the local session
$client->relogin($callback); // destroys the existing session and authenticates again

Available API methods

The read-only endpoints are grouped by domain. They reuse the authenticated session and CSRF handling provided by AuthManager.

Domain Method Returns Description
User getUserMe() array Authenticated user's profile data
Invoices invoices()->list(...) PaginatedResponse Paginated invoice list
Invoices invoices()->getFormatInfo(...) array Invoice format information for a date
Counterparts counterparts()->list(...) array Counterpart list
Payments payments()->listMethods(...) PaginatedResponse Paginated payment method list
Dashboard dashboard()->getRealtimeYearStats(...) array Real-time fiscal-year statistics
Dashboard dashboard()->getFulfillmentForecast(...) array Fiscal-year fulfillment forecast
Dashboard dashboard()->getTasks() array Dashboard tasks

Only GET endpoints observed in captured application traffic are included. No write endpoint is exposed.

Invoices

$invoices = $client->invoices()->list(
    page: 1,
    pageSize: 20,
    selfInvoice: false,
);

foreach ($invoices->results as $invoice) {
    // Read the fields needed by your application.
}

$formatInfo = $client->invoices()->getFormatInfo(
    new DateTimeImmutable('2026-01-15'),
);

Counterparts

$counterparts = $client->counterparts()->list();

The optional choices and counterpartType filters are strings because the captured traffic does not establish a stable set of allowed enum values.

Payment methods

$paymentMethods = $client->payments()->listMethods(
    page: 1,
    pageSize: 20,
);

Dashboard

$year = 2026;

$stats = $client->dashboard()->getRealtimeYearStats($year);
$forecast = $client->dashboard()->getFulfillmentForecast($year);
$tasks = $client->dashboard()->getTasks();

Pagination

Paginated methods return a PaginatedResponse with the fields observed in the API response:

$page = $client->invoices()->list(page: 1, pageSize: 20);

echo $page->count;
echo $page->page;
echo $page->pages;

if ($page->next !== null) {
    // Request the next page explicitly using page: $page->page + 1.
}

Pagination parameters must be greater than or equal to 1. Unknown filters are deliberately not accepted.

Local read-only scripts

Each script performs a single action and prints JSON to standard output; none of them save API responses automatically. Log in once with login.php, then run any read script against the session it created:

php examples/login.php
php examples/read_dashboard.php --year=2026
php examples/read_invoices.php --page=1 --page-size=20
php examples/read_counterparts.php
php examples/read_payment_methods.php --page=1 --page-size=20
php examples/read_user_info.php

The read scripts never trigger a login themselves — if no valid session is found they print an error asking you to run login.php first, keeping each script to one action.

API responses can contain personal or fiscal data. Review terminal and process access before running these commands, and do not redirect output to a file unless that file is protected and excluded from version control.

Environment variables

All scripts in examples/ read their configuration from the environment instead of hardcoded values:

Variable Required Description
FISCOZEN_EMAIL Yes Account email used to log in
FISCOZEN_PASSWORD Yes Account password used to log in
FISCOZEN_SESSION_DIR No Directory for the session cookie file. Defaults to examples/../sessions

To avoid placing credentials in shell history, enter them interactively:

read -r FISCOZEN_EMAIL
read -rs FISCOZEN_PASSWORD
export FISCOZEN_EMAIL FISCOZEN_PASSWORD

Session cookies are stored in the git-ignored sessions/ directory by default.

User profile

use GabrieleCorio\FiscozenWrapper\Exceptions\ApiException;

try {
    $response = $client->getUserMe();
    $user = $response['data'] ?? [];

    echo $user['first_name'] . ' ' . $user['last_name'];
    echo $user['email'];
    echo $user['fiscal_code'];
} catch (ApiException $e) {
    echo "HTTP {$e->getHttpStatusCode()}: {$e->getMessage()}";
}

Session persistence

Each user's session is stored in a single JSON file named after the SHA-256 hash of their email address. The directory is created automatically if it does not exist.

/tmp/fiscozen_sessions/
└── a3f1...d9.json   ← cookies for you@example.com

You can override the directory:

$client = new FiscozenClient(
    email: 'you@example.com',
    password: 'your-password',
    sessionDir: __DIR__ . '/sessions',
);

Exceptions

Class Extends When thrown
AuthenticationException RuntimeException Login or OTP verification fails
ApiException RuntimeException Any non-200 API response; exposes getHttpStatusCode()
OtpRequiredException RuntimeException OTP step is required; exposes getPhoneNumber()

Full example

The examples/ directory contains one script per action, each reading its configuration from the environment variables described above:

Running tests

composer install
./vendor/bin/phpunit

Project structure

src/
├── FiscozenClient.php          # Main entry point
├── Api/
│   └── ApiClient.php           # HTTP client for API endpoints
├── Auth/
│   └── AuthManager.php         # Authentication & session management
└── Exceptions/
    ├── ApiException.php
    ├── AuthenticationException.php
    └── OtpRequiredException.php

License

This project is released under the MIT License.