Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/AndrewwCO/Panahashi-Backend/llms.txt

Use this file to discover all available pages before exploring further.

Panahashi uses a consistent error response format across all endpoints. When a request fails, the API returns a JSON object with a machine-readable code and a human-readable message. Successful responses are always wrapped in an ApiResponse<T> envelope. Understanding the error shape and the status codes the API uses makes it straightforward to write reliable client-side error handling.

ApiError response shape

Every error response — regardless of cause — uses the same ApiError structure.
code
string
required
A machine-readable error identifier. Use this in your client code to branch on specific error types.
message
string
required
A human-readable description of what went wrong. May be in Spanish for auth errors.
Example error response
{
  "code": "NOT_FOUND",
  "message": "Bakery not found"
}
Error responses are not wrapped in ApiResponse. They are returned as a plain ApiError object directly at the top level.

HTTP status codes

The request succeeded. The response body is an ApiResponse<T> with success: true and the result in data. 201 Created is used for resource creation endpoints (e.g. POST /api/v1/orders).
{
  "success": true,
  "data": { "id": "order-abc123", "status": "PENDING" },
  "message": null
}
The request body or query parameters are invalid. This can come from a failed input validation (VALIDATION_ERROR) or a business rule rejection (BAD_REQUEST).
{
  "code": "VALIDATION_ERROR",
  "message": "price must be greater than 0, name must not be blank"
}
The Authorization header is missing, the Firebase ID token is expired, or the token cannot be verified. Re-authenticate the user and obtain a fresh token.
{
  "code": "UNAUTHORIZED",
  "message": "Token inválido o expirado"
}
The token is valid but the caller’s role does not permit the action. For example, a CUSTOMER trying to update an order status gets a 403.
{
  "code": "UNAUTHORIZED",
  "message": "Token inválido o expirado"
}
The code field for 403 responses is UNAUTHORIZED (matching the Ktor StatusPages handler). Check the HTTP status code — not just the code field — to distinguish 401 from 403 in your client.
The requested resource could not be found in Firestore. Thrown when a route handler calls noSuchElementException (or equivalent).
{
  "code": "NOT_FOUND",
  "message": "Order not found"
}
An unhandled exception occurred on the server. The response body always contains a generic message to avoid leaking internals.
{
  "code": "INTERNAL_ERROR",
  "message": "Internal server error"
}

Error codes reference

CodeHTTP statusCause
UNAUTHORIZED401 or 403Missing/invalid Firebase token, or caller’s role is insufficient
BAD_REQUEST400Malformed request body or business rule violation (IllegalArgumentException)
VALIDATION_ERROR400Request failed Ktor’s RequestValidationException checks
NOT_FOUND404Resource not found in Firestore (NoSuchElementException)
INTERNAL_ERROR500Unhandled server exception

Common errors and how to resolve them

ScenarioCodeHTTPResolution
Firebase token expiredUNAUTHORIZED401Call FirebaseAuth.currentUser.getIdToken(true) to force-refresh the token and retry.
No Authorization header sentUNAUTHORIZED401Ensure every protected request includes Authorization: Bearer <id_token>.
CUSTOMER calls a BAKER-only routeUNAUTHORIZED403Check the endpoint’s required role in the roles reference before calling.
bakeryId query param missing on product listBAD_REQUEST400Include ?bakeryId=<id> in the request URL.
Submitting a review for a non-existent orderNOT_FOUND404Verify the orderId exists and belongs to the authenticated user.
Negative or zero price on product creationVALIDATION_ERROR400Check validation error message for the specific field(s) that failed.
Firestore service temporarily unavailableINTERNAL_ERROR500Retry with exponential backoff. If the issue persists, contact support.

ApiResponse wrapper

Successful responses are always wrapped in ApiResponse<T>:
success
boolean
required
Always true for successful responses.
data
T | null
The response payload. The type varies by endpoint — see each endpoint’s reference for the concrete type returned.
message
string | null
Optional human-readable message. Often null on success, populated on some create/action endpoints.
Successful single-object response
{
  "success": true,
  "data": {
    "id": "bakery-xyz789",
    "name": "La Panadería Feliz",
    "rating": 4.8,
    "isOpen": true
  },
  "message": null
}
Always check success before reading data. Even a 200 OK could theoretically return success: false for partial-failure scenarios in future API versions.

Pagination with PagedResponse

List endpoints that return many results use PagedResponse<T> instead of a plain array. Pass page and pageSize as query parameters to control which slice you receive.
data
T[]
required
Items on the current page.
page
number
required
Current page number (1-based).
pageSize
number
required
Maximum items per page as requested.
total
number
required
Total item count across all pages.
hasMore
boolean
required
true when additional pages exist beyond the current one.
Fetching the second page of products
GET /api/v1/products?bakeryId=bakery-xyz789&page=2&pageSize=20
PagedResponse example
{
  "data": [
    { "id": "prod-021", "name": "Pan de bono", "price": 2000 }
  ],
  "page": 2,
  "pageSize": 20,
  "total": 47,
  "hasMore": true
}
When hasMore is false, you have received the final page. Requesting a page number beyond total / pageSize returns an empty data array.

Build docs developers (and LLMs) love