Developers/SDK - PHP

SDK - PHP

naprawksef/sdk - wymaga PHP 8.1+ i ext-curl. Bez Guzzle, bez PSR-7. Działa z Laravel, Symfony i czystym PHP.

Instalacja

bash
composer require naprawksef/sdk

Wymaga PHP 8.1+, ext-curl, ext-json. Brak zewnętrznych pakietów Composer w runtime - dziala out-of-the-box w każdym shared hostingu / Dockerze.

Inicjalizacja

php
<?php
use NaprawKsef\Sdk\NaprawKsef;

require __DIR__ . '/vendor/autoload.php';

$client = new NaprawKsef([
    'api_key' => $_ENV['NAPRAW_KSEF_API_KEY'], // nk_live_... lub nk_test_...
    'app_name' => 'trawers-erp/7.4.2',         // dorzucamy do User-Agent
    'timeout_ms' => 30_000,
    'max_retries' => 3,                        // 0 = bez retries
]);

Konstruktor waliduje format klucza - błąd konfiguracji rzuca InvalidArgumentException zanim zrobi pierwsze połączenie.

Walidacja XML

php
$result = $client->validate->run(
    xml: file_get_contents('faktura.xml'),
    filename: 'faktura.xml',
    idempotencyKey: "invoice-{$invoice->id}-v3", // opcjonalne
);

if (!$result['valid']) {
    foreach ($result['issues'] as $issue) {
        printf(
            "[%s] %s: %s\n",
            $issue['severity'],
            $issue['code'],
            $issue['message'],
        );
    }
}

Analiza pod korekty FA(3)

php
$analysis = $client->correction->analyze(
    xml: file_get_contents('faktura.xml'),
);

print_r($analysis['analysis']['totals']);
print_r($analysis['suggestions']);   // top 5 scenariuszy
print_r($analysis['lines_jpk']);     // sugestie pól JPK_V7M

Webhooks

php
$created = $client->webhooks->create(
    name: 'Production receiver',
    url: 'https://my-app.com/webhooks/napraw-ksef',
    events: ['validation.completed', 'correction.created'],
);

// Plaintext sekret jest dostępny TYLKO RAZ:
echo $created['secret'];

$list = $client->webhooks->list();
$deliveries = $client->webhooks->listDeliveries($created['webhook']['id']);

$client->webhooks->sendTest($created['webhook']['id']); // smoke test
$client->webhooks->update($created['webhook']['id'], ['is_active' => false]);
$client->webhooks->delete($created['webhook']['id']);

Weryfikacja podpisu webhooka

Vanilla PHP (CGI / Apache):

php
<?php
use NaprawKsef\Sdk\Webhooks\SignatureVerifier;

require __DIR__ . '/vendor/autoload.php';

$rawBody = file_get_contents('php://input');
$header = $_SERVER['HTTP_X_NK_SIGNATURE'] ?? null;

$result = SignatureVerifier::verify(
    secret: $_ENV['NAPRAW_KSEF_WEBHOOK_SECRET'],
    rawBody: $rawBody,
    header: $header,
);

if (!$result['ok']) {
    http_response_code(401);
    exit('Invalid signature: ' . $result['reason']);
}

$event = json_decode($rawBody, true);
// handle $event['type']

Laravel:

php
use NaprawKsef\Sdk\Webhooks\SignatureVerifier;

public function __invoke(Request $request)
{
    $result = SignatureVerifier::verify(
        secret: config('services.naprawksef.webhook_secret'),
        rawBody: $request->getContent(),
        header: $request->header('X-NK-Signature'),
    );

    abort_if(!$result['ok'], 401, 'Invalid signature: ' . $result['reason']);

    $event = $request->json()->all();
    // …
    return response('ok');
}

Więcej w przewodniku Webhooks.

Typowane wyjątki

php
use NaprawKsef\Sdk\Exceptions\{
    AuthException,
    RateLimitException,
    ValidationException,
    ServerException,
};

try {
    $client->validate->run(xml: $xml);
} catch (RateLimitException $e) {
    sleep($e->retryAfterSeconds() ?? 60);
} catch (AuthException $e) {
    rotateKey();
} catch (ValidationException $e) {
    showFieldErrors($e->details);
} catch (ServerException $e) {
    Sentry::captureException($e); // request_id w $e->requestId
}
Pełny README
Pełna dokumentacja, lista wyjątków i przykłady receiver'ów Laravel / Symfony żyją w pakiecie: packagist.org/packages/naprawksef/sdk.