Files
bitsforfree/openapi.json
T
smileBeda 48f05bcf8a feat: release meme protocol v1.1.0
Add one-click meme copying, complete viewer actions, fixed-footer pagination, protocol lore, and the Homo Reseticus download chooser.

Install dedicated social and favicon assets, expand local demo data, and synchronize the changelog, documentation, package, and OpenAPI release metadata.
2026-08-14 18:54:37 -03:00

581 lines
14 KiB
JSON

{
"openapi": "3.1.0",
"info": {
"title": "The Meme Protocol API",
"version": "1.1.0",
"description": "Public API for listing approved memes and adding PNG/JPEG meme uploads. Uploads follow the same moderation, image validation, normalization, and IP quota rules as the browser form."
},
"servers": [
{
"url": "/"
}
],
"tags": [
{
"name": "memes",
"description": "Approved meme discovery and addition"
},
{
"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": "Add a meme",
"description": "Adds 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 browser additions.",
"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/MemeAddResponse"
}
}
}
},
"202": {
"description": "Upload accepted and queued for admin review",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MemeAddResponse"
}
}
}
},
"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"
}
}
},
"MemeAddResponse": {
"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"
}
}
}
}
}
}
}