The plugin protects the same targets in the Shop API. The flow has two steps: fetch a challenge, solve it, and send the solution along with the protected request.
# 1. fetch a challenge (same body the widget consumes)
curl https://shop.example/api/v2/shop/altcha/challenge
# 2. solve it with any ALTCHA client library, then send the payload with the protected request
curl -X POST https://shop.example/api/v2/shop/customers/token \
-H 'Content-Type: application/json' \
-H 'X-Altcha-Payload: <base64 payload>' \
-d '{"email":"...","password":"..."}'
| Method | Path | Description |
|---|---|---|
GET |
%sylius.security.api_shop_route%/altcha/challenge |
Issues a challenge, identical format to the storefront endpoint (/altcha/challenge) |
| any protected operation | - | Accepts the proof as the X-Altcha-Payload header, or as an altcha field in a JSON body (application/json, application/ld+json, merge-patch) or form body |
The challenge endpoint is public and limited to 30 calls per client per minute, since each call costs one key derivation. A channel that is not enabled answers 404.
API requests are recognised by their route names (sylius_api_*), through the %sylius.security.api_shop_route% prefix - a customised API prefix needs no extra plugin configuration.
A rejected request returns HTTP 422 (429 when rate-limited) with a JSON body:
{ "message": "Your message could not be accepted", "reason": "gibberish" }
| Field | Description |
|---|---|
message |
Neutral, human-readable message. It is translated in the locale the channel resolves to, because the API has no _locale in its URL. |
reason |
Stable, machine-readable code, independent of the language (for example disposable_email, gibberish, rate_limited) |
The possible
reasonvalues are part of the plugin's backward compatibility, but new ones may be added in a minor release. Treat unknown values in your client like a generic rejection (see Extensibility and Compatibility).