{
  "openapi": "3.0.3",
  "info": {
    "title": "PageRankCafe API",
    "description": "API for managing ads, credits, and referrals on PageRankCafe. Authenticate with a Bearer token obtained from your account's API Keys page.",
    "version": "1.0.0",
    "contact": {
      "url": "https://pagerankcafe.com/contact-us"
    }
  },
  "servers": [
    {
      "url": "https://pagerankcafe.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key obtained from your account's API Keys page at /apiKeys"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          }
        }
      },
      "Link": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "title": { "type": "string" },
          "url": { "type": "string" },
          "views": { "type": "string" },
          "link_post_count": { "type": "string" }
        }
      },
      "Banner": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "title": { "type": "string" },
          "url": { "type": "string", "description": "Banner image URL (HTTPS, must be a valid image with supported dimensions)" },
          "url_target": { "type": "string", "description": "Click-through destination URL (HTTPS)" },
          "impressions": { "type": "string" },
          "clicks": { "type": "string" },
          "ctr": { "type": "string" }
        }
      },
      "YouTubeAd": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "title": { "type": "string" },
          "video_url": { "type": "string" },
          "views": { "type": "string" },
          "youtube_ad_post_count": { "type": "string" }
        }
      },
      "PressRelease": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "title": { "type": "string" },
          "slug": { "type": "string" },
          "url": { "type": "string" },
          "views": { "type": "string" },
          "post_count": { "type": "string" }
        }
      },
      "Credits": {
        "type": "object",
        "properties": {
          "available_credits": { "type": "integer" },
          "available_posts": { "type": "integer" },
          "links_viewed": { "type": "integer" },
          "links_remaining": { "type": "integer" }
        }
      },
      "Referrals": {
        "type": "object",
        "properties": {
          "today": { "type": "integer" },
          "last_7_days": { "type": "integer" },
          "last_30_days": { "type": "integer" },
          "all_time": { "type": "integer" }
        }
      }
    }
  },
  "paths": {
    "/api/health": {
      "get": {
        "summary": "Health check",
        "description": "Returns API status and authenticated user info.",
        "tags": ["General"],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "example": "ok" },
                    "user": { "type": "string", "example": "johndoe" },
                    "membership": { "type": "string", "enum": ["free", "upgraded"], "example": "upgraded" }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          }
        }
      }
    },
    "/api/links": {
      "get": {
        "summary": "List your links",
        "description": "Returns all active, non-reported links for the authenticated user.",
        "tags": ["Read"],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "links": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Link" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/banners": {
      "get": {
        "summary": "List your banners",
        "description": "Returns all active banners for the authenticated user.",
        "tags": ["Read"],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "banners": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Banner" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/youtube-ads": {
      "get": {
        "summary": "List your YouTube ads",
        "description": "Returns all active, non-reported YouTube ads for the authenticated user.",
        "tags": ["Read"],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "youtube_ads": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/YouTubeAd" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/press-releases": {
      "get": {
        "summary": "List your press releases",
        "description": "Returns all active, non-reported press releases for the authenticated user.",
        "tags": ["Read"],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "press_releases": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/PressRelease" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/credits": {
      "get": {
        "summary": "Get credit balance",
        "description": "Returns available credits, posts, links viewed, and links remaining for the authenticated user.",
        "tags": ["Read"],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "credits": { "$ref": "#/components/schemas/Credits" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/referral-stats": {
      "get": {
        "summary": "Get referral statistics",
        "description": "Returns referral counts for today, last 7 days, last 30 days, and all time.",
        "tags": ["Read"],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "referrals": { "$ref": "#/components/schemas/Referrals" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/banners/create": {
      "post": {
        "summary": "Create a banner",
        "description": "Creates a new banner ad. Requires paid membership. The banner image URL must be HTTPS and point to an image with supported dimensions. The location is automatically detected from the image size.",
        "tags": ["Write"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["title", "url", "url_target"],
                "properties": {
                  "title": { "type": "string", "description": "Banner title" },
                  "url": { "type": "string", "description": "HTTPS URL to the banner image. Supported sizes: 728x90, 300x250, 120x600, 160x600, 468x60, 336x280, 250x250, 851x315, 650x400, 800x82, 234x60, 125x125, 300x200, 120x240, 240x400, 150x60" },
                  "url_target": { "type": "string", "description": "HTTPS click-through destination URL" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Banner created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "example": "created" },
                    "banner": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string" },
                        "title": { "type": "string" },
                        "url": { "type": "string" },
                        "url_target": { "type": "string" },
                        "location": { "type": "string", "enum": ["TOP_BOTTOM", "HALF", "FULL_SIDE", "HALF_SIDE", "BILLBOARD"] }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "403": {
            "description": "Paid membership required",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          }
        }
      }
    },
    "/api/banners/post": {
      "post": {
        "summary": "Post a banner with credits",
        "description": "Posts an existing banner into rotation using credits. Paid members can post 1-2 day banners (10 credits per day).",
        "tags": ["Write"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["banner_id"],
                "properties": {
                  "banner_id": { "type": "integer", "description": "ID of the banner to post" },
                  "days": { "type": "integer", "description": "Duration in days. Paid members: 1-2.", "default": 1 }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Banner posted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "example": "posted" },
                    "banner_post": {
                      "type": "object",
                      "properties": {
                        "banner_id": { "type": "string" },
                        "days": { "type": "string" },
                        "start_date": { "type": "string", "format": "date-time" },
                        "end_date": { "type": "string", "format": "date-time" }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error or insufficient credits",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "403": {
            "description": "Paid membership required",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          }
        }
      }
    },
    "/api/press-releases/create": {
      "post": {
        "summary": "Create a press release",
        "description": "Creates a new press release / blog article. Requires paid membership.",
        "tags": ["Write"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["title", "url", "intro", "body", "slug"],
                "properties": {
                  "title": { "type": "string", "description": "Article title" },
                  "url": { "type": "string", "description": "HTTPS source URL" },
                  "intro": { "type": "string", "description": "Short introduction text" },
                  "body": { "type": "string", "description": "Full article HTML content" },
                  "slug": { "type": "string", "description": "URL slug (must be unique)" },
                  "meta_description": { "type": "string", "description": "SEO meta description (optional)" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Press release created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "example": "created" },
                    "press_release": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string" },
                        "title": { "type": "string" },
                        "slug": { "type": "string" }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "403": {
            "description": "Paid membership required",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          }
        }
      }
    },
    "/api/press-releases/post": {
      "post": {
        "summary": "Post a press release with credits",
        "description": "Posts an existing press release to the press release widget on the home page using credits. Paid members can post 7-day press releases (70 credits / 7 post points).",
        "tags": ["Write"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["press_release_id"],
                "properties": {
                  "press_release_id": { "type": "integer", "description": "ID of the press release to post" },
                  "days": { "type": "integer", "description": "Duration in days. Paid members: 7.", "default": 7 }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Press release posted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "example": "posted" },
                    "press_release_post": {
                      "type": "object",
                      "properties": {
                        "press_release_id": { "type": "string" },
                        "days": { "type": "string" },
                        "start_date": { "type": "string", "format": "date-time" },
                        "end_date": { "type": "string", "format": "date-time" }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error or insufficient credits",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "403": {
            "description": "Paid membership required",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          }
        }
      }
    }
  },
  "tags": [
    { "name": "General", "description": "Health and status endpoints" },
    { "name": "Read", "description": "Read-only endpoints available to all members" },
    { "name": "Write", "description": "Write endpoints requiring paid membership" }
  ]
}
