Responses and errors
Every field of an answer, the error envelope with its types, and the headers on every response.
A successful answer
A check answers 200 with this JSON. Every plan gets every field.
| Field | Type | Description |
|---|---|---|
status | string | Always success. |
workflow | string | The workflow the content was checked against. |
workflow_version | integer | The version of the workflow that decided. |
summary.action | string | reject when a reject threshold is reached, else review when a review threshold is, else accept. |
summary.reject_prob | number | The highest score among the rejected categories, 0 when none is. |
summary.reject_reason | array | Why the content is rejected, highest score first. |
summary.review_reason | array | Why the content goes to review, highest score first. |
scores | object | The best score per category the workflow checks, from 0 to 1. |
unchecked | array | The categories of the workflow this server could not check. Absent when every one was checked. |
time_ms | integer | The time spent checking, in milliseconds. |
request_id | string | The id of this request, also in X-Request-Id and in the journal. |
ref | string or null | Your own id for the content, as you sent it. |
A reason in reject_reason or review_reason has:
| Field | Description |
|---|---|
id | The category id, such as nudity or pii_iban. It is stable: map it to your own messages. |
text | A short English title. |
message | A full English sentence that can be shown to a user. |
score | The score the category got. |
threshold | The threshold it reached. |
source | The tool that produced the score. |
Match on
id, never on text or message. They are English defaults and may be reworded.Errors
An error answers with the HTTP status and this envelope:
{
"status": "failure",
"error": {
"type": "unsupported_media",
"code": 415,
"message": "The file is not a JPEG, PNG, WebP or GIF image."
}
}
Switch on error.type: it is stable. error.code repeats the HTTP status, and error.message is English text for you, not for your users.
error.type | Status | When |
|---|---|---|
unauthorized | 401 | The key is missing, malformed, invalid, revoked or expired. |
forbidden | 403 | The key may not check this kind of content or use this workflow, or the request came from a browser. |
organization_suspended | 403 | An operator suspended the organization. Write to contact@sway.events. |
bad_request | 400 | An empty body, a text that is not JSON or has no text, a refused ref, or a form that lacks a field. |
unknown_workflow | 400 | There is no workflow of that name. |
corrupt_media | 400 | The file does not decode. |
url_refused | 400 | The url of an image is not public, too large, too slow or not an image. |
unsupported_media | 415 | Not a JPEG, PNG, WebP or GIF image, or a text sent without Content-Type: application/json. |
body_too_large | 413 | A request body over 15 MB. |
image_too_large | 413 | More than 50 megapixels (12 on the free plan), or a side over 16,384 pixels. |
text_too_long | 413 | More than 20,000 characters (5,000 on the free plan). |
rate_limited | 429 | Too many requests: wait Retry-After seconds. |
too_many_concurrent | 429 | Too many checks at once: wait Retry-After seconds. |
quota_exceeded | 429 | The free plan's included checks are used, or the spending cap is reached. See limits and quotas. |
request_timeout | 408 | A SightEngine-compatible form took more than 10 seconds to arrive. |
workflow_unavailable | 503 | The workflow has no rule for this kind of content, or none this server can check. |
busy | 503 | The server is busy, or the share of it the free plans use is: retry after Retry-After. |
internal | 500 | A bug on our side. Quote the request_id when you write to us. |
What to do with an error
- 400, 413, 415: the request is wrong or the content cannot be accepted. Do not retry; refuse the content or fix the call.
- 401, 403: a configuration problem. Log it, without the key, and alert your team.
- 408: send the form again once, from a faster connection if you can.
- 429, 503 with
Retry-After: wait that many seconds, and retry at most twice. - 500, a timeout or a network error: fail closed, as best practices explains.
Headers on every response
| Header | Description |
|---|---|
X-Request-Id | The id of the request. Quote it in a support message. |
RateLimit-Limit | The burst size of your plan: how many requests the bucket holds. |
RateLimit-Remaining | How many requests are left in the bucket. |
RateLimit-Reset | Seconds until the bucket is full again. |
X-Quota-Used | Checks counted in the current period. |
X-Quota-Limit | Checks the period allows before quota_exceeded. |
Retry-After | Seconds to wait, on 429 and 503. |