Error codes
listingsAPI error codes (SYxxxxx) and the two error-envelope shapes the v4 API returns.
Error codes are SY-prefixed and travel inside the error message string,
formatted as SYxxxxx: <human-readable reason>.
Two envelope shapes
Where the errors array lives depends on whether the request failed before or
after it reached the resolver.
1. Top-level errors[]
Request-level failures — authentication, authorization, and malformed
requests — short-circuit before the operation runs. The error appears at the
top level of the response, alongside a null data.<operation>.
{
"data": { "createLocation": null },
"errors": [{ "message": "SY90005: Invalid Token" }]
}
2. Nested data.<operation>.errors[]
Business-validation failures happen inside the resolver, so the request is
otherwise valid. The error appears nested under the operation's own payload
in data.<operation>.errors. On success this array is present and empty
("errors": []).
{
"data": {
"createLocation": {
"errors": [
{ "message": "SY10126: City is Mandatory" },
{ "message": "SY10010: state_iso" }
],
"location": null
}
}
}
Always read data.<operation>.errors even on a 200 with a populated
data.<operation> object — a mutation can partially fail and report it here.
Common codes
| Code | Message | Envelope | Meaning |
|---|---|---|---|
SY90005 | Invalid Token | Top-level errors[] | The API key is missing, malformed, or revoked. Re-issue a key from the dashboard and send it as Authorization: API <your-key>. |
SY90001 | Not authorized to access this resource | Top-level errors[] | The key is valid but lacks access to the requested resource. |
SY90002 | Invalid Id | Top-level errors[] | A path or argument ID could not be resolved (often a bad or non-base64 relay ID). |
SY10126 | City is Mandatory | Nested data.<op>.errors[] | A required field (city) was omitted from the input. |
SY10010 | state_iso | Nested data.<op>.errors[] | The stateIso value is missing or invalid. See the countries and states endpoint for valid values. |
Validation codes in the SY10xxx range correspond to a specific input field;
the message names the field or the rule that failed. Auth and authorization
codes in the SY90xxx range are request-level and always arrive at the top
level.
Handling errors in code
A single check works for both shapes — look for a top-level errors array,
then for a nested one on the operation you called:
resp = client._request(method="POST", path="/api/v4/locations", body=payload)
top_level = resp.get("errors") or []
data = resp.get("data") or {}
op = data.get("createLocation") or {}
nested = op.get("errors") or []
if top_level or nested:
messages = [e["message"] for e in [*top_level, *nested]]
raise RuntimeError(f"listingsAPI error: {messages}")