Errors
The structure of an error response from the Seamless OS API, and what each status code means.
The Seamless OS API answers with a standard HTTP status code and a structured error body. The body names the fault in a form that a person can read and in a form that your code can match on.
Error response structure
Every error response has the same structure:
{
"message": "Validation failed",
"reason": "order_invalid_input",
"domain": "order",
"retryable": false,
"internalCode": "4240",
"code": "invalid_input",
"details": [
{
"message": "email is required",
"reason": "property_required",
"code": "invalid_argument",
"property": "contact.email"
},
{
"message": "msisdn is not a phone number",
"reason": "property_invalid",
"code": "invalid_argument",
"property": "subscriber.msisdn"
}
],
"hint": "Correct the fields that the details name, then send the request again.",
"traceId": "cc4a73acca1bb07e0e54bd41f5ce1e7e",
"spanId": "37cec694d3b99f0f"
}Error fields
message (required): A description of the fault for a developer to read in a log or in a
console.
reason: A name in lower snake_case for the condition that failed, such as
customer_not_found. The same condition always carries the same reason. It is independent of the
HTTP status and of which system reported the fault, and it is stable across releases. Branch on
this field.
domain: The business area of the reason, such as customer or porting. It is for
information only. Do not branch on it.
retryable: True when the same request can pass later with no change. A 429 and
a 503 always have retryable set to true.
externalCode and externalSource: The code that a third party sent for the fault, and
the name of that third party. A network operator is an example of a third party. These fields are
only present when a third party reported the fault.
internalCode: A string of digits for the condition that failed. It is stable across
releases. A condition that we added after reason has no internalCode, so branch on reason
instead.
code (required, deprecated): Use reason instead. This field mixes three unrelated codes,
and it does not say which one you have. The three are a code that we publish, an operator’s own
code, and the request status.
details: A list of the individual faults. Each entry carries these fields:
message: A description of the one fault for a person to read.reason: The name of the one fault. The section “Validation reasons” gives the general ones.code(deprecated): The request status of the whole error, such asinvalid_argument. Usereasoninstead.property: The field or the parameter that caused the fault. A nested field uses dot notation, such asbilling.email.suggestion: A correct value, when the API can propose one.
hint: One more sentence about how to correct the request.
traceId and spanId: The trace that your request produced, and the span inside it that
failed. Quote the trace identifier when you report a fault to us. It is what lets us find your
request among everything else the platform served.
Branch on the reason
Match your code on reason. Obey these rules:
- Accept a reason that you do not know. We add new reasons without notice. Use the HTTP status for a reason that you do not know.
- Do not branch on
domain. A reason can move to a different domain. - Do not parse
messageorhint. Their words can change in each release.
If retryable is true, you can send the same request again later. If the response has a
Retry-After header, wait for that number of seconds first.
Validation reasons
A validation problem in details, and an item of the validation of an order, carry a
reason. A problem that is not a business condition has one of these general reasons:
| Reason | The problem |
|---|---|
property_required | A value is missing. |
property_invalid | A value has the wrong format, or is not permitted. |
property_conflict | Two values cannot occur together. |
A problem that is a business condition has the reason of that condition, such as
activation_date_in_past.
HTTP status codes
The status code gives the category of the fault. If an error names no condition of its own, its
reason comes from the status:
| Status Code | Reason | Description |
|---|---|---|
400 | bad_request | Bad Request - Invalid request syntax, or a validation fault |
401 | unauthorized | Unauthorized - The authentication credentials are absent or invalid |
403 | forbidden | Forbidden - The credentials are valid, but the permissions are not sufficient |
404 | not_found | Not Found - The requested resource does not exist |
409 | conflict | Conflict - The request conflicts with the current state, such as a reused idempotency key with different data |
412 | precondition_failed | Precondition Failed - The resource is not in a state that allows this request |
429 | rate_limit_exceeded | Too Many Requests - You reached the rate limit |
500 | internal_error | Internal Server Error - An unexpected fault on our side |
501 | not_implemented | Not Implemented - The endpoint is not available for your brand |
503 | service_unavailable | Service Unavailable - A system that we depend on did not answer. Send the request again |