Skip to main content

Errors

Public API errors use application/problem+json and the RFC 9457 Problem shape:

{
"type": "urn:phishinghermes:problem:unsupported_media_type",
"title": "Unsupported media type",
"status": 415,
"detail": "Content-Type must be message/rfc822.",
"instance": "urn:phishinghermes:request:req_synthetic_0001",
"code": "unsupported_media_type",
"request_id": "req_synthetic_0001"
}

Every public response carries Cache-Control: no-store and X-Request-ID. The body request_id matches the header. A Problem can include errors only for safe field-level validation details.

The read-only API Reference contains a complete, schema-valid, sanitized RFC 9457 example for every public code listed below.

Complete catalog​

StatusPublic codes and common causesRetry?Idempotency keyRecommended action
400invalid_request, invalid_content_length, idempotency_key_required, invalid_idempotency_key: malformed framing, length, or operation keyNoKeep it while diagnosingCorrect the request before sending it again
401invalid_credentials: missing or non-authenticating credential; deliberately genericNoUnchangedCorrect or rotate the credential; do not probe credential states
403insufficient_capability, credential_environment_mismatch, credential_not_customer_bound, service_not_enabled, entitlement_required: authenticated scope is not authorizedNoUnchangedUse the credential issued for this customer/environment or contact Hermes
404operation_not_found: unknown public path, including a non-canonical trailing-slash pathNoUnchangedUse exactly /v1/email-analyses
405method_not_allowed: a method other than POST was usedNoUnchangedUse POST; the response also sends Allow: POST
408request_body_timeout: the complete body did not arrive before the body-read deadlineYes, boundedSame key and bytesCheck upload/network behavior, then retry with backoff
409idempotency_conflict: the same key was already used with different bytesNoRecover original bytes; otherwise new key only for a genuinely new operationNever bypass the conflict automatically
413payload_too_large: body exceeds 10 MiBNoUnchangedDo not truncate evidence silently; use an approved alternative workflow
415unsupported_media_type, unsupported_content_encoding: body is not raw message/rfc822 or is compressedNoUnchangedCorrect headers and send the original bytes
422unusable_email, email_too_complex: empty/NUL/headerless/bodyless or over structural limitsNoUnchangedRe-export the source or use an approved alternative workflow
429rate_limit_exceeded, usage_quota_exceeded, usage_quota_temporarily_reserved, analysis_concurrency_limitedYes, boundedSame key and bytesHonor Retry-After when present, add jitter, reduce concurrency
500internal_error: unexpected failure before a safe public resultYes, boundedSame key and bytesBack off; do not assume retry will resolve it
503Temporary authentication/rate/processing/persistence/accounting unavailability, timeout, still-processing idempotency, or uncertain outcomeYes, boundedSame key and bytesHonor Retry-After when present; never create a new key to bypass uncertainty

Public 503 codes are:

authentication_unavailable
rate_limit_unavailable
service_deadline_exceeded
email_parsing_unavailable
email_parsing_timeout
idempotency_unavailable
idempotency_in_progress
analysis_outcome_unknown
analysis_timeout
analysis_unavailable
idempotency_ownership_lost
analysis_persistence_unavailable
analysis_tenant_binding_failed
usage_accounting_unavailable

idempotency_in_progress and analysis_outcome_unknown require special care: retry the original operation with the same key and byte buffer. Do not generate another key. Hermes sends Retry-After where the specific path can calculate a useful interval; the header is not guaranteed for every 429 or 503.

The facade does not return 402.

Safe error handling​

content_type = response.headers.get("content-type", "")
if response.status_code >= 400:
if "application/problem+json" not in content_type:
response.raise_for_status()
problem = response.json()
raise RuntimeError(
f"Hermes {problem['status']}: {problem['code']} "
f"(request_id={problem['request_id']})"
)

Log only stable status, code, request ID, and approximate UTC time. Never log the API key, EML, attachments, or sensitive headers.

When to contact support​

Stop bounded retries and contact info@phishinghermes.com when a retryable failure persists, an uncertain outcome remains unresolved, or a permanent response is unclear. Provide the latest request_id, status, code, UTC time, client/library version, and whether every retry used the same key and bytes.