magebitcom/acp-php-spec

Agentic Commerce Protocol specification for PHP

Maintainers

Package info

github.com/magebitcom/acp-php-spec

pkg:composer/magebitcom/acp-php-spec

Transparency log

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-08-12 08:14 UTC

This package is auto-updated.

Last update: 2026-08-12 08:18:20 UTC


README

PHP interfaces for the Agentic Commerce Protocol (ACP), generated from the official JSON Schema bundles vendored under spec/.

Installation

composer require magebitcom/acp-php-spec

What's included

One interface per schema type, namespaced by the bundle it comes from:

Namespace Bundle Covers
Magebit\AcpSpec\Api\AgenticCheckout schema.agentic_checkout.json Checkout sessions, line items, fulfillment, messages, orders
Magebit\AcpSpec\Api\Cart schema.cart.json Cart create/update
Magebit\AcpSpec\Api\DelegateAuthentication schema.delegate_authentication.json 3DS delegated authentication
Magebit\AcpSpec\Api\DelegatePayment schema.delegate_payment.json Payment delegation and allowances
Magebit\AcpSpec\Api\Discount schema.discount.json Discount extension
Magebit\AcpSpec\Api\Extension schema.extension.json Extension declarations
Magebit\AcpSpec\Api\Feed schema.feed.json Product feed

Why the bundle namespace matters

ACP defines several unrelated types under one name — Address appears in three bundles, Error in four, Link and AuthenticationResult in two. The bundle namespace keeps them apart, so there is no rename map and no arbitrary "last file wins" arbitration. AgenticCheckout\AddressInterface and DelegatePayment\AddressInterface are genuinely different shapes and stay that way.

One mutable tree, not two

Every interface has getters and setters, and there is exactly one tree. A read-only variant would double the surface for no benefit: an implementation that must not be mutated is enforced by the class, not by which interface it happens to implement.

Usage

use Magebit\AcpSpec\Api\AgenticCheckout\MessageErrorInterface;

class MyMessage implements MessageErrorInterface
{
    private string $content;

    public function getContent(): string
    {
        return $this->content;
    }

    public function setContent(string $content): self
    {
        $this->content = $content;
        return $this;
    }

    // ... plus getType/setType, getCode/setCode, getSeverity/setSeverity, ...
}

Every interface also carries constants, which is usually the fastest way in:

MessageErrorInterface::KEY_CONTENT;          // 'content'      — the wire key
MessageErrorInterface::TYPE_ERROR;           // 'error'        — a const discriminator
MessageErrorInterface::CODE_OUT_OF_STOCK;    // 'out_of_stock' — an enum member
MessageErrorInterface::SEVERITY_CRITICAL;    // 'critical'

KEY_* mirrors the JSON property name; every enum member and every const becomes a constant prefixed with its property name.

Type mapping

JSON Schema PHP PHPDoc
string / integer / number / boolean string / int / float / bool same
array with items array ItemInterface[]
array with a oneOf item array array<AInterface|BInterface>
object with properties interface SomeInterface
object that is a free-form map array array<string, string>
$ref to an object interface FQN same
$ref to a pure enum or scalar the underlying scalar same
const without type inferred from the value same
absent from required T|null T|null

Types are named by their $defs key; inline objects are named after their parent and property (CheckoutSession.discountsCheckoutSessionDiscountsInterface).

Versioning

SemVer, with one extra rule: a new ACP spec target always means a new MAJOR.

Part Bumped when
MAJOR New spec target, or a breaking change to emitted interfaces
MINOR New interfaces or members, nothing existing changed
PATCH Generator fix — same spec target, no new API

So ^1.0 means "built against ACP 2026-04-17", and a generator bug is fixed as a patch that consumers can take without thinking.

Library ACP spec target
1.x 2026-04-17

The target lives in composer.jsonextra.acp.spec-target and is copied into spec.manifest.json by the generator. The release workflow fails if they disagree, or if the target moved without a major bump.

Regenerating

composer install

php generate.php --clean   # regenerate everything
php generate.php --check   # CI drift gate: fail if committed output is stale

generate.php exits non-zero on any of:

  • a schema file that fails to load, resolve or compose;
  • integrity — a type referenced by the emitted code but never emitted itself. Without this gate a missing interface only surfaces as a fatal error at class-link time in a consuming project;
  • --check only: the fresh output differs from generated/, or spec.manifest.json is stale.

Name collisions and constants whose names collide within one interface are reported as warnings, not failures. Neither occurs at the current spec target.

Output is deterministic — inputs are sorted before generation, so two runs over the same spec/ are byte-identical regardless of filesystem iteration order.

Spec provenance (spec.manifest.json)

spec/ is a verbatim copy of upstream's spec/2026-04-17 directory at commit 7fdd78df677a94dce04c770644b0fbbb1401272b. The manifest records that commit plus a SHA-256 for every vendored file — including the OpenAPI and OpenRPC documents, which the generator does not read but which the HTTP surface depends on. spec.generator_inputs lists the subset that produced generated/.

To move to a new spec release: re-copy spec/, update all four extra.acp.upstream fields and extra.acp.spec-target in composer.json, run php generate.php --clean, and release a new MAJOR.

Known upstream defect

Item is additionalProperties: false and does not declare quantity, yet every upstream example sends it. Accept it leniently until this is resolved upstream.

Tests

vendor/bin/phpunit

The suite covers the naming scheme, cross-bundle composition, the value-versus-interface decision, constant emission, the integrity gate and output determinism. It does not test the generated interfaces themselves.

Licensing

The generator and the generated PHP are MIT — see LICENSE.md.

The vendored specification under spec/ is Apache-2.0, © OpenAI and © Stripe. Its license and notice are retained as spec/UPSTREAM-LICENSE and spec/UPSTREAM-NOTICE.

Links

Magebit

Magebit - Full-service e-commerce agency magebit.com