Skip to main content

Error Codes

Every 4xx and 5xx response from the Media Agency API carries the canonical JSON envelope with a stable machine-readable code. Clients should branch on error.code (not on the English error.message or the raw HTTP status).

Envelope shape

{
"error": {
"code": "listing_not_found",
"message": "No listing matches that identifier.",
"request_id": "req_01HX5Y7Z2M3N4P5Q6R7S8T9U0V",
"details": {
"listing_number": "ABC123"
}
}
}
  • code - short snake_case identifier; switch on this.
  • message - human-readable one-liner; safe to surface to end users.
  • request_id - mirrors the X-Request-Id response header; include it in every support ticket.
  • details - optional structured context; empty object when not populated.

Codes

Authentication

CodeHTTPSummaryRemediation
api_key_missing401No X-API-Key header on the request.Send X-API-Key: sk_live_<token> (or sk_test_<token> for sandbox). Format is documented at https://docs.valara.cloud/api-reference/authentication.
api_key_invalid401API key not recognised, revoked, or past expiry.Rotate from Settings > API Keys. Deleted keys cannot be recovered; mint a fresh key and update your secrets store.
auth.scope_denied403Key authenticated but lacks the scope for this endpoint.Mint a new key with the required scope, or contact support if your plan does not include the requested surface.
auth_required401Endpoint accepts either an API key or a dashboard session cookie; neither was presented.Send X-API-Key: sk_live_<token> for programmatic calls, or sign in at https://valara.cloud/login for the dashboard UI path. See https://docs.valara.cloud/api-reference/authentication.
role_forbidden403Caller is authenticated but their role is not permitted on this endpoint (e.g. a viewer trying to upload media).Contact the media agency owner to elevate the role, or call the endpoint with an API key that belongs to a permitted role.
agency_resolution_failed500Caller's session is valid but the server could not resolve the user to a media_agency. Indicates a data integrity issue.File a support ticket quoting the request_id; the agency membership record needs operator repair.
api_key_header_mismatch401Caller sent Authorization: Bearer instead of X-API-Key.Resend the same token under X-API-Key: sk_live_<token>. The Media Agency API uses a custom header, not Bearer auth.
api_key_malformed_prefix401API key prefix is not sk_live_, sk_test_, or ma_live_.Re-copy the full key from Settings > Developer. Check error.details.detected_prefix for what the server parsed.
api_key_malformed_length401Prefix OK but total key length is outside allowed bounds.The key looks truncated. Re-copy it from Settings > Developer and ensure no whitespace was lost.
api_key_revoked401Key was revoked. Fires only on prove-of-presentation match.This key cannot be reactivated. Mint a new key at Settings > Developer and update your secrets store.
api_key_expired401Key is past its expires_at date.Mint a fresh key at Settings > Developer. Expiry timestamp is echoed in error.details.expired_at.
api_key_disabled401Key exists but is_active=false (administratively disabled).Re-enable the key at Settings > Developer or contact the agency owner. Disabled keys can be re-enabled without rotation.
api_key_wrong_mode401Sandbox key used on live endpoint, or live key on sandbox.Use sk_test_<token> for sandbox calls and sk_live_<token> for live traffic. Modes are strictly enforced.
cross_agency404Key authenticated but requested resource belongs to another agency.Returned as 404 (not 403) to prevent cross-agency existence probing. Confirm the key's agency owns the resource.

Idempotency

CodeHTTPSummaryRemediation
idempotency.missing400Mutating request without X-Idempotency-Key header.Add X-Idempotency-Key: <UUIDv4 or ULID> to every POST and PATCH. Keys are scoped per-agency for 24 hours.
idempotency_key_conflict409Same key reused with a different body within 24h.Use a fresh key for the new body, or replay the exact original body to get the cached response back.
idempotency_key_in_progress409Replay while the first call with this key is still in flight.Wait for the first request to complete, then retry. The server serializes in-flight replays to avoid double-writes.

Listing Lifecycle

CodeHTTPSummaryRemediation
listing_not_found404No listing matches that identifier (also used for cross-agency reads).Verify the listing_number and confirm the API key belongs to the owning agency. Cross-agency reads always return 404.
endpoint_not_in_scope404URL under /api/v1/listings/ that does not match a public endpoint.Consult https://docs.valara.cloud/api-reference/endpoints for the 13 supported routes.
listing_not_activated409Status transition attempted before activation / credit capture.Complete activation in the dashboard at /property/{listing_number}/edit before retrying the status PATCH.
no_op_transition409new_status equals the current status; no change was performed.Read the current status via GET /listings/{listing_number} before PATCHing. Duplicated transitions are refused loudly.
outside_cancellation_window409Cancel attempted past the no-fee cutoff window.Route the cancellation through the dashboard so a human reviewer can decide whether to waive the fee.
listing_already_cancelled409Cancel attempted on a listing already in the cancelled state.Second cancels are rejected to prevent duplicate webhook emission. Read the current status before retrying.
section_not_exposed404PATCH targeted a section not exposed via the public API.Only matterport and floorplan sections are mutable via the public API in v1. Other sections must go through the UI.
invalid_section_payload422Section payload parsed but failed a higher-level semantic rule.Inspect error.details for the offending field and reason. Common cause: operation='set' without a url field.
listing_number_taken409Create-listing attempted with a listing_number that already exists under the caller's agency.Omit listing_number from the request body so the server mints a fresh one, or pick a different value matching [a-z0-9]{7}.
agent_not_in_hierarchy422owner_user_id / agent_one_id / agent_two_id references a user that does not belong to the calling agency's hierarchy.Confirm the user_id via GET /api/v1/users and verify the user rolls up to the caller's media_agency. Cross-agency agent assignments are rejected.

