{
  "openapi": "3.1.0",
  "info": {
    "title": "Tailkits submit API",
    "version": "1.0.0",
    "summary": "Submit a product to the Tailkits directory and get a Stripe Checkout link back.",
    "description": "For agents and scripts acting for a maker. Nothing is charged by these calls: POST /api/checkout returns a Stripe Checkout link and the person pays the one-time $29 listing there. An editor reviews the product within two business days of payment; the maker is emailed at each step and refunded in full if it is not accepted. GET /api/submit returns the allowed categories and tags, the price and an example. Guide: https://tailkits.com/submit/api/",
    "contact": { "email": "info@tailkits.com", "url": "https://tailkits.com/submit/api/" }
  },
  "servers": [{ "url": "https://tailkits.com" }],
  "paths": {
    "/api/submit": {
      "get": {
        "operationId": "getSubmitGuide",
        "summary": "How to submit: request format, allowed categories and tags, price, example",
        "responses": { "200": { "description": "The guide", "content": { "application/json": { "schema": { "type": "object" } } } } }
      }
    },
    "/api/checkout": {
      "post": {
        "operationId": "submitProduct",
        "summary": "Submit a product; returns the Stripe Checkout link for the person who pays",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/SubmitRequest" },
              "example": {
                "product": {
                  "name": "Acme UI",
                  "url": "https://acme.dev",
                  "tagline": "Tailwind CSS components for SaaS dashboards",
                  "categories": ["components", "templates"],
                  "tags": ["react", "shadcnui"],
                  "pricing": "Paid",
                  "email": "maker@acme.dev"
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Submitted; waiting for payment", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SubmitResponse" } } } },
          "422": { "description": "Invalid fields; `fields` names each problem and the allowed values", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "rate_limited: at most 5 submissions per email and 20 per IP per hour", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "503": { "description": "payments_not_configured", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/api/submission/{id}": {
      "get": {
        "operationId": "getSubmissionStatus",
        "summary": "Status of a submission: pending, paid, expired or published",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "pattern": "^sub_" } }],
        "responses": {
          "200": {
            "description": "Status",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "status": { "type": "string", "enum": ["pending", "paid", "expired", "published"] } } } } }
          },
          "404": { "description": "Unknown id" }
        }
      }
    },
    "/api/sponsor-inquiry": {
      "post": {
        "operationId": "requestSponsorship",
        "summary": "Ask for a sponsorship package; an editor replies with dates and a payment link. Nothing is charged.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["scope", "term", "name", "url", "email"],
                "properties": {
                  "scope": { "type": "string", "enum": ["sitewide", "category"], "description": "sitewide = Partner; category = Category Spotlight" },
                  "category": { "type": "string", "description": "Required for scope=category: one of the category slugs from GET /api/submit" },
                  "term": { "type": "string", "enum": ["30d", "3m", "12m"] },
                  "name": { "type": "string", "minLength": 2, "maxLength": 80 },
                  "url": { "type": "string", "format": "uri", "description": "https:// product website or Tailkits listing" },
                  "email": { "type": "string", "format": "email" },
                  "note": { "type": "string", "maxLength": 1500 }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Stored; the requester gets an acknowledgement email", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "id": { "type": "string" } } } } } },
          "422": { "description": "Invalid fields", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "rate_limited" }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "SubmitRequest": {
        "type": "object",
        "required": ["product"],
        "properties": {
          "product": {
            "type": "object",
            "required": ["name", "url", "tagline", "categories", "email"],
            "properties": {
              "name": { "type": "string", "minLength": 2, "maxLength": 80 },
              "url": { "type": "string", "format": "uri", "description": "https:// only" },
              "tagline": { "type": "string", "minLength": 5, "maxLength": 140 },
              "description": { "type": "string", "maxLength": 3000 },
              "categories": {
                "type": "array",
                "minItems": 1,
                "maxItems": 2,
                "description": "The first is the main category",
                "items": {
                  "type": "string",
                  "enum": ["templates", "components", "boilerplates", "design", "cms", "ai-coding", "ai-app-builders", "mcp-servers", "api-tools", "testing", "authentication", "databases", "hosting", "email", "payments", "analytics", "monitoring"]
                }
              },
              "tags": { "type": "array", "maxItems": 5, "items": { "type": "string" }, "description": "Slugs from GET /api/submit" },
              "pricing": { "type": "string", "enum": ["Free", "Freemium", "Paid"] },
              "logoUrl": { "type": "string", "format": "uri" },
              "email": { "type": "string", "format": "email", "description": "The maker's email: receipt and review result" }
            }
          }
        }
      },
      "SubmitResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "example": "sub_6sfwj728cmc94tmt7jfa" },
          "checkoutUrl": { "type": "string", "format": "uri", "description": "Stripe Checkout for the person who pays" },
          "amountCents": { "type": "integer", "example": 2900 },
          "currency": { "type": "string", "example": "usd" },
          "expiresAt": { "type": "string", "format": "date-time", "description": "The link stops working then (30 minutes)" },
          "statusUrl": { "type": "string", "format": "uri" },
          "thankYouUrl": { "type": "string", "format": "uri" },
          "next": { "type": "string" }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": { "type": "string" },
          "message": { "type": "string" },
          "fields": { "type": "object", "additionalProperties": { "type": "string" } }
        }
      }
    }
  }
}
