{
  "openapi": "3.0.3",
  "info": {
    "title": "Kadro Agent API",
    "version": "1.0.0",
    "description": "JSON API for AI assistants and MCP clients to discover photographers/packages and book a specific photographer on a user's behalf. The assistant never handles payment or login itself — a human completes those on the payment link this API returns."
  },
  "servers": [
    { "url": "https://www.kadro.co/api/agent/v1" }
  ],
  "security": [{ "partnerToken": [] }],
  "paths": {
    "/status": {
      "get": {
        "summary": "Service health",
        "operationId": "getStatus",
        "security": [],
        "responses": {
          "200": {
            "description": "Service is up",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "example": "ok" },
                    "time": { "type": "string", "format": "date-time" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/partners/register": {
      "post": {
        "summary": "Self-service registration for a partner token",
        "operationId": "registerPartner",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name", "contact_email"],
                "properties": {
                  "name": { "type": "string", "description": "Calling platform's name" },
                  "contact_email": { "type": "string", "format": "email" }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Token issued — shown only once",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "token": { "type": "string" },
                    "daily_limit": { "type": "integer" },
                    "note": { "type": "string" }
                  }
                }
              }
            }
          },
          "422": { "description": "name or contact_email missing" }
        }
      }
    },
    "/shoot_types": {
      "get": {
        "summary": "List bookable shoot types",
        "operationId": "listShootTypes",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": { "type": "integer" },
                      "title": { "type": "string" }
                    }
                  }
                }
              }
            }
          },
          "401": { "description": "Invalid or missing partner token" },
          "429": { "description": "Daily request limit reached for this partner" }
        }
      }
    },
    "/photographers": {
      "get": {
        "summary": "List photographers offering a shoot type",
        "operationId": "listPhotographers",
        "parameters": [
          { "name": "shoot_type_id", "in": "query", "required": true, "schema": { "type": "integer" } },
          { "name": "city_id", "in": "query", "required": false, "schema": { "type": "integer" } }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "uid": { "type": "string" },
                      "display_name": { "type": "string" },
                      "rating": { "type": "number" },
                      "review_count": { "type": "integer" },
                      "grade": { "type": "string", "nullable": true },
                      "city": { "type": "string", "nullable": true }
                    }
                  }
                }
              }
            }
          },
          "422": { "description": "shoot_type_id is required" }
        }
      }
    },
    "/photographers/{uid}/packages": {
      "get": {
        "summary": "List a photographer's packages for a shoot type",
        "operationId": "listPhotographerPackages",
        "parameters": [
          { "name": "uid", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "shoot_type_id", "in": "query", "required": true, "schema": { "type": "integer" } }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": { "type": "integer" },
                      "title": { "type": "string" },
                      "price": { "type": "integer" },
                      "duration": { "type": "string", "nullable": true },
                      "digitals": { "type": "integer", "nullable": true },
                      "is_full": { "type": "boolean" },
                      "vip": { "type": "boolean" }
                    }
                  }
                }
              }
            }
          },
          "404": { "description": "Unknown photographer" },
          "422": { "description": "shoot_type_id missing, unknown, or not offered by this photographer" }
        }
      }
    },
    "/reservations": {
      "post": {
        "summary": "Create a guest, login-free reservation",
        "operationId": "createReservation",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["shoot_type_id", "package_id", "city_id", "photographer_uid", "start_time"],
                "properties": {
                  "shoot_type_id": { "type": "integer" },
                  "package_id": { "type": "integer" },
                  "city_id": { "type": "integer" },
                  "photographer_uid": { "type": "string" },
                  "start_time": { "type": "string", "format": "date-time" },
                  "address_latitude": { "type": "number" },
                  "address_longitude": { "type": "number" },
                  "address_detail": { "type": "string" },
                  "skip_location": { "type": "boolean" },
                  "shoot_detail": { "type": "string" },
                  "idempotency_key": { "type": "string" },
                  "guest_display_name": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Reservation created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Reservation" } } } },
          "200": { "description": "Idempotent replay of an existing reservation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Reservation" } } } },
          "422": { "description": "Could not create reservation" }
        }
      }
    },
    "/reservations/{slug}/payment_link": {
      "post": {
        "summary": "Get the human-facing payment link for a reservation",
        "operationId": "getPaymentLink",
        "parameters": [
          { "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payment_url": { "type": "string", "format": "uri" },
                    "hold_expires_at": { "type": "string", "format": "date-time", "nullable": true }
                  }
                }
              }
            }
          },
          "404": { "description": "Unknown reservation" },
          "410": { "description": "Reservation expired" }
        }
      }
    },
    "/reservations/{slug}/status": {
      "get": {
        "summary": "Check a reservation's status",
        "operationId": "getReservationStatus",
        "parameters": [
          { "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "slug": { "type": "string" },
                    "status": {
                      "type": "string",
                      "enum": ["awaiting_payment", "paid_awaiting_photographer_confirmation", "confirmed", "rejected", "expired"]
                    },
                    "hold_expires_at": { "type": "string", "format": "date-time", "nullable": true }
                  }
                }
              }
            }
          },
          "404": { "description": "Unknown reservation" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "partnerToken": {
        "type": "http",
        "scheme": "bearer",
        "description": "Token from POST /partners/register, sent as Authorization: Bearer <token>"
      }
    },
    "schemas": {
      "Reservation": {
        "type": "object",
        "properties": {
          "slug": { "type": "string" },
          "price": { "type": "integer", "nullable": true },
          "currency": { "type": "string", "example": "IRT" },
          "hold_expires_at": { "type": "string", "format": "date-time", "nullable": true },
          "status": { "type": "string" }
        }
      }
    }
  }
}
