{"openapi":"3.1.0","info":{"title":"CopyPrompt API v1","version":"1.0.0","description":"Public REST API of the CopyPrompt community: search, copy and publish AI prompts from any agent or integration. Mirrors the MCP server tools (/api/mcp). JSON responses { data, nextCursor? }; errors with stable codes (rate_limited, invalid_key, not_found, invalid_body, forbidden, seed_mode, internal).","contact":{"name":"CopyPrompt","url":"https://copyprompt.dev"}},"servers":[{"url":"https://copyprompt.dev","description":"Production"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"prompts","description":"Search, detail and publishing of prompts"},{"name":"discovery","description":"Trending and categories"},{"name":"meta","description":"API specification"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"CopyPrompt API key in the cp_live_… format (create yours at /settings#api). Required on every route, no anonymous access: the key must belong to an account with a confirmed e-mail and must not be suspended (keys pause during a suspension, reads included, and work again when it ends). read scope: 600 req/h per key. write scope: publishing. Publishing via key (this API and the MCP server) has its own daily cap per ACCOUNT: 5/day for the first 7 days, 10/day afterwards with a verified email, at most one every 10s, always inside the site allowance of 20/150 per day."}},"schemas":{"PromptSummary":{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"type":{"type":"string","enum":["prompt","template","sistema","workflow","skill"]},"category":{"type":"string"},"rating":{"type":["number","null"],"description":"Displayed Bayesian rating (§7.7); null when there are no votes"},"copy_count":{"type":"integer"},"snippet":{"type":"string","description":"First 140 characters of the prompt. Empty for GitHub-only publications, whose content is repo_url + description"},"repo_url":{"type":["string","null"],"format":"uri","description":"GitHub repository (https://github.com/owner/repo); null when none"},"author":{"type":"string","description":"@username"},"url":{"type":"string","format":"uri"},"is_nsfw":{"type":"boolean","description":"Marked as sensitive content by the author or by moderation"}},"required":["slug","title","type","category","rating","copy_count","snippet","repo_url","author","url","is_nsfw"]},"PromptDetail":{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"type":{"type":"string","enum":["prompt","template","sistema","workflow","skill"]},"category":{"type":"string"},"prompt_text":{"type":"string","description":"Final text (interpolated when `variables` is sent). Empty for GitHub-only publications, whose content is repo_url + description"},"negative_prompt":{"type":["string","null"]},"model_params":{"type":"object","additionalProperties":{}},"variables":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":["string","null"]},"example":{"type":["string","null"]}},"required":["name","description","example"]},"description":"Variables detected in templates"},"workflow_steps":{"type":["array","null"],"items":{"type":"object","properties":{"ordem":{"type":"number"},"titulo":{"type":"string"},"prompt":{"type":"string"}},"required":["ordem","titulo","prompt"]}},"license":{"type":"string","enum":["cc0","cc-by","terceiros"]},"repo_url":{"type":["string","null"],"format":"uri","description":"GitHub repository (https://github.com/owner/repo); null when none"},"rating":{"type":["number","null"]},"copy_count":{"type":"integer"},"author":{"type":"string"},"url":{"type":"string","format":"uri"},"is_nsfw":{"type":"boolean","description":"Marked as sensitive content by the author or by moderation"},"skill_files":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string","description":"Relative path inside the skill, e.g. SKILL.md or references/x.md"},"content":{"type":"string"}},"required":["path","content"]},"description":"Files of a skill package, in tree order. Empty for any other type, and also for a skill whose files were flagged by the static analysis and not yet reviewed."},"skill_files_on_hold":{"type":"boolean","description":"True when the skill has files hidden until a human reviews them. `skill_files` is empty and `prompt_text` alone is NOT the package: do not install."}},"required":["slug","title","description","type","category","prompt_text","negative_prompt","model_params","variables","workflow_steps","license","repo_url","rating","copy_count","author","url","is_nsfw","skill_files","skill_files_on_hold"]},"Category":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"prompt_count":{"type":"integer"}},"required":["slug","name","prompt_count"]},"ApiError":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited","invalid_key","not_found","invalid_body","forbidden","seed_mode","internal"]},"message":{"type":"string"}},"required":["error","message"]},"PublishPromptInput":{"type":"object","properties":{"title":{"type":"string"},"prompt_text":{"type":"string","maxLength":20000},"type":{"type":"string","enum":["prompt","template","sistema","workflow","skill"],"default":"prompt"},"category":{"type":"string","minLength":2,"maxLength":40,"description":"Category slug (§5.2)"},"description":{"type":"string","minLength":150,"maxLength":3000},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":40},"maxItems":8,"description":"Tag names. Existing tags are attached as is. A NEW tag is created as pending moderation and counts against a weekly cap (5 new tags per 7 days); beyond the cap, or when moderation already refused that name, the tag is dropped WITHOUT failing the publish and comes back in ignored_tags / rejected_tags of the response. A name that cannot become a tag comes back in invalid_tags: no letter (a-z) or digit at all (e.g. only CJK, Cyrillic or symbols), invisible characters (tag characters, bidi controls), or content that moderation blocks."},"repo_url":{"type":"string","maxLength":300},"license":{"type":"string","enum":["cc0","cc-by","terceiros"],"default":"cc0"},"credit_author":{"type":"string","description":"Original author. Required when license is 'terceiros'."},"credit_url":{"type":"string","maxLength":292,"description":"Source link (GitHub, post, site...)."},"workflow_steps":{"type":"array","items":{"type":"object","properties":{"ordem":{"type":"integer","minimum":1,"maximum":20},"titulo":{"type":"string","minLength":1,"maxLength":120},"prompt":{"type":"string","maxLength":20000}},"required":["titulo","prompt"]},"maxItems":20,"description":"Ordered steps for a 'workflow' prompt (1-20). Required when type is 'workflow', forbidden otherwise."},"variables_meta":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":60},"description":{"type":"string","maxLength":200},"example":{"type":"string","maxLength":200}},"required":["name"]},"maxItems":50,"description":"Optional metadata for the {{variables}} in the prompt/steps."},"images":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string","minLength":1,"maxLength":600,"description":"The `path` returned by POST /api/upload"},"width":{"type":"integer","exclusiveMinimum":0,"maximum":16384},"height":{"type":"integer","exclusiveMinimum":0,"maximum":16384},"isCover":{"type":"boolean","description":"Cover of the publication; without it the first result is the cover"},"is_reference":{"type":"boolean","description":"Reference image (input of the prompt), not a result"}},"required":["path"]},"maxItems":11,"description":"Images already uploaded via POST /api/upload: up to 6 results plus 5 references. Video is not accepted through this port. POST /api/upload accepts only an API key with write scope (Authorization: Bearer cp_live_…, create one at /settings#api), never the OAuth token of a client authorized in the browser: such a client publishes without images, or uploads them with a key of the same account."},"is_nsfw":{"type":"boolean","description":"Mark as sensitive content. Required by the site rules when the prompt or its images are adult, graphic or otherwise not safe for every audience; the cover is then blurred behind a warning."}},"required":["title","prompt_text","category","description"]}},"parameters":{}},"paths":{"/api/v1/prompts":{"get":{"summary":"Search/list prompts","description":"Lists community prompts with filters. Cursor pagination (follow nextCursor until it runs out) is offered on the default sort=recent; other sorts (trending/copies/rating) return a single ranked page with no nextCursor.","tags":["prompts"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":200,"description":"Search text (alias: q)"},"required":false,"description":"Search text (alias: q)","name":"query","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":200,"description":"Search text (alias of query)"},"required":false,"description":"Search text (alias of query)","name":"q","in":"query"},{"schema":{"type":"string","maxLength":16,"description":"Set to 1 to return only GitHub repository-backed publications"},"required":false,"description":"Set to 1 to return only GitHub repository-backed publications","name":"github","in":"query"},{"schema":{"type":"string","maxLength":40,"description":"Category slug (e.g. image)"},"required":false,"description":"Category slug (e.g. image)","name":"category","in":"query"},{"schema":{"type":"string","enum":["prompt","template","sistema","workflow","skill"],"description":"Filter by prompt type"},"required":false,"description":"Filter by prompt type","name":"type","in":"query"},{"schema":{"type":"string","enum":["trending","copies","rating","recent"],"default":"recent","description":"Sort order. Cursor pagination (nextCursor) is offered only for 'recent' (stable); other sorts return a single ranked page."},"required":false,"description":"Sort order. Cursor pagination (nextCursor) is offered only for 'recent' (stable); other sorts return a single ranked page.","name":"sort","in":"query"},{"schema":{"type":"string","maxLength":400,"description":"Opaque cursor returned in nextCursor; do not interpret"},"required":false,"description":"Opaque cursor returned in nextCursor; do not interpret","name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":50,"default":20},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Page of results","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PromptSummary"}},"nextCursor":{"type":"string","description":"Present while there are more results (sort=recent only)"}},"required":["data"]}}}},"400":{"description":"Invalid parameters or cursor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid key, or the account behind it has not confirmed its e-mail or is suspended (keys pause during a suspension and work again when it ends) (invalid_key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"post":{"summary":"Publish a prompt","description":"Publishes a prompt as the key owner (write scope required). Counts against the account's via-key daily cap (shared with the MCP server) and against the overall daily publishing allowance, shared with the site.","tags":["prompts"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishPromptInput"}}}},"responses":{"201":{"description":"Prompt published","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"slug":{"type":"string"},"url":{"type":"string","format":"uri"},"ignored_tags":{"type":"array","items":{"type":"string"},"description":"New tags NOT created because the account hit its weekly cap for new tags. Present only when something was dropped; the prompt is published without them."},"rejected_tags":{"type":"array","items":{"type":"string"},"description":"Tags NOT attached because moderation already refused that name. Present only when something was dropped."},"invalid_tags":{"type":"array","items":{"type":"string"},"description":"Tags NOT attached because the name has no letter (a-z) or digit to build a slug from (e.g. only CJK, Cyrillic or symbols). Present only when something was dropped."},"on_hold":{"type":"boolean","description":"Skill flagged by the automatic code scan: published, but its text and files stay hidden (skill_files_on_hold on GET) until a human moderator releases them. Present only when held."}},"required":["slug","url"]}},"required":["data"]}}}},"400":{"description":"Invalid body (invalid_body, issues summarized in message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid key (invalid_key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"Key without write scope, or account email not verified (forbidden)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"413":{"description":"Request body larger than 512 KiB (invalid_body)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"Content refused by automatic screening (invalid_body)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit reached, or publishing pace/daily cap hit (rate_limited; Retry-After carries the wait in seconds)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal error (internal)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"Server in seed mode, no database (seed_mode)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/prompts/{slug}":{"get":{"summary":"Prompt detail","description":"Returns the full prompt. Send ?vars= with a urlencoded JSON object to interpolate the {{variables}} of templates. Every read records a copy with source='api' ('cli' when sent by the CopyPrompt CLI, which identifies itself with X-CopyPrompt-Client: cli).","tags":["prompts"],"parameters":[{"schema":{"type":"string","description":"Prompt slug (e.g. cinematic-product-photography)"},"required":true,"description":"Prompt slug (e.g. cinematic-product-photography)","name":"slug","in":"path"},{"schema":{"type":"string","description":"Urlencoded JSON object of name→value pairs, e.g. {\"product\":\"sneakers\"}"},"required":false,"description":"Urlencoded JSON object of name→value pairs, e.g. {\"product\":\"sneakers\"}","name":"vars","in":"query"}],"responses":{"200":{"description":"Full prompt (interpolated when vars is sent)","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PromptDetail"}},"required":["data"]}}}},"400":{"description":"vars is not a valid JSON object of name→value pairs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid key, or the account behind it has not confirmed its e-mail or is suspended (keys pause during a suspension and work again when it ends) (invalid_key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"Prompt not found (not_found)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/trending":{"get":{"summary":"Trending prompts","description":"Trending prompts in the community (same shape as search).","tags":["discovery"],"parameters":[{"schema":{"type":"string","maxLength":40},"required":false,"name":"category","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":20,"default":8},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"List of trending prompts","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PromptSummary"}}},"required":["data"]}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Missing or invalid key, or the account behind it has not confirmed its e-mail or is suspended (keys pause during a suspension and work again when it ends) (invalid_key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/categories":{"get":{"summary":"Categories","description":"All categories with the number of published prompts.","tags":["discovery"],"responses":{"200":{"description":"List of categories","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Category"}}},"required":["data"]}}}},"401":{"description":"Missing or invalid key, or the account behind it has not confirmed its e-mail or is suspended (keys pause during a suspension and work again when it ends) (invalid_key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Rate limit reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/openapi.json":{"get":{"summary":"This specification","description":"The OpenAPI 3.1 spec itself (to import into Custom GPTs and the like).","tags":["meta"],"security":[],"responses":{"200":{"description":"OpenAPI 3.1 document","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"429":{"description":"Rate limit reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}}},"webhooks":{}}