with Claude Code, from controller to OpenAPI spec
Outdated API documentation costs integration partners time and generates support requests that could be avoided. Claude Code can derive OpenAPI descriptions directly from Magento controllers, webapi.xml, and service interfaces, but it does not replace verification against actual runtime behavior. This article shows how automated documentation can reliably fit into everyday development.
Table of contents
- 1. Starting point: why API documentation in Magento projects goes stale
- 2. From controller and webapi.xml to an OpenAPI description
- 3. Claude Code as a tool: context, prompting, and limits
- 4. Documenting REST and GraphQL endpoints in a targeted way
- 5. Verifying generated documentation against real API behavior
- 6. Automated verification with contract testing
- 7. Integrating documentation into the development workflow
- 8. Limits and risks: hallucinations and outdated assumptions
- 9. Tools and approaches compared
- 10. Summary
- 11. FAQ
1. Starting point: why API documentation in Magento projects goes stale
In most Magento projects, API documentation emerges as a byproduct rather than as part of the actual development process. A new REST endpoint gets declared in webapi.xml, the corresponding service interface gets implemented, the sprint ends, and the documentation in Confluence or a separate wiki stays at its previous state. After a few months, field names, required parameters, and error codes no longer match the actual behavior of the API.
The problem gets worse for externally consumed APIs: integration partners connecting a Magento backend to a PIM, an ERP, or a marketing automation platform rely on the documented contracts. When reality diverges, support requests appear that could otherwise have been avoided. Claude Code can help here because it can read code directly and derive an initial, structured description from it, before a human manually catches up on the documentation. What matters is that the generated description is treated as a draft, not a finished result.
2. From controller and webapi.xml to an OpenAPI description
Magento already provides an automatically generated, technically correct API description through its built-in schema endpoint at /rest/V1/schema?services=all. However, it contains almost no human-readable descriptions, no example values, and no hints about business logic that cannot be read directly from the type signature. This is exactly where Claude Code becomes useful: not as a replacement for the schema endpoint, but as a tool that augments the technical structure with understandable descriptions, examples, and context.
The starting point is always the code itself: etc/webapi.xml defines the route, HTTP method, and ACL resource, and the corresponding Api/*Interface.php defines parameter and return types with PHPDoc comments. Claude Code reads both files together with the referenced data models and derives an OpenAPI 3.0 description that includes paths, parameters, schemas, and possible error responses. It is important to explicitly instruct the model to document only fields that actually exist in the interface, to avoid invented content.
#!/usr/bin/env bash
# generate-api-docs.sh - Draft OpenAPI descriptions from Magento webapi.xml and interfaces
set -euo pipefail
MODULE_PATH="app/code/Mironsoft/SeoSuite"
claude --print \
"Read ${MODULE_PATH}/etc/webapi.xml and all files in ${MODULE_PATH}/Api/. \
Generate an OpenAPI 3.0 fragment in YAML for every declared REST route. \
Include request/response schemas derived from the *Interface.php return types \
and @param/@return PHPDoc annotations. Do not invent fields that are not \
present in the interface or its data model." \
> "${MODULE_PATH}/doc/openapi-draft.yaml"
echo "[INFO] Draft written to ${MODULE_PATH}/doc/openapi-draft.yaml, review required"
3. Claude Code as a tool: context, prompting, and limits
The quality of the generated documentation depends almost entirely on the context given to the model. A prompt that simply asks for "OpenAPI documentation for the SeoSuite API" produces generic, partly invented results. A prompt that explicitly points to webapi.xml, the concrete interface files, and the related data models produces a description grounded directly in the code. In practice, a two-pass approach works best: on the first pass, Claude Code produces a structural skeleton with all paths and schemas; on the second pass, description texts, example values, and error cases are added in a targeted way.
Project-specific conventions belong in a CLAUDE.md file or a reusable prompt template, so every generation run uses the same style, the same language, and the same structure. It is equally important to know the limits: Claude Code only sees what is in the code. Behavior that emerges at runtime through plugins, observers, or extension attributes does not automatically appear in the generated description unless those extensions are also part of the context that was read.
4. Documenting REST and GraphQL endpoints in a targeted way
REST and GraphQL APIs require different approaches to automated documentation. For REST endpoints, webapi.xml already provides a clear, declarative structure that translates almost one to one into OpenAPI paths. GraphQL lacks this explicit route declaration: the structure emerges from the schema.graphqls file and the corresponding resolver classes, which actually determine which fields are nullable, which errors can be thrown, and which permissions get checked.
For GraphQL, Claude Code should therefore receive both the schema definition and the PHP resolver implementation as context. A field declared as non-nullable in the schema but that can return null under certain conditions in the resolver is a classic example of a discrepancy that only shows up by reading the resolver code. The generated documentation should explicitly note such cases as an annotation, so that API consumers know the schema declaration alone is not enough to understand the actual behavior.
{
"paths": {
"/V1/seosuite/redirects/{id}": {
"get": {
"summary": "Retrieve a single redirect rule by its ID",
"operationId": "getRedirectById",
"parameters": [
{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }
],
"responses": {
"200": {
"description": "Redirect rule found",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/RedirectInterface" }
}
}
},
"404": {
"description": "No redirect rule with the given ID exists"
},
"403": {
"description": "Caller lacks the Mironsoft_SeoSuite::redirects ACL resource"
}
}
}
}
}
}
5. Verifying generated documentation against real API behavior
A description generated from code is only as correct as the code that was read, and code alone does not always show the actual runtime behavior. Validation rules that live in a base class, ACL checks that get tightened later by a plugin, or response fields that an observer adds at runtime are often invisible in the static code. This is why purely code-based generation is not enough to call the result reliable documentation.
The second, indispensable step is verification against a running staging environment. A simple approach: send real requests against the documented endpoints and compare the actual response structure with the generated schema. Discrepancies, such as extra fields, different required fields, or unexpected status codes, become visible this way before the documentation gets published. This step should not happen manually with occasional curl calls, but as a repeatable script that can run again on every change.
#!/usr/bin/env python3
"""Verify that live API responses match the generated OpenAPI schema."""
import sys
import requests
import yaml
from jsonschema import validate, ValidationError
with open("doc/openapi-draft.yaml") as f:
spec = yaml.safe_load(f)
BASE_URL = "https://staging.mironsoft.de/rest/V1"
def check_endpoint(path: str, schema_ref: str, sample_id: int) -> bool:
"""Fetch a live endpoint and validate the response against the documented schema."""
schema = spec["components"]["schemas"][schema_ref]
response = requests.get(f"{BASE_URL}{path.format(id=sample_id)}", timeout=10)
response.raise_for_status()
try:
validate(instance=response.json(), schema=schema)
return True
except ValidationError as exc:
print(f"[MISMATCH] {path}: {exc.message}", file=sys.stderr)
return False
if not check_endpoint("/seosuite/redirects/{id}", "RedirectInterface", sample_id=42):
sys.exit(1)
print("[OK] Live response matches the documented schema")
6. Automated verification with contract testing
Beyond simple schema comparisons, it is worth using dedicated contract testing tools such as Schemathesis or Dredd, which take an OpenAPI description as a contract and automatically generate a large number of test cases against it, including boundary values, missing required fields, and invalid types. This uncovers cases that are rarely considered during manual testing, such as what happens when a parameter documented as an integer is passed as a negative number or as a string.
Such tools should sensibly run against a dedicated staging instance with test data, not against production. The result is a report that lists every discrepancy between the documented contract and the actual behavior: undocumented 500 errors, fields that are missing despite the specification, or extra fields the documentation does not mention. These reports are the real basis for trusting the generated documentation, not the generation step itself. Without this step, every automatically generated API description remains an unverified claim about the system.
7. Integrating documentation into the development workflow
The biggest mistake when using AI-assisted documentation is treating it as a one-off action: generate once, review once, then forget. API documentation goes stale just as quickly as any other documentation if it is not part of the regular development cycle. The more effective approach treats openapi-draft.yaml like source code: versioned in the repository, with pull request review, and with a CI check that detects when the API surface has changed but the documentation was not updated along with it.
In practice, this means a CI step that checks, on every pull request, whether files under Api/ or etc/webapi.xml were changed. If so, the documentation is regenerated and compared against the committed version. If it differs, the check fails, and a developer must consciously review the change and commit the update. This mechanism prevents documentation and code from drifting apart again, without anyone having to actively remember to update the docs manually.
#!/usr/bin/env bash
# ci-doc-check.sh - Run in every pull request that touches Api/ or webapi.xml
set -euo pipefail
CHANGED_FILES=$(git diff --name-only origin/main...HEAD)
if echo "$CHANGED_FILES" | grep -qE 'Api/.*Interface\.php|etc/webapi\.xml'; then
echo "[INFO] API surface changed, regenerating documentation draft"
bash generate-api-docs.sh
git diff --exit-code doc/openapi-draft.yaml || {
echo "[WARN] Documentation draft differs from committed version"
echo "[WARN] Review doc/openapi-draft.yaml and commit the update"
exit 1
}
fi
It is also worth adding a lint step that checks the generated OpenAPI file for structural quality before merging, independent of whether the content is factually correct. A tool such as Spectral catches missing descriptions, inconsistent naming, and orphaned schema references before a reviewer even opens the file.
// validate-openapi.js - Lint the generated OpenAPI draft before merging
import { Spectral } from "@stoplight/spectral-core";
import { oas } from "@stoplight/spectral-rulesets";
import fs from "node:fs";
import yaml from "js-yaml";
const spectral = new Spectral();
spectral.setRuleset(oas);
const draft = yaml.load(fs.readFileSync("doc/openapi-draft.yaml", "utf8"));
const results = await spectral.run(draft);
const errors = results.filter((r) => r.severity === 0);
if (errors.length > 0) {
console.error(`[FAIL] ${errors.length} OpenAPI lint errors found`);
errors.forEach((e) => console.error(` ${e.path.join(".")}: ${e.message}`));
process.exit(1);
}
console.log("[OK] Generated OpenAPI draft passes lint rules");
8. Limits and risks: hallucinations and outdated assumptions
AI-generated API documentation is not a risk-free process. Claude can produce plausible-sounding but incorrect descriptions for sparsely commented interfaces, for example marking a field as "optional" even though the validation logic actually requires it. This risk increases noticeably for older or less common Magento modules with thin PHPDoc coverage, simply because the model has less reliable information available.
A second risk concerns security-relevant fields: personal data, internal IDs, or permission details should never be carried into publicly accessible documentation unreviewed just because the model found them in the code. Equally important: the model has no knowledge of company-specific unwritten agreements, such as a certain endpoint being considered internally deprecated even though the code is still active. Automatically generated documentation therefore never replaces the final human review before publication, it merely speeds up the drafting process considerably.
9. Tools and approaches compared
There are several established ways to produce and maintain API documentation, with notable differences in effort, freshness, and reliability. The following table compares the common approaches for Magento projects.
| Approach | Drawback | Recommended practice | Effect |
|---|---|---|---|
| Manual wiki maintenance | Stale after a few sprints | Claude-generated draft plus review | Docs stay aligned with current code |
| Native Magento schema endpoint only | No descriptions, no examples | Schema endpoint as base, Claude for context | Technically correct and understandable |
| Code-only auto-generation without review | Misses runtime deviations | Contract testing against staging API | Uncovers plugin and observer effects |
| Documentation as a one-off project | Drifts immediately after publication | CI check on every change to Api/ | Drift becomes visible in the pull request |
| Unreviewed publishing of generated fields | Risk for security-relevant data | Manual sign-off before publication | No sensitive fields published unreviewed |
The common thread across all recommended practices in the table: automation speeds up creation but does not replace review. Using Claude Code as the first drafting step, adding contract testing as a verification layer, and enforcing freshness through CI produces documentation that actually matches the live behavior of the API instead of only the state of the code at generation time.
Mironsoft
Magento and Hyva development with Claude Code in daily practice
API documentation that keeps pace with your code?
We set up a documentation workflow for Magento projects that generates OpenAPI descriptions from code, verifies them against real API behavior, and keeps them current through CI, instead of letting them go stale after a single pass.
Documentation audit
Check existing API documentation against the actual code and runtime state
OpenAPI setup
Set up Claude-Code-assisted generation for REST and GraphQL endpoints
CI integration
Build contract testing and drift detection into your pipeline
10. Summary
Automatically generated API documentation solves a real problem: manually maintained descriptions go stale reliably because they are not part of the actual development step. Claude Code can derive a structured first draft from webapi.xml, service interfaces, and resolver classes, produced far faster than a manual description. What matters, however, is that this draft is never published without review.
Real reliability only comes from verification against actual API behavior, for example through schema validation of real responses or dedicated contract testing, and from integration into a recurring workflow instead of a one-off task. A CI check that regenerates documentation and surfaces discrepancies on every change to the API surface prevents code and documentation from drifting apart again.
Automatically generating API documentation, the essentials at a glance
Code as the starting point
Provide webapi.xml and Api/*Interface.php as context so Claude Code does not add invented fields.
Verification is mandatory
Check generated schemas against real staging responses, ideally with contract testing instead of spot checks.
A recurring process
CI check on every change to Api/, so documentation does not go stale the same way it did before.
Human sign-off
Always review security-relevant fields and edge cases manually before publication.