Reliability

Errors

Dishora uses conventional HTTP status codes and a consistent JSON error envelope. Validation errors return 422 with a per-field breakdown so you can surface them in your UI.

Status codes

200Success. The request completed.
201Created. A resource was stored (e.g., a substitution).
202Accepted. A background job was queued (weekly discovery).
204Success with no content (delete).
400Bad request. Malformed payload.
401Unauthenticated. Missing or invalid key.
402Payment required. Sandbox trial allowance used up.
403Forbidden. Key lacks scope for this action.
404Resource not found.
409Conflict. The job is already running.
413Payload too large.
422Validation error. See per-field errors.
429Rate limited. Retry after Retry-After.
500Server error. Safe to retry.

Error shapes

The envelope depends on where the request failed. Validation failures on the REST API return Laravel's structured errors object keyed by field, so client-side mapping is trivial:

422 validation (REST API)
{
  "message": "The servings must be between 1 and 20. (and 1 more error)",
  "errors": {
    "servings": ["The servings must be between 1 and 20."],
    "instruction_style": ["The selected instruction style is invalid."]
  }
}

A missing resource returns a plain error string:

404
{
  "error": "Recipe not found."
}

Rate-limit error (429)

429
// 429 Too Many Requests: back off using Retry-After
HTTP/1.1 429 Too Many Requests
Retry-After: 12
Content-Type: application/json

{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded. Retry after 12 seconds.",
    "retry_after": 12
  }
}

Retries and caching

Recipe generation is not idempotent: each fresh call may produce a new recipe. Identical requests for a specific named dish are served from the tiered cache, which makes retries of the same request cheap and consistent. For 429s, honor Retry-After and back off with jitter.