Error format
Every 4xx and 5xx response has one shape. Branch on the code, show the message, log the request id.
Every error, an unknown path and a body that is not JSON included, returns the same envelope:
{
"error": {
"code": "not_ready",
"message": "Add the missing items, then launch again. Nothing was spent.",
"errors": [
{
"param": "contact_email",
"code": "required",
"message": "Add a contact email. Some directories register the listing to it."
}
],
"doc_url": "https://submitator.com/docs/errors#not_ready",
"request_id": "6b0f2c9e-6a41-4c55-9d2a-0f0d3c1a8e77"
}
}Fields
| Field | Always there | What it holds |
|---|---|---|
code | Yes | The stable code. Branch on it; Error codes lists all 32. |
message | Yes | A sentence for people that says what happened and what to do. It can change, so never parse it. |
doc_url | Yes | The section of the error codes page for this code. |
request_id | Yes | The request's id, the same as the X-Request-Id header. Quote it when you write to support. |
param | No | The parameter at fault, when there is one. |
errors | No | Every field to fix, on validation_failed, not_ready and invalid_directories. |
existing | No | The project in the way, on project_exists and already_launched. |
Field errors
Each item of errors names one field in param, as a path such as tagline, competitors[2].url or directories.include[0]. Its code comes from this closed list:
| Code | Meaning |
|---|---|
required | The field is missing or empty. |
invalid | The value is not allowed here; message says why. |
invalid_enum | The value is not one of the listed values. |
invalid_url | Not an http or https URL. |
not_public_url | Live mode only: the host is an IP address or a reserved name such as .test. |
invalid_email | Not an email address. |
too_short | Shorter than the minimum length. |
too_long | Longer than the maximum length. |
too_many | The list has more items than allowed. |
immutable | The field cannot change any more, such as contact_email after launch. |
file_too_large | The image is larger than 5 MB. |
unsupported_file_type | The file is not a PNG, JPEG, GIF or WebP image. |
import_failed | We could not download an image from the URL. |
Handle errors in your code
- 4xx: the request was wrong. Fix it before you send it again; a retry with the same body gets the same answer.
- 409
idempotency_key_in_use: the first request with thisIdempotency-Keyis still running. Retry in 1 second with the same key. - 429: wait the seconds in
Retry-After, then send the same request again. - 500 and 503: retry with backoff, for example after 1, 2, 4 and 8 seconds. Send a
POSTagain with the sameIdempotency-Key, so it runs at most once. If it repeats, write to support with therequest_id.
Show message to the person who can fix the problem, and keep code and request_id in your logs. A failed launch spends nothing, and its message says so.
HTTP statuses
| Status | Codes |
|---|---|
| 400 | invalid_json, invalid_query, unknown_parameter, invalid_cursor |
| 401 | api_key_missing, api_key_invalid |
| 402 | no_launches_left |
| 403 | account_suspended, permission_denied, test_mode_only |
| 404 | not_found, route_not_found |
| 405 | method_not_allowed |
| 409 | already_launched, project_exists, idempotency_key_in_use |
| 410 | gone, cursor_expired |
| 415 | unsupported_media_type |
| 422 | validation_failed, not_ready, nothing_to_submit, invalid_directories, allowance_exhausted, badge_not_found, image_unreachable, endpoint_url_invalid, idempotency_key_reused, quota_exceeded |
| 429 | rate_limited |
| 500 | internal_error |
| 503 | unavailable |