{"openapi":"3.1.0","info":{"title":"The Meme Protocol API","version":"1.0.0","description":"Public API for listing approved memes and submitting PNG/JPEG meme uploads. Uploads follow the same moderation, image validation, normalization, and IP quota rules as the browser form."},"servers":[{"url":"https://bitsforfree.com"}],"tags":[{"name":"memes","description":"Approved meme discovery and submission"},{"name":"discovery","description":"Machine-readable API metadata"}],"paths":{"/api/memes":{"get":{"tags":["memes"],"summary":"List approved memes","description":"Returns approved public memes only. Results are paginated and read-limited per IP to reduce abuse.","parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"pageSize","in":"query","schema":{"type":"integer","minimum":1,"maximum":48,"default":12}}],"responses":{"200":{"description":"Approved meme page","headers":{"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"string","format":"date-time"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemeListResponse"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"tags":["memes"],"summary":"Submit a meme","description":"Submits one PNG or JPEG image using the same path as the browser upload form. The request must be multipart/form-data with a file field named meme. The server enforces the same size, dimension, pixel, moderation, normalization, and per-IP upload limits as human submissions.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["meme"],"properties":{"meme":{"type":"string","format":"binary","description":"PNG or JPEG image, maximum 5 MB, maximum edge 6000 px, maximum 20 megapixels."}}},"encoding":{"meme":{"contentType":"image/png, image/jpeg"}}}}},"responses":{"201":{"description":"Upload approved and published immediately","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemeSubmitResponse"}}}},"202":{"description":"Upload accepted and queued for admin review","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemeSubmitResponse"}}}},"400":{"$ref":"#/components/responses/Error"},"411":{"$ref":"#/components/responses/Error"},"413":{"$ref":"#/components/responses/Error"},"415":{"$ref":"#/components/responses/Error"},"422":{"description":"Upload rejected by moderation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModerationRejected"}}}},"429":{"$ref":"#/components/responses/Error"}}}},"/api/memes/{id}":{"get":{"tags":["memes"],"summary":"Get one approved meme","description":"Returns public metadata for an approved meme. Pending, rejected, deleted, or unknown IDs return 404.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-f0-9]{64}$"}}],"responses":{"200":{"description":"Approved meme metadata","headers":{"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"string","format":"date-time"}}},"content":{"application/json":{"schema":{"type":"object","required":["meme","rateLimit"],"properties":{"meme":{"$ref":"#/components/schemas/Meme"},"rateLimit":{"$ref":"#/components/schemas/RateLimit"}}}}}},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/media/{id}":{"get":{"tags":["memes"],"summary":"Fetch approved meme image","description":"Returns the normalized WebP image for an approved meme. Media reads are rate-limited per IP.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-f0-9]{64}$"}}],"responses":{"200":{"description":"WebP meme image","content":{"image/webp":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"Not found"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/openapi.json":{"get":{"tags":["discovery"],"summary":"OpenAPI document","responses":{"200":{"description":"OpenAPI 3.1 document","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/meme-api.skill.md":{"get":{"tags":["discovery"],"summary":"LLM API consumption instructions","responses":{"200":{"description":"Markdown skill instructions for LLM clients","content":{"text/markdown":{"schema":{"type":"string"}}}}}}}},"components":{"schemas":{"Meme":{"type":"object","required":["id","createdAt","byteSize","width","height","mime","originalMime","status","moderationScore","moderationReason","viewCount","downloadCount","originalName","url","downloadUrl","demo"],"properties":{"id":{"type":"string","pattern":"^[a-f0-9]{64}$"},"createdAt":{"type":"string","format":"date-time"},"byteSize":{"type":"integer","minimum":0},"width":{"type":"integer","minimum":1},"height":{"type":"integer","minimum":1},"mime":{"type":"string","const":"image/webp"},"originalMime":{"type":"string","enum":["image/png","image/jpeg"]},"status":{"type":"string","enum":["approved","pending"]},"moderationScore":{"type":"integer","minimum":0,"maximum":100},"moderationReason":{"type":"string"},"viewCount":{"type":"integer","minimum":0},"downloadCount":{"type":"integer","minimum":0},"originalName":{"type":"string"},"url":{"type":"string","format":"uri-reference"},"downloadUrl":{"type":"string","format":"uri-reference"},"demo":{"type":"boolean"}}},"MemeListResponse":{"type":"object","required":["page","pageSize","total","totalPages","memes","rateLimit"],"properties":{"page":{"type":"integer"},"pageSize":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"},"memes":{"type":"array","items":{"$ref":"#/components/schemas/Meme"}},"rateLimit":{"$ref":"#/components/schemas/RateLimit"}}},"MemeSubmitResponse":{"type":"object","required":["meme","quota","moderationScore","moderationReason","message"],"properties":{"meme":{"$ref":"#/components/schemas/Meme"},"quota":{"$ref":"#/components/schemas/UploadQuota"},"moderationScore":{"type":"integer","minimum":0,"maximum":100},"moderationReason":{"type":"string"},"message":{"type":"string","enum":["Upload approved.","Upload queued for admin review."]}}},"UploadQuota":{"type":"object","required":["remainingHour","remainingDay","remainingGlobalDay"],"properties":{"remainingHour":{"type":"integer","minimum":0},"remainingDay":{"type":"integer","minimum":0},"remainingGlobalDay":{"type":"integer","minimum":0}}},"RateLimit":{"type":"object","required":["limit","remaining","resetAt"],"properties":{"limit":{"type":"integer"},"remaining":{"type":"integer"},"resetAt":{"type":"string","format":"date-time"}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}},"ModerationRejected":{"type":"object","required":["error","moderationScore","moderationReason"],"properties":{"error":{"type":"string"},"moderationScore":{"type":"integer","minimum":0,"maximum":100},"moderationReason":{"type":"string"}}}},"responses":{"Error":{"description":"Error response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}