rossaddison/storecove-client

Hand-written PHP client for the Storecove API (v2), for use by rossaddison/invoice

Maintainers

Package info

github.com/rossaddison/storecove-client

pkg:composer/rossaddison/storecove-client

Transparency log

Statistics

Installs: 0

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

dev-master 2026-08-28 18:24 UTC

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 for POST /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