Errors
Errors return JSON with an error message. Where a client can reasonably do
something different depending on why a call failed, the body also carries a
machine-readable code — match on that, never on the message text.
Status codes
| Status | Meaning | What to do |
|---|---|---|
400 | Malformed YAML or XML | Fix the input; the body says what failed |
401 | No credential, or an unrecognised one | Send Authorization: Bearer stfv_… |
403 | Key recognised but expired | Rotate and extend — see below |
415 | Unsupported Content-Type | Send text/yaml (or application/xml for reverse) |
422 | Engine could not process a well-formed request | Usually a model the compiler rejects |
429 | Rate limited | Wait Retry-After seconds |
500 | Server fault | Retry; if it persists, tell us |
503 | Auth backend unavailable | Retry — your key is fine |
401 — authentication required
{
"error": "Authentication required. Provide a valid API key.",
"code": "auth_required",
"hint": "Include header: Authorization: Bearer stfv_YOUR_KEY",
"docs": "/api-docs.html"
}
On endpoints the web editor also uses, the same code comes with a sign-in URL
instead of a key hint, so a browser client can render the right affordance.
403 — key_expired
The key exists and belongs to you; it has passed its 30-day window.
{
"code": "key_expired",
"error": "API key expired on 2026-03-01T09:00:00.000Z.",
"hint": "Rotate your key at https://opcua-modeler.sterfive.io/app/settings/api"
}
Distinct from 401 on purpose: the fix is a rotation, not a signup. See
Authentication and API keys.
429 — rate limited
Carries Retry-After and the X-RateLimit-* headers. Two different limits can
produce it — the 30/minute burst limit or a daily quota — and the headers tell
you which. See Quotas and rate limits.
503 — not your fault
{ "error": "Authentication service temporarily unavailable. Please retry." }
Returned when the authentication backend cannot be reached. It is deliberately
not reported as a 401: masking an outage as a credential problem sends you
off regenerating a key that was never the issue. Retry with backoff.
Validation results are not errors
A model with problems still returns 200. The response reports
valid: false with diagnostics — severity, code, message and line number. Reserve
your error handling for the statuses above, and read valid for the modelling
verdict.
curl -X POST https://api.opcua-modeler.sterfive.io/api/v1/validate \
-H "Content-Type: text/yaml" \
--data-binary @model.yaml
Diagnostic codes themselves are documented with the DSL — start at Conformance flags, which covers how severities are assigned and how to silence individual codes.