PHPackages                             vs-point/kb-adaa - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. vs-point/kb-adaa

ActiveLibrary[API Development](/categories/api)

vs-point/kb-adaa
================

A PHP library for communication with the Komerční banka Account Direct Access (ADAA) API v2.

1.0.0(3w ago)00MITPHPPHP &gt;=8.2

Since May 17Pushed 3w agoCompare

[ Source](https://github.com/vs-point/kb-adaa)[ Packagist](https://packagist.org/packages/vs-point/kb-adaa)[ RSS](/packages/vs-point-kb-adaa/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (1)Dependencies (13)Versions (2)Used By (0)

vs-point/kb-adaa
================

[](#vs-pointkb-adaa)

PHP knihovna pro komunikaci s **[Komerční banka Account Direct Access API v2](https://developers.kb.cz/service/AccountDirectAccessAPI-v2)**. Typovaný interface pro účty, zůstatky, transakce, výpisy v PDF a notifikace o pohybech.

Pokrývá všech 5 vrstev integrace:

VrstvaCo děláTřída**Runtime ADAA**čte účty, zůstatky, transakce, výpisy, spravuje notifikační subscriptions`KbAdaaClient->accounts`, `->balances`, `->transactions`, `->statements`, `->eventSubscriptions`**OAuth2**vyměňuje authorization code za tokeny, refreshuje access token, sestavuje login URL`KbAdaaClient->oauth2`**Client Registration (mTLS)**žádá KB o software statement JWT pro tvou aplikaci`KbAdaaClient->clientRegistration`**Application Registration**builduje redirect URL a dešifruje AES-256-GCM odpověď z callbacku`KbAdaaClient->applicationRegistration`**Event API receiver**server-side helpery pro implementaci tvého webhook endpointu`KbAdaaClient->eventApi`Instalace
---------

[](#instalace)

```
composer require vs-point/kb-adaa
```

Vyžaduje PHP ≥ 8.2 a rozšíření `openssl`, `json`, `curl` (curl ≥ 7.71 pro inline certifikát).

Architektura konfigurace
------------------------

[](#architektura-konfigurace)

ADAA má **tři různé apiKey** (Client Registration, OAuth2, ADAA) a každý se získává zvlášť v [developer portálu](https://developers.kb.cz). Proto má knihovna tři oddělené config objekty:

```
use VsPoint\KbAdaa\Config\KbAdaaConfig;            // pro runtime ADAA volání
use VsPoint\KbAdaa\Config\OAuth2Config;            // pro token endpoint
use VsPoint\KbAdaa\Config\ClientRegistrationConfig; // pro software statement (mTLS)
```

Při inicializaci `KbAdaaClient` jsou **OAuth2Config a ClientRegistrationConfig volitelné** — předáš jen ty, které potřebuješ pro aktuální use-case.

### Sandbox vs produkce

[](#sandbox-vs-produkce)

```
use VsPoint\KbAdaa\Enum\Environment;

Environment::Sandbox     // https://api-gateway.kb.cz/sandbox/...
Environment::Production  // https://api-gateway.kb.cz/... (Client Registration má vlastní host)
```

### Token storage

[](#token-storage)

Access token žije pouze 3 minuty, refresh token 12 měsíců. Knihovna vyžaduje `TokenStorageInterface`:

```
interface TokenStorageInterface {
    public function load(): ?AccessToken;
    public function save(AccessToken $token): void;
    public function clear(): void;
}
```

Pro lokální vývoj / CLI použij `InMemoryTokenStorage`. Pro produkci napiš vlastní implementaci nad svou DB / Redisem / secret managerem.

**Auto-refresh:** Pokud klientovi předáš `OAuth2Config`, automaticky před každým voláním zkontroluje expiraci tokenu, sám refreshne a uloží nový. Pokud OAuth2Config nepředáš, používá se uložený access token jak je (chování pro „manuální“ režim).

Quick start — runtime ADAA
--------------------------

[](#quick-start--runtime-adaa)

Předpokládá, že už máš access token + refresh token získaný OAuth2 flow (viz dál).

```
use VsPoint\KbAdaa\Config\KbAdaaConfig;
use VsPoint\KbAdaa\Config\OAuth2Config;
use VsPoint\KbAdaa\Enum\Environment;
use VsPoint\KbAdaa\KbAdaaClient;
use VsPoint\KbAdaa\Token\AccessToken;
use VsPoint\KbAdaa\Token\InMemoryTokenStorage;

$tokenStorage = new InMemoryTokenStorage(new AccessToken(
    accessToken: 'eyJ...',
    refreshToken: 'eyJ...',
    expiresAt: time() + 180,
    scope: 'adaa',
));

$client = KbAdaaClient::create(
    config: new KbAdaaConfig(
        apiKey: 'adaa-api-key',
        environment: Environment::Production,
    ),
    tokenStorage: $tokenStorage,
    // Volitelné — povoluje auto-refresh tokenu:
    oauth2Config: new OAuth2Config(
        apiKey: 'oauth2-api-key',
        clientId: 'YourApp-1234',
        clientSecret: 'shh',
        redirectUri: 'https://nas-produkt.cz/kb/callback',  // KB ho vyžaduje i u refresh
        environment: Environment::Production,
    ),
);

// Účty
foreach ($client->accounts->list() as $account) {
    echo $account->iban . ' (' . $account->currency?->getCurrencyCode() . ')' . PHP_EOL;
}
```

Konfigurace mTLS (Client Registration)
--------------------------------------

[](#konfigurace-mtls-client-registration)

Software statement endpoint vyžaduje kvalifikovaný certifikát od I.CA nebo PostSignum (KB ho sama nevydává). Certifikační autority ho typicky dávají jako `.p12` (PKCS#12). Knihovna nabízí **tři** cesty, vyber si podle toho, kde certifikát žije:

TřídaVstupKdy použít`ClientRegistrationP12Config``.p12` soubor nebo bytes + hesloMáš `.p12` přímo od I.CA / PostSignum, nechceš konvertovat`ClientRegistrationConfig`cesta k `.pem` souboruPo jednorázové konverzi P12→PEM, certifikát žije na disku`ClientRegistrationInlineConfig`PEM stringCertifikát ze secret manageru / env proměnné### Z `.p12` souboru (přímo od certifikační autority)

[](#z-p12-souboru-přímo-od-certifikační-autority)

Nejjednodušší — knihovna provede `openssl_pkcs12_read()` interně:

```
use VsPoint\KbAdaa\Config\ClientRegistrationP12Config;

$config = ClientRegistrationP12Config::fromFile(
    apiKey: 'cr-api-key',
    p12Path: '/secrets/qualified-cert.p12',
    p12Password: 'heslo-k-p12',
    environment: Environment::Production,
);
```

Pokud máš `.p12` už načtený v paměti (typicky ze secret manageru):

```
$config = new ClientRegistrationP12Config(
    apiKey: 'cr-api-key',
    p12Content: $secretManager->get('kb-qualified-cert.p12'),
    p12Password: $secretManager->get('kb-qualified-cert-password'),
    environment: Environment::Production,
);
```

> **OpenSSL 3.x heads-up:** `openssl_pkcs12_read()` selže na `.p12` šifrovaných legacy algoritmy (RC2 / 3DES) — časté u starších Windows exportů z I.CA. Pokud konstruktor vyhodí výjimku, proveď jednorázovou konverzi `openssl pkcs12 -legacy ...` a použij `ClientRegistrationConfig` nebo `ClientRegistrationInlineConfig`.

### Z PEM souboru na disku

[](#z-pem-souboru-na-disku)

```
use VsPoint\KbAdaa\Config\ClientRegistrationConfig;

$config = new ClientRegistrationConfig(
    apiKey: 'cr-api-key',
    certPath: '/secrets/qualified-cert.pem',
    certPassword: null,           // pokud je PEM zašifrovaný
    keyPath: null,                // pokud je klíč v jiném souboru
    keyPassword: null,
    environment: Environment::Production,
);
```

Konverze `.p12` → `.pem`:

```
openssl pkcs12 -in qualified-cert.p12 -out qualified-cert.pem -nodes -passin pass:HESLO
```

### Inline (PEM string ze secret manageru)

[](#inline-pem-string-ze-secret-manageru)

Žádný dočasný soubor se nezapisuje — používá `CURLOPT_SSLCERT_BLOB` (curl 7.71+).

```
use VsPoint\KbAdaa\Config\ClientRegistrationInlineConfig;

$config = new ClientRegistrationInlineConfig(
    apiKey: 'cr-api-key',
    certPem: $_ENV['KB_QUALIFIED_CERT_PEM'],
    keyPem: $_ENV['KB_QUALIFIED_KEY_PEM'],   // pokud klíč není v certPem
    environment: Environment::Production,
);
```

Kompletní onboarding flow
-------------------------

[](#kompletní-onboarding-flow)

KB onboarding je jednorázový proces na začátku integrace. Pak už jen průběžně refreshuješ token a voláš ADAA.

### 1. Software statement (jednou za 12 měsíců na aplikaci)

[](#1-software-statement-jednou-za-12-měsíců-na-aplikaci)

```
use VsPoint\KbAdaa\DTO\ClientRegistration\SoftwareStatementPayload;

$statement = $client->clientRegistration->issue(new SoftwareStatementPayload(
    softwareName: 'Náš produkt',
    softwareNameEn: 'Our product',
    softwareId: bin2hex(random_bytes(16)),
    softwareVersion: '1.0',
    softwareUri: 'https://nas-produkt.cz',
    redirectUris: ['https://nas-produkt.cz/kb/callback'],
    registrationBackUri: 'https://nas-produkt.cz/kb/registration-back',
    contacts: ['email: support@nas-produkt.cz'],
));

echo $statement->token;                     // raw JWT
echo $statement->claims->vendorName;        // dekódované claims
echo $statement->claims->exp;               // expirace (12 měsíců)
// → ulož $statement->token do secret manageru, použiješ při registraci aplikace
```

### 2. Application registration (jednou za 12 měsíců na klienta — provede uživatel přes browser)

[](#2-application-registration-jednou-za-12-měsíců-na-klienta--provede-uživatel-přes-browser)

```
use VsPoint\KbAdaa\DTO\ApplicationRegistration\RegistrationRequest;
use VsPoint\KbAdaa\Enum\ApplicationType;
use VsPoint\KbAdaa\Enum\Scope;

// Vygeneruj a ulož AES-256 klíč — budeš ho potřebovat pro dešifrování callbacku.
$encryptionKey = $client->applicationRegistration->generateEncryptionKey();
// $encryptionKey ulož do session / DB svázaný s registrací

$redirectUrl = $client->applicationRegistration->buildRedirectUrl(
    Environment::Production,
    new RegistrationRequest(
        clientName: 'Náš produkt',
        clientNameEn: 'Our product',
        redirectUris: ['https://nas-produkt.cz/kb/callback'],
        scope: [Scope::Adaa, Scope::CardData],
        encryptionKey: $encryptionKey,
        softwareStatement: $statement->token,
        applicationType: ApplicationType::Web,
    ),
);

// Redirectni uživatele
header('Location: ' . $redirectUrl);
```

Po dokončení se uživatel vrátí na tvůj `registrationBackUri` s `?salt=…&encryptedData=…`. Dešifruj:

```
$registration = $client->applicationRegistration->decryptResponse(
    base64Salt: $_GET['salt'],
    base64EncryptedData: $_GET['encryptedData'],
    base64EncryptionKey: $encryptionKey,    // tentýž klíč jako výše
);

echo $registration->clientId;       // ulož do DB
echo $registration->clientSecret;   // ulož do DB
```

### 3. OAuth2 — získání access tokenu (uživatel se přihlásí do KB)

[](#3-oauth2--získání-access-tokenu-uživatel-se-přihlásí-do-kb)

```
$loginUrl = $client->oauth2->buildAuthorizationUrl(
    scopes: [Scope::Adaa],
    state: bin2hex(random_bytes(16)),
);

header('Location: ' . $loginUrl);
```

> `redirect_uri` se vždy bere z `OAuth2Config::$redirectUri` — KB ho vyžaduje shodný napříč authorize / token-exchange / refresh.

Callback handler:

```
$accessToken = $client->oauth2->exchangeAuthorizationCodeForToken(code: $_GET['code']);

$tokenStorage->save($accessToken);
```

Od této chvíle můžeš volat ADAA endpointy. Pokud máš `OAuth2Config` připojený na klientovi, refresh probíhá automaticky.

Použití runtime API
-------------------

[](#použití-runtime-api)

### Účty

[](#účty)

```
$accounts = $client->accounts->list();

foreach ($accounts as $account) {
    echo $account->accountId . ' — ' . $account->iban . PHP_EOL;
}

// accountId se nemění — cachuj ho, ať nepáliš zbytečně API call
```

### Zůstatky

[](#zůstatky)

```
foreach ($client->balances->list($accountId) as $balance) {
    echo $balance->type?->value . ': ' . $balance->amount?->toMoney() . PHP_EOL;
}
// CLOSING_AVAILABLE: CZK 85,061.41
// PREVIOUSLY_CLOSED_BOOK: CZK 85,061.41
```

### Transakce

[](#transakce)

```
use Brick\DateTime\Duration;
use Brick\DateTime\TimeZone;
use Brick\DateTime\ZonedDateTime;
use VsPoint\KbAdaa\DTO\Transaction\TransactionQuery;

$now = ZonedDateTime::now(TimeZone::utc());

$page = $client->transactions->list(
    $accountId,
    new TransactionQuery(
        fromDateTime: $now->minusDuration(Duration::ofDays(30)),
        toDateTime: $now,
        page: 0,
        size: 100,    // max 100 (KB-enforced)
    ),
);

foreach ($page->content as $tx) {
    echo $tx->bookingDate . ' ' . $tx->amount?->toMoney() . ' ' . $tx->status?->value . PHP_EOL;

    // Pro párování PDNG → BOOK použij references.accountServicer
    echo '  pair key: ' . $tx->references?->accountServicer . PHP_EOL;
}
```

**Throughput limit KB:** 1 stažení / hodinu. Pro vyšší frekvenci použij Event API subscriptions níže.

### Výpisy v PDF

[](#výpisy-v-pdf)

```
use Brick\DateTime\ZonedDateTime;
use VsPoint\KbAdaa\DTO\Statement\StatementListQuery;

$statements = $client->statements->list(
    $accountId,
    new StatementListQuery(dateFrom: ZonedDateTime::parse('2024-01-01T00:00:00Z')),
);

foreach ($statements as $statement) {
    $pdf = $client->statements->download($accountId, $statement->statementId);
    file_put_contents("statement-{$statement->statementId}.pdf", $pdf);
}
```

### Notifikace (subscription management)

[](#notifikace-subscription-management)

```
use VsPoint\KbAdaa\DTO\EventSubscription\CreateSubscriptionPayload;

$subscription = $client->eventSubscriptions->create(
    $accountId,
    new CreateSubscriptionPayload(
        eventApiUrl: 'https://nas-produkt.cz/webhook/kb-events',
        eventApiKey: bin2hex(random_bytes(32)),    // sdílené tajemství — KB ho posílá jako x-api-key header
    ),
);

echo $subscription->subscriptionId;   // ulož do DB ke svému účtu

// Později:
$client->eventSubscriptions->delete($accountId, $subscription->subscriptionId);
```

> KB volá tvůj endpoint z IP `194.50.202.179` a `194.50.226.179` — povolit ve firewallu.

Event API receiver (serverová strana webhooku)
----------------------------------------------

[](#event-api-receiver-serverová-strana-webhooku)

KB vyžaduje, aby tvůj endpoint implementoval dvě cesty:

- `POST /subscriptions/{subscriptionId}/events` — musí vrátit **HTTP 204 do 5 sekund**
- `GET /version` — musí vrátit `{"version": "1.0"}`

Knihovna ti dává helper, který je framework-agnostický:

```
// V tvém controlleru pro POST /subscriptions/{subscriptionId}/events
try {
    $payload = $client->eventApi->handleEvent(
        jsonBody: file_get_contents('php://input'),
        expectedApiKey: $mySubscriptionApiKey,         // ten, co jsi předal při create()
        providedApiKey: $request->headers->get('x-api-key', ''),
    );

    // $payload->eventCount — počet nových událostí
    // Spusť fetch nových transakcí (async, neblokuj odpověď)
    dispatch_to_queue(new FetchKbTransactions($accountId));

    http_response_code(204);
} catch (InvalidEventApiKeyException) {
    http_response_code(401);
    echo $client->eventApi->errorResponseJson('Invalid API key');
}
```

```
// V controlleru pro GET /version
header('Content-Type: application/json');
echo $client->eventApi->versionResponseJson();
```

> KB při 401/403/404 odpovědi subscription **trvale zastaví** (status STOPPED). Při 500 nebo timeout circuit breaker (SUSPENDED), opakování → STOPPED. Nereaguj 5xx kvůli své interní chybě — vrať 204 a process asynchronně.

Symfony DI integrace
--------------------

[](#symfony-di-integrace)

Knihovna sama není Symfony bundle (žádný DI extension). Stačí YAML wiring:

```
# config/services.yaml
services:
    VsPoint\KbAdaa\Config\KbAdaaConfig:
        arguments:
            $apiKey: '%env(KB_ADAA_API_KEY)%'
            $environment: !php/enum VsPoint\KbAdaa\Enum\Environment::Production

    VsPoint\KbAdaa\Config\OAuth2Config:
        arguments:
            $apiKey: '%env(KB_OAUTH2_API_KEY)%'
            $clientId: '%env(KB_OAUTH2_CLIENT_ID)%'
            $clientSecret: '%env(KB_OAUTH2_CLIENT_SECRET)%'
            $redirectUri: '%env(KB_OAUTH2_REDIRECT_URI)%'
            $environment: !php/enum VsPoint\KbAdaa\Enum\Environment::Production

    VsPoint\KbAdaa\Config\ClientRegistrationConfig:
        arguments:
            $apiKey: '%env(KB_CR_API_KEY)%'
            $certPath: '%env(KB_CR_CERT_PATH)%'
            $environment: !php/enum VsPoint\KbAdaa\Enum\Environment::Production

    # Implementuj vlastní TokenStorage nad svou DB / Redisem
    VsPoint\KbAdaa\Token\TokenStorageInterface:
        class: App\Kb\DoctrineTokenStorage

    VsPoint\KbAdaa\KbAdaaClient:
        factory: ['VsPoint\KbAdaa\KbAdaaClient', 'create']
        arguments:
            $config: '@VsPoint\KbAdaa\Config\KbAdaaConfig'
            $tokenStorage: '@VsPoint\KbAdaa\Token\TokenStorageInterface'
            $oauth2Config: '@VsPoint\KbAdaa\Config\OAuth2Config'
            $clientRegistrationConfig: '@VsPoint\KbAdaa\Config\ClientRegistrationConfig'
```

Výjimky
-------

[](#výjimky)

Všechny API výjimky dědí z `KbAdaaApiException`. `getHttpStatus()`, `getResponseBody()`, `getErrorCode()` (parsovaný kód z `{"errors":[{"code":"…"}]}`).

HTTP / důvodTřídaTypické error codes400`InvalidRequestException``DATE_IN_FUTURE`, `INVALID_DATE_INTERVAL`, `INVALID_ACCOUNT_ID`, `INVALID_CORRELATION_ID`, `INVALID_CURRENCY`401`UnauthorisedException``INVALID_TOKEN`, `900900`403`ForbiddenException``ACCOUNT_ACCESS_DENIED`, `ACCOUNT_NOT_CONFIGURED`, `900908`404`NotFoundException``ACCOUNT_NOT_FOUND`, `STATEMENT_NOT_FOUND`, `SUBSCRIPTION_NOT_FOUND`429`RateLimitException``REQUEST_IS_THROTTLED` (1 stažení/hod limit), `getRetryAfterSeconds()`(refresh)`TokenRefreshFailedException`Refresh token expiroval → uživatel musí re-authorize(callback)`ApplicationRegistrationDecryptionException`Špatný klíč / poškozený ciphertext(webhook)`InvalidEventApiKeyException``x-api-key` z KB neodpovídá uložené hodnotě```
use VsPoint\KbAdaa\Exception\KbAdaaApiException;
use VsPoint\KbAdaa\Exception\NotFoundException;
use VsPoint\KbAdaa\Exception\RateLimitException;

try {
    $balances = $client->balances->list($accountId);
} catch (NotFoundException $e) {
    // accountId neexistuje
} catch (RateLimitException $e) {
    sleep($e->getRetryAfterSeconds() ?? 60);
} catch (KbAdaaApiException $e) {
    error_log($e->getHttpStatus() . ': ' . $e->getErrorCode() . ' — ' . $e->getResponseBody());
}
```

Přehled endpointů
-----------------

[](#přehled-endpointů)

ServiceMetodaHTTPPath`accounts``list()`GET`/adaa/v2/accounts``balances``list(accountId)`GET`/adaa/v2/accounts/{accountId}/balances``transactions``list(accountId, ?TransactionQuery)`GET`/adaa/v2/accounts/{accountId}/transactions``statements``list(accountId, StatementListQuery)`GET`/adaa/v2/accounts/{accountId}/statements``statements``download(accountId, statementId)`GET`/adaa/v2/accounts/{accountId}/statements/{statementId}``eventSubscriptions``create(accountId, CreateSubscriptionPayload)`POST`/adaa/v2/accounts/{accountId}/transactions/event-subscriptions``eventSubscriptions``get(accountId, subscriptionId)`GET`/adaa/v2/accounts/{accountId}/transactions/event-subscriptions/{id}``eventSubscriptions``delete(accountId, subscriptionId)`DELETE`/adaa/v2/accounts/{accountId}/transactions/event-subscriptions/{id}``oauth2``buildAuthorizationUrl(scopes, ?state)`— (browser redirect)login.kb.cz nebo sandbox UI`oauth2``exchangeAuthorizationCode(code)`POST`/oauth2/v3/access_token``oauth2``refresh(refreshToken)`POST`/oauth2/v3/access_token``clientRegistration``issue(SoftwareStatementPayload)`POST`/client-registration/v3/software-statements``applicationRegistration``buildRedirectUrl(env, RegistrationRequest)`— (browser redirect)client-registration-ui`applicationRegistration``decryptResponse(salt, encrypted, key)`— (lokální AES-GCM dešifrování)—`eventApi``handleEvent(body, expected, provided)`— (server-side helper)—Headless bootstrap v sandboxu
-----------------------------

[](#headless-bootstrap-v-sandboxu)

Sandbox OAuth2 obrazovka **autorizační kód generuje čistě v JavaScriptu** — žádné přihlašování, žádný backend roundtrip. Algoritmus je `base64(JSON({userId, scopes}))` bez `=` paddingu. Knihovna ho reprodukuje v PHP, takže integrační testy nemusí klikat v prohlížeči.

```
use VsPoint\KbAdaa\Enum\Scope;
use VsPoint\KbAdaa\Sandbox\SandboxAuthorizationCodeFactory;

$code = (new SandboxAuthorizationCodeFactory())->generate(
    userId: 'test',                       // libovolný neprázdný string — sandbox nehlídá
    scopes: [Scope::Adaa, Scope::CardData],
);

$token = $client->oauth2->exchangeAuthorizationCodeForToken(code: $code);

$tokenStorage->save($token);
// Hotovo — můžeš volat $client->accounts->list() atd.
```

Pro plný integrační test stačí jen **dva apiKey z developer portálu** (`KB_ADAA_API_KEY` + `KB_ADAA_OAUTH2_API_KEY`); `client_id` a `client_secret` jsou KB-dokumentované sandbox defaults (`ExampleClient-6303` / `bUfDQ1fMmfaSlZBZXlxBOQ`). Viz `tests/Integration/SandboxBootstrapTest.php` jako referenční E2E příklad — udělá code → token → `accounts->list()` proti reálnému KB sandboxu bez jakékoliv ruční interakce.

> **Pouze sandbox.** Produkční token endpoint tento kód odmítne. V produkci musí uživatel projít opravdovým KB loginem na `https://login.kb.cz/autfe/ssologin` — viz `OAuth2Service::buildAuthorizationUrl()`.

### Canary test sandboxového JS

[](#canary-test-sandboxového-js)

Sandbox algoritmus je závislý na tom, že ho KB nezmění. Unit test `testSandboxJavascriptStillImplementsKnownAlgorithm` stáhne živý JS a ověří přítomnost klíčových tokenů. Defaultně se skipuje; aktivuj přes:

```
docker run --rm -v "$(pwd):/app" -w /app -e KB_ADAA_SANDBOX_CANARY=1 vspoint/php:8.5-fpm-alpine sh -c "./vendor/bin/phpunit --testsuite Unit --filter Sandbox"
```

Pokud canary spadne, znamená to, že KB algoritmus změnili a je třeba aktualizovat `SandboxAuthorizationCodeFactory`.

Vývoj
-----

[](#vývoj)

`composer` není na hostu — všechno přes Docker:

```
# Instalace
docker run --rm -v "$(pwd):/app" -w /app vspoint/php:8.5-fpm-alpine sh -c "composer install --no-interaction --prefer-dist"

# PHPStan + ECS + Unit testy (musí všechno projít před commitem)
docker run --rm -v "$(pwd):/app" -w /app vspoint/php:8.5-fpm-alpine sh -c "./vendor/bin/ecs check --fix && ./vendor/bin/phpstan analyse --memory-limit=512M && ./vendor/bin/phpunit --testsuite Unit --testdox"

# Integrační testy proti reálnému KB sandboxu (vyžadují apiKeys — viz .secrets/README.md)
./bin/test-integration.sh
./bin/test-integration.sh --filter SandboxBootstrap   # filtr argy projdou skrz na phpunit
```

### Integrační testy

[](#integrační-testy)

Helper `bin/test-integration.sh` načte sandbox apiKeys z `.secrets/`, exportuje je jako env proměnné a spustí integration testy uvnitř Dockeru. Stačí mít dva JWT soubory:

```
.secrets/
├── sandbox-adaa-apikey.jwt       # KB_ADAA_API_KEY
└── sandbox-oauth2-apikey.jwt     # KB_ADAA_OAUTH2_API_KEY

```

Plný návod (kde získat klíče, jaký mít obsah) je v [`.secrets/README.md`](.secrets/README.md). Pozor — `.secrets/` je gitignored, klíče tam neházej do commitů.

**V GitLab CI** je k dispozici stage `integration`, který se aktivuje automaticky, pokud jsou v project Settings → CI/CD → Variables nastavené (Masked + Protected) proměnné `KB_ADAA_API_KEY` a `KB_ADAA_OAUTH2_API_KEY`. Forky / unprotected branches stage tiše přeskočí.

Pokud chceš testovat s předem získaným access/refresh tokenem (bez sandbox bootstrap), nastav místo `KB_ADAA_OAUTH2_API_KEY` proměnné `KB_ADAA_ACCESS_TOKEN` + `KB_ADAA_REFRESH_TOKEN` (volitelně + `KB_ADAA_ACCESS_TOKEN_EXPIRES_AT`, `KB_ADAA_SCOPE`, `KB_ADAA_ACCOUNT_ID`).

Kompatibilita
-------------

[](#kompatibilita)

- PHP ≥ 8.2
- Symfony Serializer / PropertyAccess / PropertyInfo 6.4, 7.x, 8.x
- Bez závislosti na Symfony FrameworkBundle / DI containeru

Licence
-------

[](#licence)

MIT

###  Health Score

38

—

LowBetter than 83% of packages

Maintenance95

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

23d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/e26703b5108310c1f3ef4966dd6f82a43b720950850a98b5d27a289d78e14730?d=identicon)[vitek499](/maintainers/vitek499)

---

Top Contributors

[![vitek499](https://avatars.githubusercontent.com/u/1543645?v=4)](https://github.com/vitek499 "vitek499 (3 commits)")

---

Tags

apiBankingkbOpen BankingKomerční bankaadaaaccount-direct-access

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleECS

Type Coverage Yes

### Embed Badge

![Health badge](/badges/vs-point-kb-adaa/health.svg)

```
[![Health](https://phpackages.com/badges/vs-point-kb-adaa/health.svg)](https://phpackages.com/packages/vs-point-kb-adaa)
```

###  Alternatives

[craftcms/cms

Craft CMS

3.6k3.6M2.9k](/packages/craftcms-cms)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k5.8M710](/packages/sylius-sylius)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

585.4M506](/packages/shopware-core)[api-platform/core

Build a fully-featured hypermedia or GraphQL API in minutes!

2.6k50.1M306](/packages/api-platform-core)[shopware/platform

The Shopware e-commerce core

3.4k1.5M3](/packages/shopware-platform)[web-auth/webauthn-lib

FIDO2/Webauthn Support For PHP

1237.8M117](/packages/web-auth-webauthn-lib)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
