{
  "openapi": "3.1.0",
  "info": {
    "title": "Sefera Partner API",
    "version": "1.2.0",
    "summary": "Server-to-server read API for publishable programs",
    "description": "Official Partner API V1 (documentation v1.2). Paths remain /v1/programs. Tenant is resolved only from the partner token. companyId is never accepted from the request. Intended for server-to-server use. CORS is not a security boundary. v1.2 adds optional public program fields and is backward-compatible.",
    "contact": {
      "name": "Sefera Partner API",
      "url": "https://sefera.com.tr"
    }
  },
  "servers": [
    {
      "url": "https://api.sefera.com.tr",
      "description": "Sefera Partner API v1.2"
    }
  ],
  "tags": [
    {
      "name": "Programs",
      "description": "Publishable programs for the token tenant"
    }
  ],
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "paths": {
    "/v1/programs": {
      "get": {
        "tags": [
          "Programs"
        ],
        "operationId": "listPrograms",
        "summary": "List publishable programs",
        "description": "Returns only publishable programs for the token company. Full programs (remaining=0) are included. Draft, cancelled, completed, archived, and ended programs are omitted.",
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Program list",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProgramListResponse"
                },
                "examples": {
                  "sample": {
                    "value": {
                      "data": [
                        {
                          "id": "abc123",
                          "name": "15 Gunluk Umre",
                          "status": "active",
                          "departureDate": "2026-10-12",
                          "returnDate": "2026-10-25",
                          "durationDays": 14,
                          "duration": {
                            "days": 14,
                            "nights": 13
                          },
                          "capacity": {
                            "total": 45,
                            "used": 23,
                            "remaining": 22
                          },
                          "currency": "USD",
                          "category": {
                            "type": "Yurt Disi",
                            "subtype": "Umre"
                          },
                          "guide": {
                            "name": "Rehber Adi"
                          },
                          "prices": {
                            "startingAmount": 1950,
                            "rooms": [
                              {
                                "occupancy": 2,
                                "amount": 1950
                              }
                            ],
                            "children": [
                              {
                                "minAge": 2,
                                "maxAge": 7,
                                "amount": 1400
                              }
                            ]
                          }
                        }
                      ],
                      "meta": {
                        "count": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/programs/{programId}": {
      "get": {
        "tags": [
          "Programs"
        ],
        "operationId": "getProgram",
        "summary": "Get one publishable program",
        "description": "Returns list fields plus description, category, departurePoint, hotels, guide, marketingTags, staff, accommodation, transport, media, and content. Non-publishable or other-tenant IDs return 404 with the same body so tenants cannot be enumerated.",
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "programId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Program detail",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProgramDetailResponse"
                },
                "examples": {
                  "sample": {
                    "value": {
                      "data": {
                        "id": "abc123",
                        "name": "15 Gunluk Umre",
                        "status": "active",
                        "departureDate": "2026-10-12",
                        "returnDate": "2026-10-25",
                        "durationDays": 14,
                        "duration": {
                          "days": 14,
                          "nights": 13
                        },
                        "capacity": {
                          "total": 45,
                          "used": 23,
                          "remaining": 22
                        },
                        "currency": "USD",
                        "category": {
                          "type": "Yurt Disi",
                          "subtype": "Umre"
                        },
                        "guide": {
                          "name": "Rehber Adi"
                        },
                        "prices": {
                          "startingAmount": 1950,
                          "rooms": [
                            {
                              "occupancy": 2,
                              "amount": 1950
                            }
                          ],
                          "children": [
                            {
                              "minAge": 2,
                              "maxAge": 7,
                              "amount": 1400
                            }
                          ]
                        },
                        "description": "Program aciklamasi",
                        "departurePoint": "Istanbul",
                        "hotels": [
                          {
                            "name": "Hotel Name",
                            "location": "Mekke",
                            "checkIn": "2026-10-12",
                            "checkOut": "2026-10-18",
                            "starLevel": 5
                          }
                        ],
                        "marketingTags": [
                          "Ramazan"
                        ],
                        "staff": {
                          "leadGuide": {
                            "name": "Rehber Adi"
                          },
                          "teachers": [
                            {
                              "name": "Hoca Adi",
                              "gender": "male",
                              "roleLabel": "Hoca"
                            }
                          ]
                        },
                        "accommodation": {
                          "stays": [
                            {
                              "name": "Hotel Name",
                              "location": "Mekke",
                              "checkIn": "2026-10-12",
                              "checkOut": "2026-10-18",
                              "starLevel": 5
                            }
                          ],
                          "description": "Konaklama aciklamasi"
                        },
                        "transport": {
                          "flights": [
                            {
                              "airline": {
                                "code": "THY",
                                "logoUrl": "https://api.sefera.com.tr/v1/assets/airlines/thy.svg"
                              }
                            }
                          ]
                        },
                        "media": {
                          "coverUrl": null,
                          "galleryUrls": []
                        },
                        "content": {
                          "included": [
                            "Ucak bileti"
                          ],
                          "excluded": [
                            "Kisisel harcamalar"
                          ],
                          "visits": [
                            "Mescid-i Haram"
                          ],
                          "accommodationDescription": "Konaklama aciklamasi",
                          "faq": [
                            {
                              "question": "Vize dahil mi?",
                              "answer": "Evet."
                            }
                          ],
                          "itinerary": [
                            {
                              "title": "Varis",
                              "description": "Havalimani karsilama"
                            }
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "partner_token",
        "description": "Authorization Bearer partner_token. Token plaintext is shown only once at create/rotate."
      }
    },
    "parameters": {
      "RequestId": {
        "name": "X-Request-Id",
        "in": "header",
        "required": false,
        "description": "Optional caller correlation id. Echoed when it matches [A-Za-z0-9._-]+ up to 128 chars.",
        "schema": {
          "type": "string"
        }
      }
    },
    "headers": {
      "XRequestId": {
        "description": "Correlation id for support",
        "schema": {
          "type": "string"
        }
      },
      "CacheControl": {
        "description": "Authenticated responses are not cached",
        "schema": {
          "type": "string",
          "example": "no-store"
        }
      },
      "RetryAfter": {
        "description": "Seconds until the current per-token window resets",
        "schema": {
          "type": "string"
        }
      }
    },
    "schemas": {
      "Capacity": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "total",
          "used",
          "remaining"
        ],
        "properties": {
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "Program capacity from the tour document"
          },
          "used": {
            "type": "integer",
            "minimum": 0,
            "description": "Operational passenger enrollments only. Terminal statuses and program_staff are excluded."
          },
          "remaining": {
            "type": "integer",
            "minimum": 0,
            "description": "max(0, total - used). Zero does not hide the program."
          }
        }
      },
      "RoomPrice": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "occupancy",
          "amount"
        ],
        "properties": {
          "occupancy": {
            "type": "integer",
            "minimum": 1
          },
          "amount": {
            "type": "number"
          }
        }
      },
      "ChildPrice": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "minAge",
          "maxAge",
          "amount"
        ],
        "properties": {
          "minAge": {
            "type": "integer"
          },
          "maxAge": {
            "type": "integer"
          },
          "amount": {
            "type": "number"
          }
        }
      },
      "Duration": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "days",
          "nights"
        ],
        "properties": {
          "days": {
            "type": "integer",
            "minimum": 1,
            "description": "Inclusive day count (same value as durationDays)"
          },
          "nights": {
            "type": "integer",
            "minimum": 0,
            "description": "Night count, max(0, days - 1)"
          }
        }
      },
      "Prices": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "rooms",
          "children"
        ],
        "properties": {
          "startingAmount": {
            "type": [
              "number",
              "null"
            ],
            "description": "Minimum valid adult room price derived from roomPrices"
          },
          "rooms": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RoomPrice"
            }
          },
          "children": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChildPrice"
            }
          }
        }
      },
      "HotelStay": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "location": {
            "type": [
              "string",
              "null"
            ]
          },
          "checkIn": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "checkOut": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "starLevel": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1,
            "maximum": 5,
            "description": "Public hotel star rating when available"
          }
        }
      },
      "Category": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "type": {
            "type": [
              "string",
              "null"
            ]
          },
          "subtype": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Guide": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "name": {
            "type": "string"
          }
        }
      },
      "StaffTeacher": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Public teacher display name"
          },
          "gender": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "male",
              "female",
              null
            ],
            "description": "Public gender when available"
          },
          "roleLabel": {
            "type": [
              "string",
              "null"
            ],
            "description": "Public role label when available"
          }
        }
      },
      "Staff": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "leadGuide": {
            "type": [
              "object",
              "null"
            ],
            "allOf": [
              {
                "$ref": "#/components/schemas/Guide"
              }
            ],
            "description": "Lead guide display name only"
          },
          "teachers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StaffTeacher"
            },
            "description": "Public teacher/hoca display info"
          }
        }
      },
      "AirlineBrand": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "code"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "Public airline code"
          },
          "logoUrl": {
            "type": [
              "string",
              "null"
            ],
            "description": "Public airline logo URL when available"
          }
        }
      },
      "PublicMedia": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "coverUrl": {
            "type": [
              "string",
              "null"
            ],
            "description": "Public cover image URL"
          },
          "galleryUrls": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Public gallery image URLs"
          }
        }
      },
      "PublicContent": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "included": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Included services"
          },
          "excluded": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Excluded services"
          },
          "visits": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Public visit/place names"
          },
          "accommodationDescription": {
            "type": [
              "string",
              "null"
            ],
            "description": "Public accommodation description"
          },
          "faq": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "question",
                "answer"
              ],
              "properties": {
                "question": {
                  "type": "string"
                },
                "answer": {
                  "type": "string"
                }
              }
            },
            "description": "Public program FAQ"
          },
          "itinerary": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "description": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            },
            "description": "Public itinerary. Raw dailyPlan is never published."
          }
        }
      },
      "Accommodation": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "stays": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HotelStay"
            },
            "description": "Public hotel stays including starLevel when available"
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Public accommodation description"
          }
        }
      },
      "Transport": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "flights": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "airline"
              ],
              "properties": {
                "airline": {
                  "$ref": "#/components/schemas/AirlineBrand"
                }
              }
            },
            "description": "Distinct public airlines used by the program"
          }
        }
      },
      "ProgramListItem": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "name",
          "status",
          "capacity",
          "prices"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Firestore tour document id"
          },
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "active"
            ],
            "description": "Stable public lifecycle. Publishable programs are always active."
          },
          "departureDate": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "returnDate": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "durationDays": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Inclusive date-only difference"
          },
          "duration": {
            "type": [
              "object",
              "null"
            ],
            "allOf": [
              {
                "$ref": "#/components/schemas/Duration"
              }
            ],
            "description": "Days and nights when both travel dates exist"
          },
          "capacity": {
            "$ref": "#/components/schemas/Capacity"
          },
          "currency": {
            "type": [
              "string",
              "null"
            ]
          },
          "category": {
            "type": [
              "object",
              "null"
            ],
            "allOf": [
              {
                "$ref": "#/components/schemas/Category"
              }
            ],
            "description": "Display category"
          },
          "guide": {
            "type": [
              "object",
              "null"
            ],
            "allOf": [
              {
                "$ref": "#/components/schemas/Guide"
              }
            ],
            "description": "Guide display name only"
          },
          "prices": {
            "$ref": "#/components/schemas/Prices"
          }
        }
      },
      "ProgramDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ProgramListItem"
          },
          {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "description": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Public program description"
              },
              "category": {
                "type": [
                  "object",
                  "null"
                ],
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Category"
                  }
                ],
                "description": "Display category"
              },
              "departurePoint": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Departure point text"
              },
              "hotels": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/HotelStay"
                },
                "description": "Hotel stays on the program"
              },
              "guide": {
                "type": [
                  "object",
                  "null"
                ],
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Guide"
                  }
                ],
                "description": "Guide display name only"
              },
              "marketingTags": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "string"
                },
                "description": "Public marketing labels"
              },
              "staff": {
                "type": [
                  "object",
                  "null"
                ],
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Staff"
                  }
                ],
                "description": "Public lead guide and teacher display info"
              },
              "accommodation": {
                "type": [
                  "object",
                  "null"
                ],
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Accommodation"
                  }
                ],
                "description": "Public stays plus accommodation description"
              },
              "transport": {
                "type": [
                  "object",
                  "null"
                ],
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Transport"
                  }
                ],
                "description": "Public airline brands used by the program"
              },
              "media": {
                "type": [
                  "object",
                  "null"
                ],
                "allOf": [
                  {
                    "$ref": "#/components/schemas/PublicMedia"
                  }
                ],
                "description": "Public cover and gallery URLs"
              },
              "content": {
                "type": [
                  "object",
                  "null"
                ],
                "allOf": [
                  {
                    "$ref": "#/components/schemas/PublicContent"
                  }
                ],
                "description": "Public included/excluded services, itinerary, visits, and FAQ"
              }
            }
          }
        ]
      },
      "ProgramListResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "data",
          "meta"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProgramListItem"
            }
          },
          "meta": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "count"
            ],
            "properties": {
              "count": {
                "type": "integer",
                "minimum": 0
              }
            }
          }
        }
      },
      "ProgramDetailResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/ProgramDetail"
          }
        }
      },
      "ErrorBody": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "code",
          "message"
        ],
        "properties": {
          "code": {
            "type": "string",
            "enum": [
              "invalid_request",
              "unauthorized",
              "forbidden",
              "not_found",
              "method_not_allowed",
              "rate_limit_exceeded",
              "internal_error"
            ]
          },
          "message": {
            "type": "string"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "error",
          "requestId"
        ],
        "properties": {
          "error": {
            "$ref": "#/components/schemas/ErrorBody"
          },
          "requestId": {
            "type": "string"
          }
        }
      }
    },
    "responses": {
      "InvalidRequest": {
        "description": "Invalid request",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "invalid_request",
                "message": "Invalid request"
              },
              "requestId": "req-example"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing, invalid, or revoked token",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "unauthorized",
                "message": "Authentication required"
              },
              "requestId": "req-example"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Token is valid but lacks programs.read",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "forbidden",
                "message": "Insufficient scope"
              },
              "requestId": "req-example"
            }
          }
        }
      },
      "NotFound": {
        "description": "Unknown path, or program is not publishable for this tenant",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "not_found",
                "message": "Resource not found"
              },
              "requestId": "req-example"
            }
          }
        }
      },
      "MethodNotAllowed": {
        "description": "Only GET is supported",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "method_not_allowed",
                "message": "Method not allowed"
              },
              "requestId": "req-example"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Per-token rate limit exceeded",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "rate_limit_exceeded",
                "message": "Rate limit exceeded"
              },
              "requestId": "req-example"
            }
          }
        }
      },
      "InternalError": {
        "description": "Unexpected server error",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "internal_error",
                "message": "Internal error"
              },
              "requestId": "req-example"
            }
          }
        }
      }
    }
  }
}
