Download the PHP package justinholtweb/craft-headdy without Composer

On this page you can find all versions of the php package justinholtweb/craft-headdy. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package craft-headdy

Headdy

A token-authenticated headless storefront API for Craft Commerce.

Craft Commerce has exposed products through GraphQL since version 2. It has never exposed a single cart or order mutation — craftcms/commerce discussion #2350 has been open for years, and the standing advice is to give up on GraphQL for the cart and POST form-encoded requests to actions/commerce/cart/update-cart with a PHP session cookie and a CSRF token.

That works for a Twig site posting to itself. For a Next, Nuxt or Astro front end on another origin it means credentials: 'include', a SameSite policy that survives your CDN, a round trip to fetch a CSRF token, responses shaped like Craft's internal element attributes, and a payment step that is simply unreachable because Craft hashes the return URL into a Twig form your JavaScript cannot produce.

WooCommerce has the Store API and CoCart. Craft has had nothing. Headdy is that layer.

No cookie. No CSRF token. Hold cart.token, send it back as X-Headdy-Cart, and you have a cart.

What you get

The one thing worth knowing about the design

services\Carts::update() is the only place a cart changes. Every REST endpoint, every GraphQL mutation and every console command builds a parameter array and hands it to that method. The granular verbs (POST /carts/current/items, PATCH …/items/{id}) exist because they read well — each is a few lines that assembles params and calls update().

So REST and GraphQL cannot drift apart, and there is exactly one place where stock checks, option signatures, recalculation order and validation happen.

Mutations are also applied in a fixed order regardless of the order you wrote them: clear → items → addresses → email → coupon → shipping → gateway → fields. Setting a shipping method before an address exists would pick from an empty option list; applying a coupon before the items are in would not meet the discount's minimum. One big patch and six small ones give the same answer.

Install

Then, in Settings → Plugins → Headdy, or from the command line:

That prints a public key and a secret. The secret is shown once — only its hash is stored.

Point your front end at https://your-site.com/api/storefront/v1 and send the public key in X-Headdy-Key.

Check the setup at any time:

Authentication, and why there is no CSRF token

Three modes:

Mode Header For
Public key (default) X-Headdy-Key Browser JavaScript. Identifies and scopes a caller; does not authenticate one.
Public key + secret + X-Headdy-Secret Server-side callers. A secret in a bundled JS file is not a secret.
None — A private network, and nowhere else.

A CSRF token defends a credential the browser attaches on its own. Headdy has no cookie: the cart token is only ever sent deliberately, which is the same defence a CSRF token provides. Requiring one would only add a round trip — exactly the friction that makes headless Commerce painful today.

Signing a customer in never logs them into Craft. Craft::$app->getUser() stays anonymous for every API request. A customer token identifies a shopper to Headdy's own endpoints and nothing else; it cannot be replayed against the control panel, and control panel accounts are refused outright.

Payment, and the return-URL problem

Craft's PaymentsController reads its return and cancel URLs with getValidatedBodyParam(), which only accepts a value Craft itself hashed into a Twig form. There is no endpoint that will mint that hash, so a JSON client cannot pay.

Headdy validates those URLs against an explicit allow-list instead. The hash exists to stop an attacker redirecting a shopper somewhere of their choosing after payment; an allow-list stops the same thing, and unlike the hash it can be satisfied from JavaScript.

The list is empty by default, so off-site gateways cannot be driven from the API until you say where returns may land. Relative paths are always accepted.

For an off-site gateway the response carries a redirect object rather than a 302:

Honour method: GET means navigate, POST means submit data as a form. Gateways that sign a POST body reject a customer who arrives by navigation.

CORS

An empty allowed-origins list reflects whatever origin asks. That is deliberate: CORS is not what protects this API — the bearer token is, and no cookie is ever sent — so a locked-down default would mean every new install starts broken for no security gain. Naming your front ends is still one less way for a leaked key to be used, and the Overview screen says so.

Access-Control-Allow-Credentials is off by default and cannot be combined with a * origin; browsers reject that pair, so Headdy refuses to save it.

Editions

Lite Pro
Carts, line items, addresses, coupons, shipping ✓ ✓
Checkout state and payment ✓ ✓
Catalog endpoints ✓ ✓
Multi-store, multi-site ✓ ✓
API keys, scopes, rate limiting ✓ ✓
Customer accounts, order history, address book ✓
GraphQL cart mutations ✓
Outbound webhooks ✓
Request log ✓

Lite $99 · Pro $199.

Documentation

Full documentation is at justinholt.com/plugins/craft-headdy/docs, built from docs/. The API contract — every endpoint, every error code, the GraphQL schema, webhook signing — is docs/api.md.

Console commands

Requirements

Craft CMS 5.3+, Craft Commerce 5.0+, PHP 8.2+.

Tested against Craft 5.10 and Commerce 5.7.

Testing

Static analysis runs in the same container (cd /var/www/craft-headdy first): vendor/bin/phpstan analyse --memory-limit=1G && vendor/bin/ecs check (level 4, clean).

The suite includes live HTTP round-trips against the real endpoint — key rejection, CORS preflight, the whole cart lifecycle and a real gateway payment — so a green run means the wire protocol works, not just the units.

Licence

The Craft License. See LICENSE.md.


All versions of craft-headdy with dependencies

PHP Build Version
Package Version
Requires php Version ^8.2
ext-json Version *
craftcms/cms Version ^5.3.0
craftcms/commerce Version ^5.0.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package justinholtweb/craft-headdy contains the following files

Loading the files please wait ...