Versions
Documentation states the version it describes, and is updated as part of releasing a version rather than afterwards. If a page here disagrees with the SDK you have installed, check this page first.
What this documentation describes
| Component | Version | Source of truth | Distribution |
|---|---|---|---|
| PHP SDK | 0.1.0-dev | None declared. composer.json carries no
version field. |
not on Packagist — install from a checkout. |
| Python SDK | 0.1.0 | legibl.__version__ and
pyproject.toml. |
not on PyPI — install from a checkout. |
| Gateway HTTP API | unversioned | No version identifier assigned yet. | endpoints not deployed |
| This documentation | Reviewed 2026-08-06 | Read against the SDK sources on that date. | Static site, deployed independently. |
The PHP package genuinely declares no version. This documentation calls it
0.1.0-dev so that pages have something to name, and to keep it
aligned with the Python SDK it is conformance-tested against. Do not expect
composer show to print it.
Runtime requirements
| SDK | Runtime | Dependencies |
|---|---|---|
| PHP | 7.4.33+, and 8.x. The suite runs against both;
composer.json pins config.platform.php to
7.4.33 so resolution cannot silently pull packages needing 8.x. |
ext-dom, ext-libxml, ext-json,
plus ext-curl for the drop-ins. No Composer runtime
dependencies. |
| Python | 3.8+ | None. Optional extras legibl[httpx] and
legibl[requests] pull in the client you already use. |
PHP 7.4 reached end of life in November 2022 and receives no security patches. It is supported here because the first customer's stack requires it. That is a constraint being met, not a recommendation.
What is shipped
| Capability | PHP 0.1.0-dev | Python 0.1.0 |
|---|---|---|
| Detection of reCAPTCHA v2 / invisible / Turnstile | yes | yes |
| Image-captcha extraction helper | yes | yes |
| Automatic interception | curl_* drop-ins |
httpx transport, requests adapter |
Service client (createTask / getTaskResult) |
yes | yes |
| Modes: live, stub, replay, dry run | yes | yes |
| Observability | yes | yes |
| Impersonation status reporting | yes | n/a |
What is not shipped
Listed because a gap discovered in production is more expensive than one read in documentation.
| Gap | Affects | Consequence |
|---|---|---|
| Image OCR in the SDK's service client | both | An image_ocr extraction produces no solution from
HttpSolver; it builds reCAPTCHA and Turnstile tasks only.
Submit ImageToTextTask to
createTask yourself. |
| Config-level per-target extraction overrides | both | extractionOverrides /
extraction_overrides is declared and unread. Overrides work
only as a direct argument —
see the recipe. |
Stable reason_code alongside the prose reason |
both | Reason strings are not compared across languages; PHP and Python can
explain the same unhandled challenge differently and no test notices.
Switch on status, not on prose. |
SolveFailedException / SolveFailedError |
both | Declared but never raised. A failed solve is the
solve_failed outcome. |
| Guzzle and Symfony HttpClient middleware | PHP | Only the curl_* drop-ins exist. Code on Guzzle is not
intercepted. |
| Per-target transport profiles | PHP | Impersonation is process-wide via LD_PRELOAD; it cannot
be varied per target. |
| Multi-handle curl support | PHP | Legibl\curl_multi_exec() throws rather than forwarding
silently. Deliberate, and unlikely to change. |
| Public HTTP endpoints | gateway | The task parser and error envelope exist; the served API does not yet. The API page documents the contract, not a live service. |
| Package publication | both | Neither Packagist nor PyPI. Install from a checkout. |
Conformance between the SDKs
The two SDKs are verified against a shared fixture corpus rather than against fixtures of their own. For every fixture, the PHP detector and the Python reference extractor must produce identical results — that is the whole point of the corpus, and the conformance test is not optional. Any behaviour documented here as shared is shared because a test enforces it.
The exception, stated above: reason strings are prose and are not compared across languages.
How these docs are versioned
- Every page footer names the SDK versions it describes.
- Documentation changes ship as part of a release, not after it. A release that changes behaviour without changing these pages is an incomplete release.
- This site deploys independently of the gateway and the portal, so a documentation correction never carries the risk of a solver deploy — and it stays available when either application is not.