Cliente PHP oficial de la API de Pimia para apps de partner: OAuth con PKCE, rotación del refresh token persistida, reintentos de rate limit y excepciones tipadas. Licencia MIT.
El código vive en el monorepo
Pimia-AI/pimia-sdks, directoriophp/.Pimia-AI/pimia-phpes un espejo de solo lectura que se regenera en cada release: existe porque Composer exige elcomposer.jsonen la raíz del repositorio. Las incidencias y los PRs, al monorepo.
Requisitos: PHP ≥ 8.2 + un cliente HTTP PSR-18 (cualquiera vale; Guzzle es el sugerido).
composer require pimia/pimia-phpPendiente del alta en Packagist. El código ya es público y no hace falta invitación. Dos caminos mientras tanto:
a) repositorio
vcsapuntando al espejo de solo lecturaPimia-AI/pimia-php, que sí lleva elcomposer.jsonen la raíz:b) repositorio
pathsobre un clon del monorepo. Un repositoriovcsapuntando al monorepo no funciona: Composer exige elcomposer.jsonen la raíz del repo y aquí el paquete vive enphp/.// composer.json de tu app { "repositories": [ { "type": "path", "url": "../pimia-sdks/php" } ] }git clone git@github.com:Pimia-AI/pimia-sdks.git composer require "pimia/pimia-php:@dev"
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\HttpFactory;
use Pimia\{Config, PimiaClient, Scopes};
use Pimia\Http\PsrTransport;
use Pimia\OAuth\{InMemoryTokenStore, OAuthClient, PkceChallenge};
$config = new Config(
baseUrl: 'https://acme.pimia.es',
clientId: getenv('PIMIA_CLIENT_ID'),
clientSecret: getenv('PIMIA_CLIENT_SECRET') ?: null,
redirectUri: 'https://miapp.example/callback',
);
$factory = new HttpFactory();
$transport = new PsrTransport(new Client(), $factory, $factory);
// 1. Autorización
$pkce = PkceChallenge::create(); // guarda $pkce->verifier en sesión
$oauth = new OAuthClient($config, $transport);
$url = $oauth->authorizeUrl([Scopes::INVOICES_READ], PkceChallenge::state(), $pkce);
// 2. Callback: canje + persistencia
$tokens = new InMemoryTokenStore(); // en producción: tu BD
$tokens->save($oauth->exchangeCode($code, PkceChallenge::fromVerifier($verifierDeSesion)));
// 3. Uso
$pimia = new PimiaClient($config, $transport, $tokens);
$invoices = $pimia->invoices->list(['page' => 1]);El refresh token de Pimia rota. Cada refresco devuelve uno nuevo y mata el
anterior; reusar uno ya rotado revoca el grant entero en cascada. Por eso el
cliente exige un TokenStore: persiste el conjunto de tokens tras cada
refresco y no refresques dos veces en paralelo con el mismo token. Las dos
cosas las cubre el SDK si lo usas como está pensado.
Documentación completa, modelo mental (un tenant = una base URL = un token), tabla de excepciones tipadas y el contrato OpenAPI, en el monorepo: Pimia-AI/pimia-sdks.
{ "repositories": [ { "type": "vcs", "url": "https://github.com/Pimia-AI/pimia-php" } ] }