Media

CodeHTTPSummaryRemediation
unsupported_mime_type422Uploaded content_type is not in the allowlist for this asset_type (e.g. image/webp for asset_type=video).Pick a content_type from the asset-type-specific allowlist. Photos accept image/jpeg
file_too_large422Declared size_bytes exceeds the asset-type's cap. The presigned URL would have been rejected at the bucket layer.Check the per-asset-type size cap on the endpoint reference page, compress / transcode the asset, then retry with the new size_bytes value.
celery_unavailable503The background delivery queue is temporarily unavailable so the upload pre-signer cannot hand off the post-upload task.Retry after the Retry-After interval. If the error persists for more than 15 minutes, file a support ticket.

Scheduling

CodeHTTPSummaryRemediation
calendar_not_connected403The agency has not connected a Google Calendar, so the availability endpoint has no source to read slots from.Connect Google Calendar at /settings/integrations in the dashboard. The connection token is resolved up the manager chain, so any agency ancestor's connection also works.

Users

CodeHTTPSummaryRemediation
user_not_found404No user with that id (also used for cross-agency reads).Verify the user_id and confirm the API key's agency owns that user. Cross-agency reads always return 404.

Rate Limiting

CodeHTTPSummaryRemediation
rate_limit_exceeded429Per-key request budget exhausted for the current window.Honour the Retry-After header with exponential jitter. See https://docs.valara.cloud/api-reference/rate-limits for per-endpoint budgets.
rate_limit_misconfigured500The rate-limit middleware could not resolve the caller's identity or the endpoint's budget (internal config error).File a support ticket quoting the request_id. Retries will keep hitting the same wall until an operator corrects the rate-limit configuration.
rate_limit_unavailable503The rate-limit backend (Redis) is temporarily unreachable so the middleware fails closed instead of serving unmetered traffic.Retry after a few seconds. If the error persists for more than 5 minutes, the platform is in a degraded state; check https://status.valara.cloud.

Validation

CodeHTTPSummaryRemediation
validation.failed422Request body failed Pydantic schema validation.Consult error.details.fields for the per-field failure reasons and correct the payload before retrying.
validation_type_mismatch422Field value has the wrong JSON type.Consult error.details.errors[].field for the path and coerce the value to the expected type before retrying.
validation_missing_required422A required field is absent from the request body.Include every field flagged in error.details.errors[]. See the endpoint schema in the OpenAPI docs.
validation_unknown_field422Field sent that is not declared on the schema (extra=forbid).Remove the offending field, or consult did_you_mean[] for the likely intended field name.
validation_deprecated_field422Field matches a registered rename (e.g. old_name -> new_name).Migrate to the new field name in error.details.errors[].migration.to. See the linked migration guide for payload examples.
validation_out_of_range422Numeric value outside the schema's allowed bounds.Inspect error.details.errors[].ctx for the bound violated and clamp the value before retrying.
validation_enum_not_allowed422String value is not in the schema's allowed enum values.Use one of the values in error.details.errors[].ctx.expected. Enum values are case-sensitive.
validation_string_pattern422String failed a format constraint (regex, uuid, email, url, date).Validate against the documented format. Check error.details.errors[].ctx.pattern for the regex if declared.
validation_array_length422List is too short or too long for the schema.Trim or pad per the bounds in error.details.errors[].ctx. Empty optional lists should be omitted, not sent as [].
validation_nested_error422Wrapper code when a nested object has its own error list.Drill into error.details.errors[].children[] for per-field reasons. Child entries carry their own codes.

Placeholders

CodeHTTPSummaryRemediation
not_implemented501Endpoint reserved for a future wave; URL is live but body is not.Check the changelog at https://docs.valara.cloud/api-reference/changelog for the planned ship date of the section referenced in details.

Server

CodeHTTPSummaryRemediation
internal_error500Unexpected server error. Includes request_id for support escalation.Safe to retry with the SAME X-Idempotency-Key. If the error persists, file a support ticket quoting the request_id.

Wire

CodeHTTPSummaryRemediation
request_body_not_json400Content-Type is application/json but body does not parse.Fix the JSON syntax. error.details.parse_error_position gives the approximate byte offset of the first parse failure.
request_body_empty400Required request body is missing on a POST or PATCH.Send a JSON object even when every field is optional. Empty bodies are rejected at the wire layer for safety.
request_body_too_large413Request body exceeds the per-endpoint size limit.Split the payload. Media uploads use the dedicated multipart endpoints; large batches use streaming.
request_content_type_mismatch415Content-Type header does not match what the endpoint accepts.Send Content-Type: application/json for body endpoints. Multipart endpoints document the type in OpenAPI.
request_method_not_allowed405Path exists but the HTTP method is not supported.Use one of the methods in error.details.methods_allowed (also echoed in the Allow response header).
request_path_not_found404URL does not match any public API endpoint.Consult https://docs.valara.cloud/api-reference/endpoints for the complete route catalog.
request_query_invalid422Query-parameter validation failed.Same shape as body validation: inspect error.details.errors[] for per-parameter reasons. Query keys are case-sensitive.

Security non-negotiable: 404 hides 403

Cross-agency reads always return 404 listing_not_found or 404 user_not_found, never 403. Returning 403 would confirm that a given id belongs to a different agency, enabling id enumeration across the tenant boundary. This is deliberate; do not report it as a bug.