Scam AI raised $2.6M to combat AI-powered scams→
scam.ai

~/docs cat errors.md

Errors

Errors are conventional HTTP, and they are never dressed up as a verdict: a caller out of credits sees a 402, not a reassuring answer. Every error body carries a stable code to branch on and a message written for people, which may change. A 429 from the rate limiter is the one body without success: false: it is {error, message}, or plain text from the per-tier limiter.

Error codes
StatusCodeMeaning and fix
400NO_FILE_UPLOADEDNeither file nor url was sent. Attach one as file, or send url.
400INVALID_URLurl is not an http or https link.
401UNAUTHORIZEDThe x-api-key header is missing or the key is not recognised.
402INSUFFICIENT_CREDITSOut of credits. Top up in the dashboard, then retry.
403API_KEY_SCOPEThe key is scoped to another service. Use a universal key.
403FORBIDDENThe account's email is not verified yet; the message begins EMAIL_VERIFICATION_REQUIRED. Verify it in the dashboard.
404NOT_FOUNDNo stored detection with that id for this account. Runs sent with save=false are not stored.
413FILE_TOO_LARGEThe file is over the cap for its media type. The message names the cap.
413LINK_MEDIA_TOO_LARGEThe video behind the link is over 100 MB.
422UNSUPPORTED_MEDIA_TYPENot a file a detector can read: a text file, an archive, an unknown format.
422UNDECODABLE_IMAGEAn empty file, or bytes that decode to nothing.
422LINK_NOT_RESOLVABLEThe url does not resolve to a video page or a media file the server can fetch: a web page, a private or deleted video, a playlist, a live stream, a video over 5 minutes. The code arrives as a string in error, with retryable and the resolver's resolverCode beside it. Answered as 502 when the resolver itself failed.
422NOT_ASSESSABLEThe platform looked and could not judge. Today an audio outcome: reasons[] carries no_voice_content (no speech in any window) or audio_too_short (shorter than the analyzer accepts). Every decodable image and video frame is scored, face or not. Show the reasons; do not retry the same file. Nothing is charged.
429Too many requests this minute. Back off; honour Retry-After.
429DAILY_LIMITThe account's daily usage ceiling is reached. Refused before the run starts; see Credits and limits.
429MONTHLY_LIMITThe account's monthly usage ceiling is reached. Refused before the run starts.
500DETECTORS_UNAVAILABLENo detector could take the run. Retry with backoff, then contact support.
500INTERNAL_ERRORAn unexpected gateway failure. Retry with backoff, then contact support.
501LINK_RESOLUTION_UNAVAILABLEThis deployment cannot fetch links. Upload the file instead.
502DETECTION_NOT_BILLABLEThe run could not be metered and was not charged. Resubmit only if you still need the answer.
502LINK_RESOLUTION_FAILEDThe resolver could not fetch the media behind the link. Retry once; then upload the file.
503BILLING_UNAVAILABLEThe usage gate could not be read, or the debit did not land after the run. Nothing is charged or stored and the verdict is withheld. A retry is an ordinary charged run.
504DETECTION_PLATFORM_TIMEOUTThe platform did not answer in time. The run may still have completed; check history before re-sending.
504DETECTION_PLATFORM_UNREACHABLEThe platform could not be reached. Retry with backoff.
504LINK_RESOLUTION_TIMEOUTThe link took too long to fetch. Retryable.
504LINK_RESOLUTION_UNAVAILABLEThe resolver could not be reached. Retryable; the same code as 501 means the deployment has no resolver at all.

A 422 with reasons[] is an answer, not an outage. Its body looks like this:

response · 422
{
  "success": false,
  "error": {
    "code": "NOT_ASSESSABLE",
    "message": "no detector could score this media"
  },
  "reasons": ["no_voice_content"],
  "request_id": "6f1c2a3e-9b7d-4e5f-8a21-3c4d5e6f7a8b"
}

Route and platform refusals carry the code as error.code with the message beside it, as above. Link refusals (INVALID_URL, LINK_*) and the key-scope refusal (API_KEY_SCOPE) carry the code as error directly, a string, with message next to it; link refusals also carry retryable and the resolver's own resolverCode. Errors answered by the gateway's central handler (401, 403 FORBIDDEN) also carry timestamp and path; refusals the route answers itself do not. Neither is part of the contract; error.code is. The SDKs fold every shape into one exception. Keep the id from every response, or the request_id when an error carries one (platform refusals, 502, 503), when you write to support@scam.ai.