SellerMagnet does not publish an OpenAPI (Swagger) document for its Amazon API, so tools that import one, Insomnia, Stoplight, Redocly, or an openapi-generator/openapi-python-client codegen run, have nothing to read. This post builds a real openapi.json from the API's own documented 10 endpoints, parameters and response shapes, and ships a dependency-free Python validator that checks the spec's structure is correct, not a response-body validator against the live API.
Key Takeaways
- The spec covers exactly the 10 real endpoints with their documented required/optional parameters, no invented 11th endpoint and no invented parameter.
- api_key is modelled as two OpenAPI security schemes (ApiKeyHeader for X-Api-Key, ApiKeyQuery for ?api_key=), never as a plain query parameter, matching how the API actually authenticates.
- Response schemas are capped at two levels deep on purpose: a full nested dump for all 10 endpoints runs past 46 KB of JSON, most of it duplicate shape already covered field-by-field in the quickstart and Postman-collection posts linked below.
- The validator was run three times against a deliberately broken copy of the real spec, a dropped endpoint, a required parameter demoted to optional, and api_key reintroduced as a query parameter, and it failed all three, proving the checks catch real mistakes instead of rubber-stamping any input.
- This was not run against the live API: it is a structural check on the spec file, the same honesty callout as the Postman-collection post's newman note.
What the spec covers
- All 10 endpoints: get marketplaces, product lookup, product statistics, product offers, seller review, search, bestsellers, deals, estimated monthly sales, and the ASIN/EAN converter.
- Dual auth as two security schemes:
ApiKeyHeader(headerX-Api-Key) andApiKeyQuery(queryapi_key), listed as alternatives on every operation, matching the real header-vs-query behaviour. - Every documented parameter, with its real required/optional flag, for example
asin+marketplaceIdrequired on lookup,graphsoptional on statistics. - Every status code the API actually returns: 200, 400, 401, 404, 429, 500, 502, 503, each with the billing note from the API's own docs (a free gate 400 versus a billed endpoint 400, a refunded 500 versus a billed 502/503).
Why build this instead of just using the Postman collection?
The Postman collection for this API is a Postman-specific file with embedded pm.test() assertions; it only works inside Postman or newman. OpenAPI is a vendor-neutral standard: the same openapi.json imports into Postman, Insomnia, Stoplight and most API gateways, and feeds openapi-generator/openapi-python-client to produce a typed client in languages beyond the ones already covered by the Python, Go and other quickstarts. The two artifacts solve different problems: the collection is for manually poking the API and running assertions, the spec is for generating code and for other tools' import screens.
The generated spec: openapi.json
Built from the API's own documented endpoint list and response shapes (the same source the API documentation and the code examples page describe), minified here for space; python -m json.tool openapi.json pretty-prints it locally. This is the exact file the validator below checks.
openapi.json, OpenAPI 3.0.3, 10 paths, minified
{"openapi":"3.0.3","info":{"title":"SellerMagnet Amazon Data API","version":"1.0.0","description":"Unofficial spec built from the public parameter and response docs at https://sellermagnet-api.com/documentation. Not published by SellerMagnet; regenerate it after an endpoint changes."},"servers":[{"url":"https://sellermagnet-api.com/api"}],"components":{"securitySchemes":{"ApiKeyHeader":{"type":"apiKey","in":"header","name":"X-Api-Key"},"ApiKeyQuery":{"type":"apiKey","in":"query","name":"api_key"}}},"paths":{"/amazon-product-statistics":{"get":{"summary":"Amazon Product Statistics","description":"Retrieve detailed statistics for an Amazon product, including sales rank and review counts.","parameters":[{"name":"asin","in":"query","required":true,"description":"Product ASIN (e.g., \"B08N5WRWNW\")","schema":{"type":"string"}},{"name":"marketplaceId","in":"query","required":true,"description":"Marketplace ID (e.g., \"A1PA6795UKMFR9\")","schema":{"type":"string"}},{"name":"graphs","in":"query","required":false,"description":"Set to true to add data.graphs: a PNG chart URL per series (same single credit)","schema":{"type":"string"}}],"security":[{"ApiKeyHeader":[]},{"ApiKeyQuery":[]}],"responses":{"200":{"description":"success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"see the linked quickstart/FACTS posts for exact fields"},"success":{"type":"boolean"}},"required":["data","success"]}}}},"400":{"description":"bad request (free gate 400s are free; endpoint 400s are billed)"},"401":{"description":"invalid/inactive key or insufficient credits"},"404":{"description":"product/seller not found (billed)"},"429":{"description":"rate limited (free; honour Retry-After)"},"500":{"description":"upstream parse failure (refunded once)"},"502":{"description":"upstream fetch failure (billed, retry up to 4x)"},"503":{"description":"upstream unavailable (billed, retry up to 4x)"}}}},"/amazon-asin-converter":{"get":{"summary":"Amazon ASIN Converter","description":"Convert between ASIN and EAN identifiers for Amazon products.","parameters":[{"name":"asin","in":"query","required":true,"description":"ASIN or EAN to convert (e.g., \"B08N5WRWNW\" or \"9781234567890\")","schema":{"type":"string"}},{"name":"marketplaceId","in":"query","required":true,"description":"Marketplace ID (e.g., \"A1PA6795UKMFR9\")","schema":{"type":"string"}},{"name":"conversion_direction","in":"query","required":true,"description":"Conversion direction: \"asin-to-ean\" or \"ean-to-asin\"","schema":{"type":"string"}}],"security":[{"ApiKeyHeader":[]},{"ApiKeyQuery":[]}],"responses":{"200":{"description":"success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"see the linked quickstart/FACTS posts for exact fields"},"success":{"type":"boolean","description":"Indicates whether the API request was successful."}},"required":["data","success"],"additionalProperties":false}}}},"400":{"description":"bad request (free gate 400s are free; endpoint 400s are billed)"},"401":{"description":"invalid/inactive key or insufficient credits"},"404":{"description":"product/seller not found (billed)"},"429":{"description":"rate limited (free; honour Retry-After)"},"500":{"description":"upstream parse failure (refunded once)"},"502":{"description":"upstream fetch failure (billed, retry up to 4x)"},"503":{"description":"upstream unavailable (billed, retry up to 4x)"}}}},"/amazon-seller-review":{"get":{"summary":"Get Amazon Seller Review","description":"Fetch review details for a specific Amazon seller.","parameters":[{"name":"sellerId","in":"query","required":true,"description":"Seller ID of a seller on that marketplace (e.g., \"A1CWSGXIR635I6\")","schema":{"type":"string"}},{"name":"marketplaceId","in":"query","required":true,"description":"Marketplace ID (e.g., \"ATVPDKIKX0DER\")","schema":{"type":"string"}}],"security":[{"ApiKeyHeader":[]},{"ApiKeyQuery":[]}],"responses":{"200":{"description":"success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"see the linked quickstart/FACTS posts for exact fields"},"success":{"type":"boolean","description":"Indicates whether the API request was successful."}},"required":["data","success"]}}}},"400":{"description":"bad request (free gate 400s are free; endpoint 400s are billed)"},"401":{"description":"invalid/inactive key or insufficient credits"},"404":{"description":"product/seller not found (billed)"},"429":{"description":"rate limited (free; honour Retry-After)"},"500":{"description":"upstream parse failure (refunded once)"},"502":{"description":"upstream fetch failure (billed, retry up to 4x)"},"503":{"description":"upstream unavailable (billed, retry up to 4x)"}}}},"/amazon-product-lookup":{"get":{"summary":"Get Amazon Product","description":"Retrieve detailed product information for a given ASIN.","parameters":[{"name":"asin","in":"query","required":true,"description":"Product ASIN (e.g., 'B08N5WRWNW')","schema":{"type":"string"}},{"name":"marketplaceId","in":"query","required":true,"description":"Marketplace ID (e.g., 'A1PA6795UKMFR9')","schema":{"type":"string"}}],"security":[{"ApiKeyHeader":[]},{"ApiKeyQuery":[]}],"responses":{"200":{"description":"success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"see the linked quickstart/FACTS posts for exact fields"},"success":{"type":"boolean","description":"Indicates whether the API request was successful."}},"required":["data","success"],"additionalProperties":false}}}},"400":{"description":"bad request (free gate 400s are free; endpoint 400s are billed)"},"401":{"description":"invalid/inactive key or insufficient credits"},"404":{"description":"product/seller not found (billed)"},"429":{"description":"rate limited (free; honour Retry-After)"},"500":{"description":"upstream parse failure (refunded once)"},"502":{"description":"upstream fetch failure (billed, retry up to 4x)"},"503":{"description":"upstream unavailable (billed, retry up to 4x)"}}}},"/amazon-product-offers":{"get":{"summary":"Get Amazon Product Offers","description":"List offers for a product, including price, seller, condition, and inventory details.","parameters":[{"name":"asin","in":"query","required":true,"description":"Product ASIN (e.g., 'B08N5WRWNW')","schema":{"type":"string"}},{"name":"marketplaceId","in":"query","required":true,"description":"Marketplace ID (e.g., 'A1PA6795UKMFR9')","schema":{"type":"string"}},{"name":"geo_location","in":"query","required":false,"description":"Detailed Geo Location ZIP CODE","schema":{"type":"string"}}],"security":[{"ApiKeyHeader":[]},{"ApiKeyQuery":[]}],"responses":{"200":{"description":"success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"see the linked quickstart/FACTS posts for exact fields"},"success":{"type":"boolean","description":"Indicates whether the API request was successful."}},"required":["data","success"],"additionalProperties":false}}}},"400":{"description":"bad request (free gate 400s are free; endpoint 400s are billed)"},"401":{"description":"invalid/inactive key or insufficient credits"},"404":{"description":"product/seller not found (billed)"},"429":{"description":"rate limited (free; honour Retry-After)"},"500":{"description":"upstream parse failure (refunded once)"},"502":{"description":"upstream fetch failure (billed, retry up to 4x)"},"503":{"description":"upstream unavailable (billed, retry up to 4x)"}}}},"/amazon-get-marketplaces":{"get":{"summary":"Get Amazon Marketplaces","description":"Retrieve every supported Amazon marketplace, keyed by marketplace ID, with its domain, name, currency and default geo_location postcode.","parameters":[],"security":[{"ApiKeyHeader":[]},{"ApiKeyQuery":[]}],"responses":{"200":{"description":"success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","description":"see the linked quickstart/FACTS posts for exact fields"}}}}}},"400":{"description":"bad request (free gate 400s are free; endpoint 400s are billed)"},"401":{"description":"invalid/inactive key or insufficient credits"},"404":{"description":"product/seller not found (billed)"},"429":{"description":"rate limited (free; honour Retry-After)"},"500":{"description":"upstream parse failure (refunded once)"},"502":{"description":"upstream fetch failure (billed, retry up to 4x)"},"503":{"description":"upstream unavailable (billed, retry up to 4x)"}}}},"/amazon-search":{"get":{"summary":"Search Amazon","description":"Search Amazon products by keyword.","parameters":[{"name":"q","in":"query","required":true,"description":"Search query (e.g., \"phone\")","schema":{"type":"string"}},{"name":"marketplaceId","in":"query","required":true,"description":"Marketplace ID (e.g., \"A1PA6795UKMFR9\")","schema":{"type":"string"}},{"name":"count","in":"query","required":false,"description":"Number of results (max 50, default 30)","schema":{"type":"string"}},{"name":"geo_location","in":"query","required":false,"description":"Detailed Geo Location ZIP CODE","schema":{"type":"string"}}],"security":[{"ApiKeyHeader":[]},{"ApiKeyQuery":[]}],"responses":{"200":{"description":"success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"see the linked quickstart/FACTS posts for exact fields"},"success":{"type":"boolean","description":"Indicates whether the API request was successful."}},"required":["data","success"],"additionalProperties":false}}}},"400":{"description":"bad request (free gate 400s are free; endpoint 400s are billed)"},"401":{"description":"invalid/inactive key or insufficient credits"},"404":{"description":"product/seller not found (billed)"},"429":{"description":"rate limited (free; honour Retry-After)"},"500":{"description":"upstream parse failure (refunded once)"},"502":{"description":"upstream fetch failure (billed, retry up to 4x)"},"503":{"description":"upstream unavailable (billed, retry up to 4x)"}}}},"/amazon-bestsellers":{"get":{"summary":"Get Amazon Bestsellers","description":"Fetch top-selling products in a specific category.","parameters":[{"name":"category_id","in":"query","required":true,"description":"Category ID (e.g., 'electronics') or category name in the marketplace's language, such as 'dog food'. A name that fits several categories, or none, is a free 400 listing the candidates; a resolved name adds resolved_category to the response.","schema":{"type":"string"}},{"name":"marketplaceId","in":"query","required":true,"description":"Marketplace ID (e.g., 'A1PA6795UKMFR9')","schema":{"type":"string"}},{"name":"count","in":"query","required":false,"description":"Number of results (max 50, default 30)","schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"description":"Skip the first N ranks (default 0; offset + count must be at most 50)","schema":{"type":"string"}}],"security":[{"ApiKeyHeader":[]},{"ApiKeyQuery":[]}],"responses":{"200":{"description":"success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"see the linked quickstart/FACTS posts for exact fields"},"success":{"type":"boolean","description":"Indicates whether the API request was successful."}},"required":["data","success"],"additionalProperties":false}}}},"400":{"description":"bad request (free gate 400s are free; endpoint 400s are billed)"},"401":{"description":"invalid/inactive key or insufficient credits"},"404":{"description":"product/seller not found (billed)"},"429":{"description":"rate limited (free; honour Retry-After)"},"500":{"description":"upstream parse failure (refunded once)"},"502":{"description":"upstream fetch failure (billed, retry up to 4x)"},"503":{"description":"upstream unavailable (billed, retry up to 4x)"}}}},"/amazon-deals":{"get":{"summary":"Get Amazon Deals","description":"Current deals of a marketplace as JSON: deal price, list price, savings, start/end time and a lightning-deal flag.","parameters":[{"name":"marketplaceId","in":"query","required":true,"description":"Marketplace ID (e.g., 'A1PA6795UKMFR9')","schema":{"type":"string"}},{"name":"category_id","in":"query","required":false,"description":"Department slug to filter by (e.g., 'electronics'); omit for all deals","schema":{"type":"string"}},{"name":"count","in":"query","required":false,"description":"Number of deals to return (default 30, max 50)","schema":{"type":"string"}},{"name":"geo_location","in":"query","required":false,"description":"Detailed Geo Location ZIP CODE","schema":{"type":"string"}}],"security":[{"ApiKeyHeader":[]},{"ApiKeyQuery":[]}],"responses":{"200":{"description":"success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"see the linked quickstart/FACTS posts for exact fields"},"success":{"type":"boolean","description":"Indicates whether the API request was successful."}},"required":["data","success"],"additionalProperties":false}}}},"400":{"description":"bad request (free gate 400s are free; endpoint 400s are billed)"},"401":{"description":"invalid/inactive key or insufficient credits"},"404":{"description":"product/seller not found (billed)"},"429":{"description":"rate limited (free; honour Retry-After)"},"500":{"description":"upstream parse failure (refunded once)"},"502":{"description":"upstream fetch failure (billed, retry up to 4x)"},"503":{"description":"upstream unavailable (billed, retry up to 4x)"}}}},"/amazon-product-search-estimated-sells":{"get":{"summary":"Amazon Product Search Estimated Sells","description":"Retrieve estimated sales data for an Amazon product by ASIN.","parameters":[{"name":"asin","in":"query","required":true,"description":"Product ASIN (e.g., \"B08N5WRWNW\")","schema":{"type":"string"}},{"name":"marketplaceId","in":"query","required":true,"description":"Marketplace ID (e.g., \"A1PA6795UKMFR9\")","schema":{"type":"string"}}],"security":[{"ApiKeyHeader":[]},{"ApiKeyQuery":[]}],"responses":{"200":{"description":"success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"see the linked quickstart/FACTS posts for exact fields"},"success":{"type":"boolean","description":"Indicates whether the API request was successful."}},"required":["data","success"],"additionalProperties":false}}}},"400":{"description":"bad request (free gate 400s are free; endpoint 400s are billed)"},"401":{"description":"invalid/inactive key or insufficient credits"},"404":{"description":"product/seller not found (billed)"},"429":{"description":"rate limited (free; honour Retry-After)"},"500":{"description":"upstream parse failure (refunded once)"},"502":{"description":"upstream fetch failure (billed, retry up to 4x)"},"503":{"description":"upstream unavailable (billed, retry up to 4x)"}}}}}}
Why does the response schema stop at two levels deep?
Several endpoints nest deeply, statistics and search run six or more levels before reaching a plain string or number, and reproducing every one of those levels for all 10 endpoints puts the unminified spec past 46 KB, nearly all of it a second copy of field shapes already documented field-by-field in the language quickstarts and in the Postman collection's price-shape table. Past two levels the schema keeps just the type (object or array) and a pointer to where the real shape lives, which keeps the spec a readable top-level reference instead of a duplicate field dump; a tool that generates a client only needs the top-level shape to produce working method signatures, the per-field types are a client-code concern.
| Endpoint | Required parameters |
|---|---|
/amazon-get-marketplaces | none (beyond auth) |
/amazon-product-lookup | asin, marketplaceId |
/amazon-product-offers | asin, marketplaceId |
/amazon-product-statistics | asin, marketplaceId |
/amazon-product-search-estimated-sells | asin, marketplaceId |
/amazon-asin-converter | asin, marketplaceId, conversion_direction |
/amazon-seller-review | sellerId, marketplaceId |
/amazon-search | q, marketplaceId |
/amazon-bestsellers | category_id, marketplaceId |
/amazon-deals | marketplaceId |

How was this validated without calling the live API?
This checks the SPEC, not a live response: required OpenAPI keys present, all 10 endpoints present and no extra ones, every operation's required/optional parameter flags matching the documented set, api_key never listed as a plain query parameter, both security schemes present with the right in/name, every documented status code covered, and the whole structure round-tripping through json.dumps/json.loads. No network call is made and no dependency beyond the standard library is used.
not run against the live API
Like the Postman-collection post's newman note: this validates the spec document itself. It does not call sellermagnet-api.com, so it cannot catch a live response that drifted from its documented shape, that is what the FACTS-grounded quickstart and Postman-collection posts, which do decode real documented field shapes in real client code, are for.
validate_openapi.py, structural validator, stdlib only
"""Structural validator for the SellerMagnet OpenAPI spec (openapi.json), run with no network access
and no dependencies beyond the standard library. It is not a response-body validator: we do not call
the live API here (see the "not run against live" note in the post), so it checks the SPEC itself -
the properties a broken generator run, a hand-edit or a future script change could silently break:
every endpoint present, every parameter typed and flagged required/optional correctly against the
API's own documented endpoint list, the dual auth schemes, and valid, round-trippable JSON throughout.
"""
import copy
import json
import sys
REQUIRED_RESPONSES = {"200", "400", "401", "404", "429", "500", "502", "503"}
# The exact (endpoint, required-params) pairs the API documents for each endpoint; api_key
# excluded because the spec models it as a security scheme, not a parameter.
EXPECTED = {
"/amazon-product-statistics": {"asin", "marketplaceId"},
"/amazon-asin-converter": {"asin", "marketplaceId", "conversion_direction"},
"/amazon-seller-review": {"sellerId", "marketplaceId"},
"/amazon-product-lookup": {"asin", "marketplaceId"},
"/amazon-product-offers": {"asin", "marketplaceId"},
"/amazon-get-marketplaces": set(),
"/amazon-search": {"q", "marketplaceId"},
"/amazon-bestsellers": {"category_id", "marketplaceId"},
"/amazon-deals": {"marketplaceId"},
"/amazon-product-search-estimated-sells": {"asin", "marketplaceId"},
}
def validate(spec: dict) -> list[str]:
"""Returns a list of problems; an empty list means the spec passes every check."""
problems = []
for key in ("openapi", "info", "servers", "paths", "components"):
if key not in spec:
problems.append(f"missing top-level key: {key}")
if problems:
return problems # nothing else is safe to inspect
if spec["paths"].keys() != EXPECTED.keys():
missing = EXPECTED.keys() - spec["paths"].keys()
extra = spec["paths"].keys() - EXPECTED.keys()
if missing:
problems.append(f"missing endpoints: {sorted(missing)}")
if extra:
problems.append(f"undocumented endpoints: {sorted(extra)}")
seen_operation_names = set()
for path, expected_required in EXPECTED.items():
if path not in spec["paths"]:
continue
ops = spec["paths"][path]
if "get" not in ops:
problems.append(f"{path}: no get operation")
continue
op = ops["get"]
for field in ("summary", "parameters", "responses", "security"):
if field not in op:
problems.append(f"{path}: operation missing '{field}'")
if op.get("summary") in seen_operation_names:
problems.append(f"{path}: duplicate summary {op['summary']!r} (operationIds would collide)")
seen_operation_names.add(op.get("summary"))
if "api_key" in {p["name"] for p in op.get("parameters", [])}:
problems.append(f"{path}: api_key listed as a query parameter, should be a security scheme only")
actual_required = {p["name"] for p in op.get("parameters", []) if p.get("required")}
if actual_required != expected_required:
problems.append(f"{path}: required params {sorted(actual_required)} != "
f"catalogue {sorted(expected_required)}")
for p in op.get("parameters", []):
if "schema" not in p or "type" not in p.get("schema", {}):
problems.append(f"{path}: parameter {p.get('name')} has no typed schema")
missing_responses = REQUIRED_RESPONSES - op.get("responses", {}).keys()
if missing_responses:
problems.append(f"{path}: missing response codes {sorted(missing_responses)}")
schemes = spec.get("components", {}).get("securitySchemes", {})
want = {"ApiKeyHeader": ("header", "X-Api-Key"), "ApiKeyQuery": ("query", "api_key")}
for name, (location, field) in want.items():
scheme = schemes.get(name)
if not scheme or scheme.get("in") != location or scheme.get("name") != field:
problems.append(f"security scheme {name} missing or wrong (expected in={location}, name={field})")
try:
json.loads(json.dumps(spec))
except (TypeError, ValueError) as exc:
problems.append(f"spec does not round-trip through JSON: {exc}")
return problems
def run_scenario(name: str, spec: dict) -> None:
problems = validate(spec)
status = "PASS" if not problems else "FAIL"
print(f"{name}: {status}" + ("" if not problems else f" ({len(problems)} problem(s))"))
for p in problems:
print(f" - {p}")
if __name__ == "__main__":
with open("openapi.json") as f:
good = json.load(f)
run_scenario("real spec, unmodified", good)
broken_missing_path = copy.deepcopy(good)
del broken_missing_path["paths"]["/amazon-bestsellers"]
run_scenario("tampered: dropped one endpoint", broken_missing_path)
broken_required = copy.deepcopy(good)
for p in broken_required["paths"]["/amazon-product-lookup"]["get"]["parameters"]:
if p["name"] == "asin":
p["required"] = False # simulates a generator bug that forgot the required flag
run_scenario("tampered: asin marked optional on lookup", broken_required)
broken_api_key = copy.deepcopy(good)
broken_api_key["paths"]["/amazon-product-offers"]["get"]["parameters"].append(
{"name": "api_key", "in": "query", "required": True, "schema": {"type": "string"}})
run_scenario("tampered: api_key reintroduced as a query parameter", broken_api_key)
sys.exit(0 if not validate(good) else 1)
Real output: python3 validate_openapi.py (this environment, no network, no dependencies)
real spec, unmodified: PASS
tampered: dropped one endpoint: FAIL (1 problem(s))
- missing endpoints: ['/amazon-bestsellers']
tampered: asin marked optional on lookup: FAIL (1 problem(s))
- /amazon-product-lookup: required params ['marketplaceId'] != catalogue ['asin', 'marketplaceId']
tampered: api_key reintroduced as a query parameter: FAIL (2 problem(s))
- /amazon-product-offers: api_key listed as a query parameter, should be a security scheme only
- /amazon-product-offers: required params ['api_key', 'asin', 'marketplaceId'] != catalogue ['asin', 'marketplaceId']

Can I generate a typed client from this spec?
That is the point of shipping a standard OpenAPI document instead of a Postman-only file: feed openapi.json to openapi-generator-cli generate -i openapi.json -g python -o client/ (or -g typescript-fetch, -g go, any of its ~60 generators) or to openapi-python-client generate --path openapi.json to get typed request functions for every one of the 10 endpoints without hand-writing them. Neither generator was installed in the sandbox this post was built in, so these commands are given as documented CLI usage, not run here, the same honesty rule as the ci.sh newman script in the Postman-collection post: nothing is shown as output unless it was actually captured.
Frequently Asked Questions
Is this spec published by SellerMagnet itself?
No. SellerMagnet does not publish an OpenAPI document; this spec was built from the API's own documented endpoints, parameters and response shapes for this post, and should be regenerated if an endpoint's parameters change.
Does the spec validate live API responses?
No. The validator checks the spec document's own structure (endpoints present, required flags correct, auth modelled correctly), not a live HTTP response. Response-shape checks against real, documented field values live in the quickstart and Postman-collection posts instead.
Why is api_key not listed as a parameter on each endpoint?
Because the API accepts it as either the X-Api-Key header or an api_key query parameter, which OpenAPI models as security schemes, not as a regular parameter, so client generators produce an auth option instead of a plain string field named api_key.
Why do nested response fields just say "object" past two levels?
Reproducing the full nested shape for all 10 endpoints runs the spec past 46 KB, almost all of it duplicating fields already documented endpoint-by-endpoint in the quickstart and Postman-collection posts. A client generator only needs the top-level shape to produce a working method signature.
How do I turn this into client code?
Run openapi-generator-cli generate -i openapi.json -g <language> -o client/, or openapi-python-client generate --path openapi.json for a typed Python client. Both read the spec directly; no further editing is required.
What exactly did the three tampering scenarios prove?
That the validator is not a rubber stamp: dropping an endpoint, demoting a required parameter to optional, and reintroducing api_key as a query parameter each triggered a distinct, correctly worded failure instead of a silent PASS.
Bottom line: a real OpenAPI 3.0.3 document for all 10 SellerMagnet Amazon API endpoints, with the correct dual auth modelled as security schemes, and a dependency-free validator that proves itself by failing on three separately injected spec bugs. For calling the API directly instead of generating a client, the Python and Go quickstarts and the Postman collection cover the same 10 endpoints; the API documentation is the live reference if a parameter ever changes, and a free account includes 150 credits to try any of them.