{
  "openapi": "3.1.0",
  "info": {
    "title": "FrameAnyPhoto API",
    "version": "1.1.0",
    "description": "Museum-quality framed prints of public-domain art. Agents can search works, price prints, and create a Stripe checkout link for the buyer to pay."
  },
  "servers": [
    {
      "url": "https://frameanyphoto.com"
    }
  ],
  "paths": {
    "/api/catalog": {
      "get": {
        "operationId": "listCatalog",
        "summary": "Public works with sizes, frames, prices, and credit. Aliases: /api/works, /api/browse",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "description": "Search title, artist, and category"
          },
          {
            "name": "category",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Category slug or id, as on /browse (see /api/catalog/categories)"
          },
          {
            "name": "series",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Series id (see /api/catalog/categories)"
          },
          {
            "name": "artist",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Small, Medium, Large, or a size id like 24x36"
          },
          {
            "name": "min_price",
            "in": "query",
            "schema": {
              "type": "number",
              "minimum": 0
            },
            "description": "USD"
          },
          {
            "name": "max_price",
            "in": "query",
            "schema": {
              "type": "number",
              "minimum": 0
            },
            "description": "USD"
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "relevance",
                "title",
                "artist",
                "newest",
                "resolution"
              ]
            },
            "description": "Default: relevance with q, else title. newest = latest artwork date"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "next_cursor from the previous page"
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ total, offset, limit, count, next_cursor, next, works[] }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/catalog/{slug}": {
      "get": {
        "operationId": "getCatalogWork",
        "summary": "One public work",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Work",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/catalog/categories": {
      "get": {
        "operationId": "listCatalogCategories",
        "summary": "Categories with ids, names, and counts",
        "responses": {
          "200": {
            "description": "Categories",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/collection": {
      "get": {
        "operationId": "getCollection",
        "summary": "All works with image, pixels, PPI, and source record",
        "responses": {
          "200": {
            "description": "Collection",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/agent/print-options": {
      "get": {
        "operationId": "getPrintOptions",
        "summary": "Sizes, frames, and prices for one work",
        "parameters": [
          {
            "name": "work",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Print options",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/agent/quote": {
      "post": {
        "operationId": "quoteOrder",
        "summary": "Price a framed print with shipping; tax is added at checkout",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "work": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Prefer ascii_id (the slug) from search_works or get_work; the id with or without its en dash, a /w/ URL, exact title, accession, or NASA ID also work"
                  },
                  "size": {
                    "type": "string",
                    "maxLength": 40,
                    "description": "size_id from get_print_options, or Small, Medium, Large. Default: the site default (Large when the scan allows)"
                  },
                  "frame": {
                    "type": "string",
                    "maxLength": 120,
                    "description": "frame_id from get_print_options. Default: the work's default frame"
                  },
                  "quantity": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 6,
                    "default": 1
                  },
                  "ship_to": {
                    "type": "object",
                    "description": "Optional. Checks that we ship there.",
                    "properties": {
                      "country": {
                        "type": "string",
                        "description": "ISO country code. Only US is accepted."
                      },
                      "state": {
                        "type": "string",
                        "description": "2-letter state code"
                      },
                      "zip": {
                        "type": "string",
                        "description": "US ZIP code"
                      }
                    },
                    "additionalProperties": false
                  }
                },
                "required": [
                  "work"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Quote",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/agent/checkout": {
      "post": {
        "operationId": "createCheckout",
        "summary": "Stripe Checkout link for the buyer to pay",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "work": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Prefer ascii_id (the slug) from search_works or get_work; the id with or without its en dash, a /w/ URL, exact title, accession, or NASA ID also work"
                  },
                  "size": {
                    "type": "string",
                    "maxLength": 40,
                    "description": "size_id from get_print_options, or Small, Medium, Large. Default: the site default (Large when the scan allows)"
                  },
                  "frame": {
                    "type": "string",
                    "maxLength": 120,
                    "description": "frame_id from get_print_options. Default: the work's default frame"
                  },
                  "quantity": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 6,
                    "default": 1
                  },
                  "email": {
                    "type": "string",
                    "maxLength": 254,
                    "description": "Optional buyer email to prefill"
                  }
                },
                "required": [
                  "work"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "checkout_url and order_ref",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/agent/orders/{order_ref}": {
      "get": {
        "operationId": "getOrderStatus",
        "summary": "Payment and shipping status; no personal data",
        "parameters": [
          {
            "name": "order_ref",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/policies": {
      "get": {
        "operationId": "getPolicies",
        "summary": "Shipping, returns, payment, tax, and contact policies (same JSON as /.well-known/policies.json). Alias: /api/agent/policies",
        "responses": {
          "200": {
            "description": "Store policies",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/mcp": {
      "post": {
        "operationId": "mcp",
        "summary": "MCP JSON-RPC (Streamable HTTP)",
        "responses": {
          "200": {
            "description": "JSON-RPC response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/a2a": {
      "post": {
        "operationId": "a2a",
        "summary": "A2A JSON-RPC",
        "responses": {
          "200": {
            "description": "JSON-RPC response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  }
}
