PHP code example of facta-dte / api

1. Go to this page and download the library: Download facta-dte/api library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

facta-dte / api example snippets






use Facta\Api\Facta;
use Facta\Api\FactaError;

$facta = new Facta([
    'apiKey'  => getenv('FACTA_API_KEY'),    // facta_test_... (environment 00) or facta_live_... (01)
    'signKey' => getenv('FACTA_SIGN_KEY'),   // factask_..., sent only on routes that sign
    // 'timeoutMs' => 60000,
    // 'maxRetries' => 3,
]);

try {
    $result = $facta->issue(
        ['tipoDte' => '01', 'items' => [['descripcion' => 'Servicio', 'cantidad' => 1, 'precioUni' => 11.30]]],
        ['idempotencyKey' => 'order-1234']   // yours: reuse it to retry safely, even after a crash
    );
    echo $result['estado'], ' ', $result['codigoGeneracion'], "\n";   // sellado ...
} catch (FactaError $e) {
    echo $e->getErrorCode(), ' (HTTP ', $e->getStatus(), '): ', $e->getMessage(), "\n";
}

use Facta\Api\Facta;
use Facta\Api\Pago;
use Facta\Api\SaleType;

$facta = new Facta([
    'apiKey'  => getenv('FACTA_API_KEY'),            // facta_test_... created in staging.factadte.com
    'baseUrl' => Facta::STAGING_BASE_URL,            // the default stays production
]);
$result = $facta->issue([
    'tipoDte' => '03',
    'receptor' => ['customerId' => $customerId],
    'items' => [
        ['descripcion' => 'Cafe', 'cantidad' => 2, 'precioUni' => 30, 'montoDescu' => 5],   // discount of the line, in money
        ['descripcion' => 'Libro', 'cantidad' => 1, 'precioUni' => 10, 'tipoVenta' => SaleType::EXENTA],
    ],
    'pagos' => [new Pago('01', 25), new Pago('02', 40, 'VOUCHER-0042')],   // must add up to the total, to the cent
    'aplicarRetencionIva' => true,    // 01 and 03 only; never automatic
    // 'aplicarPercepcionIva' => true // 03 only
]);
foreach ($result['unknownFields'] ?? [] as $warning) {
    error_log('Facta ignored ' . $warning['campo'] . ' (did you mean ' . ($warning['sugerencia'] ?? '?') . ')');
}

$report = $facta->storeAndConfirmUnconfirmed([
    'where' => 'disco-contabilidad',            // used when store() returns nothing
    'store' => function (array $files, array $document): ?string {
        // $files: codigoGeneracion, json (the Archivo DTE, exactly as downloaded), pdf (or null), sha256.
        // Return only when the bytes are durably stored; throw if they are not.
        file_put_contents('/books/' . $files['codigoGeneracion'] . '.json', $files['json']);
        return null;
    },
]);
// $report['stopped'] is 'complete', 'limit', 'too_many_failures', 'fatal' or 'list_failed'.
// $report['remaining'] and $report['firstDeletionAt'] say what is still waiting and until when.

$facta->confirmDocumentStorage($code, ['where' => 'disco-contabilidad', 'bytes' => $json]);

$facta->issue(['tipoDte' => '01', 'receptor' => ['customerId' => $customerId],
               'items' => [['productId' => $productId, 'cantidad' => 1]]]);

$customer = $facta->getCustomer($id);
try {
    $facta->updateCustomer($id, ['telefono' => '22223333'], ['ifMatch' => $customer['revision']]);
} catch (FactaError $e) {
    if ($e->getErrorCode() === FactaError::CATALOG_REVISION_CONFLICT) { /* read again and re-apply */ }
}

$since = 0; $generation = null;
do {
    $page = $facta->listCatalogChanges($since, $generation !== null ? ['generation' => $generation] : []);
    foreach ($page['cambios'] as $change) { /* tipo, registroId, registroRevision, operacion */ }
    $since = $page['siguiente']; $generation = $page['generacion'];
} while ($page['hayMas']);
// catalog_cursor_expired (HTTP 410): read everything again from since = 0

use Facta\Api\MemoryWebhookReplayStore;   // use your own WebhookReplayStore across workers
use Facta\Api\Webhook;

$event = Webhook::constructEvent($secret, $_SERVER['HTTP_FACTA_SIGNATURE'] ?? null,
    file_get_contents('php://input'), ['store' => $store]);   // throws on a bad signature, a stale
// timestamp (> 300 s) or a replayed deliveryId; answer 2xx for a repeated delivery, order by revision

$draft = $facta->createDraft(
    ['tipoDte' => '01', 'receptor' => ['customerId' => $customerId], 'items' => [['productId' => $productId, 'cantidad' => 1]], 'referencia' => 'order-77'],
    ['idempotencyKey' => 'order-77']
);                                                        // $draft['borradorId'], ['version'], ['totales']
$page  = $facta->listDrafts(['state' => 'pendiente', 'reference' => 'order-77']);   // ['borradores', 'siguiente']
$same  = $facta->getDraftByKey('order-77');               // draft -> invoice without the generation code
$facta->updateDraft($draft['borradorId'], $draft['version'], $request);               // If-Match: version
$issued = $facta->issueDraft($draft['borradorId'], $draft['version'], $request, ['idempotencyKey' => 'issue-77']);
$facta->cancelDraft($draft['borradorId']);                // only while pending and closed

use Facta\Api\Json\Fingerprint;

// fingerprint-v1: lowercase hex SHA-256 of the RFC 8785 (JCS) form of the request.
$fingerprint = Fingerprint::v1($jsonRequestText);