rossaddison / storecove-client
Hand-written PHP client for the Storecove API (v2), for use by rossaddison/invoice
Requires
- php: 8.4 - 9.0
- ext-curl: *
- ext-json: *
- ext-mbstring: *
- guzzlehttp/guzzle: >=7.15.5
- guzzlehttp/psr7: >=2.13.1
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.95.23
- phpunit/phpunit: >=13.1.4
- vimeo/psalm: >=6.16.1
This package is auto-updated.
Last update: 2026-08-28 18:40:13 UTC
README
A small, hand-written PHP client for the Storecove API (v2), built for rossaddison/invoice.
Why not a generated client?
This started as a full client generated from Storecove's OpenAPI spec (via
openapi-generator-cli, the classic php template, and separately via
Jane). Both produced a working client —
and both were unusable at Psalm errorLevel="1": 16,505 and 8,975 errors
respectively, almost entirely Mixed* errors from a generic, reflection-based
(de)serialization engine that has to handle all ~150 of Storecove's model
types generically (new $class() where $class is a runtime string,
$data->{$discriminator} where $discriminator is computed at runtime, and
so on — inherent to how that style of generator works, not a bug in either
tool).
rossaddison/invoice only ever needs six of those ~150 shapes, to call one
endpoint (POST /document_submissions). So this package hand-writes just
those six as plain, readonly, constructor-promoted PHP 8.4 classes with no
dynamic class resolution or property access anywhere — Psalm level-1 clean by
construction, not by suppression or baseline.
What's here
Model\RoutingIdentifier,Model\Routing,Model\RawDocumentData,Model\SendableDocument,Model\DocumentSubmission,Model\DocumentSubmissionResult— the request/response shapes forPOST /document_submissions.StorecoveClient— a thin Guzzle wrapper around that one endpoint.Exception\StorecoveApiException— thrown on a non-2xx response, carrying the raw response body.
Deliberately not here: Storecove's other ~34 endpoints (legal entities,
discovery, webhooks, purchase invoices, ...). Add a model + client method the
same way, only when rossaddison/invoice actually needs one.
Usage
use RossAddison\StorecoveClient\StorecoveClient; use RossAddison\StorecoveClient\Model\{DocumentSubmission, Routing, RoutingIdentifier, SendableDocument, RawDocumentData}; $client = new StorecoveClient(apiKey: $apiKey); $submission = new DocumentSubmission( document: new SendableDocument( documentType: 'invoice', rawDocumentData: new RawDocumentData(document: base64_encode($ublXml)), ), legalEntityId: $legalEntityId, idempotencyGuid: Uuid::uuid4()->toString(), // a fresh one per invoice — never a fixed literal routing: new Routing(eIdentifiers: [ new RoutingIdentifier(scheme: $scheme, id: $participantId), ]), ); $result = $client->createDocumentSubmission($submission); // $result->guid — store this against the invoice for later status lookup