{
    "openapi": "3.1.0",
    "info": {
        "title": "ZebraSnap Public API",
        "summary": "AI-powered marketplace for event sports photography.",
        "description": "ZebraSnap connects race photographers with athletes. Photographers upload event photos; AI tags faces and bib numbers; athletes find themselves with a selfie or a race number.\n\nThis specification documents the **public** HTTP API: site config, showcase content, event search, geo lookups, and token authentication. Authenticated photographer endpoints (albums, uploads, sales) use the same base URL and a Sanctum bearer token from `loginUser`.\n\nWhen to call this API:\n- Look up live plans, commissions, and app download URLs.\n- Search public events so an athlete can find their photos.\n- List countries/divisions for location pickers.\n- Authenticate a photographer or buyer on behalf of an official client.\n\nDo not use this API to scrape private galleries, bypass watermarks, or download unpaid originals.\n\nVersioning: this document is API version 1. Send `X-API-Version: 1` or omit it (v1 is the default). Paths stay at `/api/...` for v1. Breaking changes ship as `/api/v2/...`; the retired path then sends `Deprecation` and `Sunset` headers. Nothing is deprecated today.\n\nRate limits: unauthenticated catalogue endpoints allow 60 requests per minute per client. Successful responses include `RateLimit-Limit`, `RateLimit-Remaining`, and `RateLimit-Policy`. A 429 also includes `Retry-After`.",
        "version": "1.0.0",
        "contact": {
            "name": "ZebraSnap support",
            "email": "alfonso@vexilo.com",
            "url": "https://zebrasnap.com/contact"
        },
        "license": {
            "name": "Proprietary",
            "url": "https://zebrasnap.com/terms-and-conditions"
        }
    },
    "servers": [
        {
            "url": "https://zebrasnap.com",
            "description": "Production"
        }
    ],
    "tags": [
        {
            "name": "Catalog",
            "description": "Unauthenticated catalogue and marketing data."
        },
        {
            "name": "Events",
            "description": "Public event search."
        },
        {
            "name": "Auth",
            "description": "Sanctum token authentication for official clients."
        },
        {
            "name": "Discovery",
            "description": "Machine-readable docs for agents."
        }
    ],
    "paths": {
        "/openapi.json": {
            "get": {
                "operationId": "getOpenApiJson",
                "tags": [
                    "Discovery"
                ],
                "summary": "OpenAPI specification (JSON)",
                "description": "Returns this OpenAPI 3.1 document as JSON. Use it to generate clients or bind function-calling tools.",
                "responses": {
                    "200": {
                        "description": "OpenAPI 3.1 document.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/OpenApiDocument"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/Error"
                    },
                    "404": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    },
                    "500": {
                        "$ref": "#/components/responses/Error"
                    }
                },
                "parameters": [
                    {
                        "$ref": "#/components/parameters/ApiVersion"
                    }
                ]
            }
        },
        "/api/openapi.yaml": {
            "get": {
                "operationId": "getOpenApiYaml",
                "tags": [
                    "Discovery"
                ],
                "summary": "OpenAPI specification (YAML)",
                "description": "Same document as `/openapi.json`, serialized as YAML.",
                "responses": {
                    "200": {
                        "description": "OpenAPI 3.1 document.",
                        "content": {
                            "application/yaml": {
                                "schema": {
                                    "type": "string"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/Error"
                    },
                    "404": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    },
                    "500": {
                        "$ref": "#/components/responses/Error"
                    }
                },
                "parameters": [
                    {
                        "$ref": "#/components/parameters/ApiVersion"
                    }
                ]
            }
        },
        "/api/site-config": {
            "get": {
                "operationId": "getSiteConfig",
                "tags": [
                    "Catalog"
                ],
                "summary": "Plans, commissions, and app download URLs",
                "description": "Live photographer plans (prices in USD cents), the lowest commission, store/desktop download URLs, and public social handles. Unauthenticated. Cache for up to an hour.",
                "responses": {
                    "200": {
                        "description": "Current site configuration.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/SiteConfig"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/Error"
                    },
                    "404": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    },
                    "500": {
                        "$ref": "#/components/responses/Error"
                    }
                },
                "parameters": [
                    {
                        "$ref": "#/components/parameters/ApiVersion"
                    }
                ]
            }
        },
        "/api/config": {
            "get": {
                "operationId": "getAppConfig",
                "tags": [
                    "Catalog"
                ],
                "summary": "Mobile app bootstrap config",
                "description": "Locale, localization hints, Stripe fee constants, and help-center URLs used to boot the official mobile app. Unauthenticated; a Sanctum bearer is optional and only changes localization defaults.",
                "parameters": [
                    {
                        "name": "language",
                        "in": "query",
                        "required": false,
                        "description": "ISO 639-1 locale to localize help URLs.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "en"
                    },
                    {
                        "$ref": "#/components/parameters/ApiVersion"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "App bootstrap payload.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AppConfig"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/Error"
                    },
                    "404": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    },
                    "500": {
                        "$ref": "#/components/responses/Error"
                    }
                }
            }
        },
        "/api/showcase/photos": {
            "get": {
                "operationId": "listShowcasePhotos",
                "tags": [
                    "Catalog"
                ],
                "summary": "Curated public photos for the home hero",
                "description": "Watermarked showcase photos used on the marketing home. Faces are normalized bounding boxes. Unauthenticated.",
                "responses": {
                    "200": {
                        "description": "Showcase photos.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ShowcasePhotoList"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/Error"
                    },
                    "404": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    },
                    "500": {
                        "$ref": "#/components/responses/Error"
                    }
                },
                "parameters": [
                    {
                        "$ref": "#/components/parameters/ApiVersion"
                    }
                ]
            }
        },
        "/api/showcase/albums": {
            "get": {
                "operationId": "listShowcaseAlbums",
                "tags": [
                    "Catalog"
                ],
                "summary": "Curated public albums",
                "description": "Recently published public albums (no minors). Unauthenticated. Cached per locale.",
                "parameters": [
                    {
                        "name": "language",
                        "in": "query",
                        "required": false,
                        "description": "ISO 639-1 locale for dates and location labels.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "en"
                    },
                    {
                        "$ref": "#/components/parameters/ApiVersion"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Showcase albums.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ShowcaseAlbumList"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/Error"
                    },
                    "404": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    },
                    "500": {
                        "$ref": "#/components/responses/Error"
                    }
                }
            }
        },
        "/api/countries": {
            "get": {
                "operationId": "listCountries",
                "tags": [
                    "Catalog"
                ],
                "summary": "Countries supported for payouts and location pickers",
                "description": "Sorted list of countries. Names follow the `language` query (or Accept-Language). Unauthenticated.",
                "parameters": [
                    {
                        "name": "language",
                        "in": "query",
                        "required": false,
                        "description": "ISO 639-1 locale for country names.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "en"
                    },
                    {
                        "$ref": "#/components/parameters/ApiVersion"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Country list.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "$ref": "#/components/schemas/Country"
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/Error"
                    },
                    "404": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    },
                    "500": {
                        "$ref": "#/components/responses/Error"
                    }
                }
            }
        },
        "/api/divisions": {
            "get": {
                "operationId": "listDivisions",
                "tags": [
                    "Catalog"
                ],
                "summary": "States or provinces for a country",
                "description": "Requires `country` (the numeric id from `listCountries`). Unauthenticated.",
                "parameters": [
                    {
                        "name": "country",
                        "in": "query",
                        "required": true,
                        "description": "Country id from `listCountries`.",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "language",
                        "in": "query",
                        "required": false,
                        "description": "ISO 639-1 locale for division names.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "en"
                    },
                    {
                        "$ref": "#/components/parameters/ApiVersion"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Division list.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "$ref": "#/components/schemas/Division"
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/Error"
                    },
                    "404": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    },
                    "500": {
                        "$ref": "#/components/responses/Error"
                    }
                }
            }
        },
        "/api/event-categories": {
            "get": {
                "operationId": "listEventCategories",
                "tags": [
                    "Catalog"
                ],
                "summary": "Canonical event disciplines",
                "description": "Slug list such as `running`, `cycling`, `triathlon`. Unauthenticated.",
                "responses": {
                    "200": {
                        "description": "Category slugs.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/EventCategoryList"
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/Error"
                    },
                    "404": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    },
                    "500": {
                        "$ref": "#/components/responses/Error"
                    }
                },
                "parameters": [
                    {
                        "$ref": "#/components/parameters/ApiVersion"
                    }
                ]
            }
        },
        "/api/events/quick-search": {
            "get": {
                "operationId": "searchEvents",
                "tags": [
                    "Events"
                ],
                "summary": "Typeahead search for public events with photos",
                "description": "Returns up to 8 active public events that have published albums. Without `q`, results are ranked by the visitor's country. Throttled at 60 requests per minute. Unauthenticated.",
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "required": false,
                        "description": "Event name fragment. Empty returns nearby popular events.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "division",
                        "in": "query",
                        "required": false,
                        "description": "Division id to pin the nearby ranking.",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/ApiVersion"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Matching events.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/EventSearchResponse"
                                }
                            }
                        }
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    },
                    "400": {
                        "$ref": "#/components/responses/Error"
                    },
                    "404": {
                        "$ref": "#/components/responses/Error"
                    },
                    "500": {
                        "$ref": "#/components/responses/Error"
                    }
                }
            }
        },
        "/api/login": {
            "post": {
                "operationId": "loginUser",
                "tags": [
                    "Auth"
                ],
                "summary": "Exchange credentials for a Sanctum token",
                "description": "Authenticate a photographer or buyer. `login` accepts email or username. The returned bearer token authorizes the official mobile and desktop clients. Rate limited.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/LoginRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Authenticated session.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/LoginResponse"
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    },
                    "400": {
                        "$ref": "#/components/responses/Error"
                    },
                    "404": {
                        "$ref": "#/components/responses/Error"
                    },
                    "500": {
                        "$ref": "#/components/responses/Error"
                    }
                },
                "parameters": [
                    {
                        "$ref": "#/components/parameters/ApiVersion"
                    }
                ]
            }
        },
        "/api/user": {
            "get": {
                "operationId": "getCurrentUser",
                "tags": [
                    "Auth"
                ],
                "summary": "Current authenticated user",
                "description": "Requires a Sanctum bearer token from `loginUser`.",
                "security": [
                    {
                        "sanctum": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The authenticated user.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CurrentUserResponse"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Error"
                    },
                    "400": {
                        "$ref": "#/components/responses/Error"
                    },
                    "404": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    },
                    "500": {
                        "$ref": "#/components/responses/Error"
                    }
                },
                "parameters": [
                    {
                        "$ref": "#/components/parameters/ApiVersion"
                    }
                ]
            }
        },
        "/api/logout": {
            "post": {
                "operationId": "logoutUser",
                "tags": [
                    "Auth"
                ],
                "summary": "Revoke the current Sanctum token",
                "description": "Deletes the bearer token sent on the request. Returns 204.",
                "security": [
                    {
                        "sanctum": []
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Token revoked."
                    },
                    "401": {
                        "$ref": "#/components/responses/Error"
                    },
                    "400": {
                        "$ref": "#/components/responses/Error"
                    },
                    "404": {
                        "$ref": "#/components/responses/Error"
                    },
                    "429": {
                        "$ref": "#/components/responses/Error"
                    },
                    "500": {
                        "$ref": "#/components/responses/Error"
                    }
                },
                "parameters": [
                    {
                        "$ref": "#/components/parameters/ApiVersion"
                    }
                ]
            }
        }
    },
    "components": {
        "parameters": {
            "ApiVersion": {
                "name": "X-API-Version",
                "in": "header",
                "required": false,
                "description": "API version. Defaults to `1`. Breaking changes ship as `/api/v2` and send Deprecation/Sunset on the old path.",
                "schema": {
                    "type": "string",
                    "enum": [
                        "1"
                    ],
                    "default": "1"
                }
            }
        },
        "securitySchemes": {
            "sanctum": {
                "type": "http",
                "scheme": "bearer",
                "bearerFormat": "token",
                "description": "Personal access token from `loginUser`. Send as `Authorization: Bearer {token}`."
            }
        },
        "schemas": {
            "OpenApiDocument": {
                "type": "object",
                "description": "OpenAPI 3.1 document.",
                "additionalProperties": true
            },
            "ShowcasePhotoList": {
                "type": "object",
                "required": [
                    "data"
                ],
                "properties": {
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/ShowcasePhoto"
                        }
                    }
                }
            },
            "ShowcaseAlbumList": {
                "type": "object",
                "required": [
                    "data"
                ],
                "properties": {
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/ShowcaseAlbum"
                        }
                    }
                }
            },
            "EventCategoryList": {
                "type": "array",
                "items": {
                    "type": "string",
                    "examples": [
                        "running",
                        "cycling",
                        "triathlon"
                    ]
                }
            },
            "CurrentUserResponse": {
                "type": "object",
                "required": [
                    "user"
                ],
                "properties": {
                    "user": {
                        "$ref": "#/components/schemas/User"
                    }
                }
            },
            "ErrorEnvelope": {
                "type": "object",
                "required": [
                    "message",
                    "error"
                ],
                "properties": {
                    "message": {
                        "type": "string",
                        "description": "Human-readable summary (legacy clients)."
                    },
                    "errors": {
                        "type": "object",
                        "additionalProperties": {
                            "type": "array",
                            "items": {
                                "type": "string"
                            }
                        },
                        "description": "Field-level validation messages when `error.code` is `validation_error`."
                    },
                    "error": {
                        "$ref": "#/components/schemas/Error"
                    }
                }
            },
            "Error": {
                "type": "object",
                "required": [
                    "code",
                    "message",
                    "hint"
                ],
                "properties": {
                    "code": {
                        "type": "string",
                        "description": "Stable machine code: `not_found`, `unauthenticated`, `forbidden`, `validation_error`, `rate_limited`, `internal_error`."
                    },
                    "message": {
                        "type": "string"
                    },
                    "hint": {
                        "type": "string",
                        "description": "What an agent should do next."
                    },
                    "details": {
                        "description": "Optional structured extras (validation map, etc.)."
                    }
                }
            },
            "SiteConfig": {
                "type": "object",
                "required": [
                    "lowestCommission",
                    "plans",
                    "appStoreUrl",
                    "googlePlayUrl"
                ],
                "properties": {
                    "lowestCommission": {
                        "type": "integer",
                        "description": "Lowest photographer commission percentage."
                    },
                    "appStoreUrl": {
                        "type": "string",
                        "format": "uri"
                    },
                    "googlePlayUrl": {
                        "type": "string",
                        "format": "uri"
                    },
                    "desktopMacArmUrl": {
                        "type": "string",
                        "format": "uri"
                    },
                    "desktopMacIntelUrl": {
                        "type": "string",
                        "format": "uri"
                    },
                    "desktopWindowsUrl": {
                        "type": "string",
                        "format": "uri"
                    },
                    "lightroomPluginUrl": {
                        "type": "string",
                        "format": "uri"
                    },
                    "social": {
                        "type": "object",
                        "properties": {
                            "instagram": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "tiktok": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        }
                    },
                    "plans": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Plan"
                        }
                    }
                }
            },
            "Plan": {
                "type": "object",
                "required": [
                    "key",
                    "commission",
                    "monthlyPriceCents",
                    "yearlyPriceCents"
                ],
                "properties": {
                    "key": {
                        "type": "string",
                        "examples": [
                            "free",
                            "lite",
                            "pro",
                            "enterprise"
                        ]
                    },
                    "commission": {
                        "type": "integer"
                    },
                    "storageGb": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "monthlyPriceCents": {
                        "type": "integer"
                    },
                    "yearlyPriceCents": {
                        "type": "integer"
                    },
                    "recommended": {
                        "type": "boolean"
                    },
                    "features": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "key": {
                                    "type": "string"
                                },
                                "comingSoon": {
                                    "type": "boolean"
                                }
                            }
                        }
                    }
                }
            },
            "AppConfig": {
                "type": "object",
                "required": [
                    "language",
                    "maxImageUploadSizeKb"
                ],
                "properties": {
                    "language": {
                        "type": "string"
                    },
                    "maxImageUploadSizeKb": {
                        "type": "integer"
                    },
                    "helpFeesUrl": {
                        "type": "string",
                        "format": "uri"
                    },
                    "helpRewardsUrl": {
                        "type": "string",
                        "format": "uri"
                    },
                    "helpVideosUrl": {
                        "type": "string",
                        "format": "uri"
                    },
                    "helpDiscountsUrl": {
                        "type": "string",
                        "format": "uri"
                    }
                }
            },
            "ShowcasePhoto": {
                "type": "object",
                "required": [
                    "uuid",
                    "thumb",
                    "aspect",
                    "album_uuid",
                    "event_slug"
                ],
                "properties": {
                    "uuid": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "thumb": {
                        "type": "string",
                        "format": "uri"
                    },
                    "aspect": {
                        "type": "number"
                    },
                    "faces": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "width": {
                                    "type": "number"
                                },
                                "height": {
                                    "type": "number"
                                },
                                "left": {
                                    "type": "number"
                                },
                                "top": {
                                    "type": "number"
                                }
                            }
                        }
                    },
                    "album_uuid": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "event_slug": {
                        "type": "string"
                    }
                }
            },
            "ShowcaseAlbum": {
                "type": "object",
                "properties": {
                    "title": {
                        "type": "string"
                    },
                    "total_photos": {
                        "type": "integer"
                    },
                    "cover": {
                        "type": "string",
                        "format": "uri"
                    },
                    "cover_2x": {
                        "type": "string",
                        "format": "uri"
                    },
                    "url": {
                        "type": "string",
                        "format": "uri"
                    },
                    "event_name": {
                        "type": "string"
                    },
                    "event_location": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "event_date": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "photographer": {
                        "type": "string"
                    }
                }
            },
            "Country": {
                "type": "object",
                "required": [
                    "id",
                    "name",
                    "code"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "name": {
                        "type": "string"
                    },
                    "code": {
                        "type": "string",
                        "description": "ISO 3166-1 alpha-2."
                    }
                }
            },
            "Division": {
                "type": "object",
                "required": [
                    "id",
                    "name"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "name": {
                        "type": "string"
                    }
                }
            },
            "EventSearchResponse": {
                "type": "object",
                "required": [
                    "events",
                    "scope"
                ],
                "properties": {
                    "events": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/EventSummary"
                        }
                    },
                    "scope": {
                        "type": "string",
                        "enum": [
                            "division",
                            "country",
                            "continent",
                            "global"
                        ]
                    },
                    "locationLabel": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "countryId": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "divisionId": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    }
                }
            },
            "EventSummary": {
                "type": "object",
                "required": [
                    "name",
                    "slug",
                    "url"
                ],
                "properties": {
                    "name": {
                        "type": "string"
                    },
                    "slug": {
                        "type": "string"
                    },
                    "url": {
                        "type": "string",
                        "format": "uri"
                    },
                    "cover": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "uri"
                    },
                    "categorySlug": {
                        "type": "string"
                    },
                    "dateLabel": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "locationLabel": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "photosCount": {
                        "type": "integer"
                    }
                }
            },
            "LoginRequest": {
                "type": "object",
                "required": [
                    "login",
                    "password"
                ],
                "properties": {
                    "login": {
                        "type": "string",
                        "description": "Email or username."
                    },
                    "password": {
                        "type": "string",
                        "format": "password"
                    },
                    "remember": {
                        "type": "boolean",
                        "default": false
                    },
                    "device_name": {
                        "type": "string",
                        "maxLength": 255
                    }
                }
            },
            "LoginResponse": {
                "type": "object",
                "required": [
                    "token",
                    "token_type",
                    "user"
                ],
                "properties": {
                    "token": {
                        "type": "string"
                    },
                    "token_type": {
                        "type": "string",
                        "examples": [
                            "Bearer"
                        ]
                    },
                    "expires_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "user": {
                        "$ref": "#/components/schemas/User"
                    }
                }
            },
            "User": {
                "type": "object",
                "properties": {
                    "uuid": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "name": {
                        "type": "string"
                    },
                    "username": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "email": {
                        "type": "string",
                        "format": "email"
                    }
                }
            }
        },
        "responses": {
            "Error": {
                "description": "Structured error. `message` is kept for existing clients; agents should read `error`.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ErrorEnvelope"
                        }
                    }
                }
            }
        }
    }
}