{"openapi":"3.0.3","info":{"title":"Valentine Captcha – Storage API (d-solve.de)","version":"1.0.0","description":"Stores a page of the \"Valentine Captcha\" tool on the server and returns a short link. Without an account: creating a site returns an edit key that allows any later change. The data is exactly the tool's link parameters (to, from, title, subtitle, select, prompt, help, cells, question, scale, readouts, reveal, msg, lang, img1 … img9 – see docs); other names are rejected. Hard limits: 1000 sites in total, 9 photos per site, 2500000 bytes per photo, retention at most 90 days, then automatic deletion. Global daily quotas (cost cap): 300 new sites, 1000 uploads, 20000 changes, 300000 picture views per UTC day; then 503 with code \"daily-cap\". Today's usage: GET /limits → today."},"externalDocs":{"description":"llms.txt: how the tool works, every parameter of data, the rules for agents, API and MCP","url":"https://d-solve.de/projects/valentine-captcha/llms.txt"},"x-mcp":{"url":"https://d-solve.de/valentine/mcp","transport":"streamable-http","description":"MCP server with one tool per endpoint below (valentine_limits, _create, _get, _update, _delete, _add_image, _delete_image, _rotate_key). Stateless, no login; the edit key is a tool argument."},"servers":[{"url":"https://d-solve.de/valentine/api"}],"tags":[{"name":"sites"},{"name":"images"},{"name":"accounts"},{"name":"billing"},{"name":"meta"}],"paths":{"/limits":{"get":{"tags":["meta"],"summary":"Limits, retention options, features, login providers","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/sites":{"post":{"tags":["sites"],"summary":"Create a site (no sign-in required)","description":"With a Bearer session the site belongs to the account. The response contains the edit key – exactly once.","security":[{},{"session":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Data"},"retentionDays":{"type":"integer","enum":[7,30,90],"default":30}}},"example":{"data":{"to":"Sarah","from":"Alex","cells":"1,3,5","lang":"en"},"retentionDays":30}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"allOf":[{"type":"object","properties":{"id":{"type":"string","example":"k7m2p9q4r6t8"},"url":{"type":"string","example":"https://d-solve.de/valentine/k7m2p9q4r6t8"},"subpages":{"type":"object","additionalProperties":{"type":"string"}},"data":{"$ref":"#/components/schemas/Data"},"images":{"type":"array","items":{"$ref":"#/components/schemas/Image"}},"imageCount":{"type":"integer"},"retentionDays":{"type":"integer"},"createdAt":{"type":"integer"},"updatedAt":{"type":"integer"},"expiresAt":{"type":"integer","description":"Unix seconds. After this time the site is deleted together with its photos."},"owned":{"type":"boolean"}}},{"type":"object","properties":{"editKey":{"type":"string","description":"Only in this response. Stored as a hash and cannot be retrieved again."},"apiUrl":{"type":"string"}}}]}}}},"400":{"description":"Invalid data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Daily limit per sender","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Storage full","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sites/bulk":{"post":{"tags":["sites"],"summary":"Create several sites (Premium)","security":[{"session":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"retentionDays":{"type":"integer"},"items":{"type":"array","maxItems":50,"items":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Data"},"retentionDays":{"type":"integer"}}}}}}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"allOf":[{"type":"object","properties":{"id":{"type":"string","example":"k7m2p9q4r6t8"},"url":{"type":"string","example":"https://d-solve.de/valentine/k7m2p9q4r6t8"},"subpages":{"type":"object","additionalProperties":{"type":"string"}},"data":{"$ref":"#/components/schemas/Data"},"images":{"type":"array","items":{"$ref":"#/components/schemas/Image"}},"imageCount":{"type":"integer"},"retentionDays":{"type":"integer"},"createdAt":{"type":"integer"},"updatedAt":{"type":"integer"},"expiresAt":{"type":"integer","description":"Unix seconds. After this time the site is deleted together with its photos."},"owned":{"type":"boolean"}}},{"type":"object","properties":{"editKey":{"type":"string","description":"Only in this response. Stored as a hash and cannot be retrieved again."},"apiUrl":{"type":"string"}}}]}}}}}}},"402":{"description":"Premium required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sites/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["sites"],"summary":"Read a site (public, like the link itself)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","example":"k7m2p9q4r6t8"},"url":{"type":"string","example":"https://d-solve.de/valentine/k7m2p9q4r6t8"},"subpages":{"type":"object","additionalProperties":{"type":"string"}},"data":{"$ref":"#/components/schemas/Data"},"images":{"type":"array","items":{"$ref":"#/components/schemas/Image"}},"imageCount":{"type":"integer"},"retentionDays":{"type":"integer"},"createdAt":{"type":"integer"},"updatedAt":{"type":"integer"},"expiresAt":{"type":"integer","description":"Unix seconds. After this time the site is deleted together with its photos."},"owned":{"type":"boolean"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["sites"],"summary":"Change data and/or retention","security":[{"editKey":[]},{"session":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Data"},"retentionDays":{"type":"integer","description":"Restarts the retention period from now."}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","example":"k7m2p9q4r6t8"},"url":{"type":"string","example":"https://d-solve.de/valentine/k7m2p9q4r6t8"},"subpages":{"type":"object","additionalProperties":{"type":"string"}},"data":{"$ref":"#/components/schemas/Data"},"images":{"type":"array","items":{"$ref":"#/components/schemas/Image"}},"imageCount":{"type":"integer"},"retentionDays":{"type":"integer"},"createdAt":{"type":"integer"},"updatedAt":{"type":"integer"},"expiresAt":{"type":"integer","description":"Unix seconds. After this time the site is deleted together with its photos."},"owned":{"type":"boolean"}}}}}},"401":{"description":"Key missing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Key incorrect","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["sites"],"summary":"Delete a site together with its photos","security":[{"editKey":[]},{"session":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/sites/{id}/verify":{"post":{"tags":["sites"],"summary":"Verify key","security":[{"editKey":[]},{"session":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"via":{"type":"string","enum":["key","owner"]}}}}}},"403":{"description":"Incorrect","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sites/{id}/rotate-key":{"post":{"tags":["sites"],"summary":"Generate a new edit key (the old one becomes invalid)","security":[{"editKey":[]},{"session":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"editKey":{"type":"string"}}}}}}}}},"/sites/{id}/claim":{"post":{"tags":["accounts"],"summary":"Assign an existing site to the signed-in account","security":[{"session":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["editKey"],"properties":{"editKey":{"type":"string"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","example":"k7m2p9q4r6t8"},"url":{"type":"string","example":"https://d-solve.de/valentine/k7m2p9q4r6t8"},"subpages":{"type":"object","additionalProperties":{"type":"string"}},"data":{"$ref":"#/components/schemas/Data"},"images":{"type":"array","items":{"$ref":"#/components/schemas/Image"}},"imageCount":{"type":"integer"},"retentionDays":{"type":"integer"},"createdAt":{"type":"integer"},"updatedAt":{"type":"integer"},"expiresAt":{"type":"integer","description":"Unix seconds. After this time the site is deleted together with its photos."},"owned":{"type":"boolean"}}}}}}}}},"/sites/{id}/images":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["images"],"summary":"Photos of the site","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Image"}}}}}}}}},"post":{"tags":["images"],"summary":"Upload a photo","description":"Three ways: raw data with Content-Type image/*; multipart/form-data with the field \"file\"; or JSON { \"url\": \"https://…\" } – then the server fetches the image itself (for AI agents). Allowed: JPEG, PNG, WebP, GIF, AVIF up to 2500000 bytes, at most 9 per site. The returned url is the value for img1 … img9 (one image per tile).","security":[{"editKey":[]},{"session":[]}],"requestBody":{"content":{"image/*":{"schema":{"type":"string","format":"binary"}},"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}}}},"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"}}}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Image"}}}},"409":{"description":"Photo limit reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Unsupported image","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sites/{id}/images/{imageId}":{"delete":{"tags":["images"],"summary":"Delete a photo","security":[{"editKey":[]},{"session":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"imageId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/auth/providers":{"get":{"tags":["accounts"],"summary":"Configured social login providers","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/auth/login":{"get":{"tags":["accounts"],"summary":"Start login (302 redirect to the provider)","parameters":[{"name":"provider","in":"query","required":true,"schema":{"type":"string","enum":["google"]}},{"name":"return","in":"query","required":true,"schema":{"type":"string"},"description":"Return address into the app; allowed origins only. The app receives #/auth/<token>."}],"responses":{"302":{"description":"Redirect"}}}},"/auth/me":{"get":{"tags":["accounts"],"summary":"Signed-in user with Premium status and account limits","security":[{"session":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/me/sites":{"get":{"tags":["accounts"],"summary":"Own sites","security":[{"session":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/billing/checkout":{"post":{"tags":["billing"],"summary":"Start Stripe Checkout for Premium","security":[{"session":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["return"],"properties":{"return":{"type":"string"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"}}}}}}}}},"/billing/portal":{"post":{"tags":["billing"],"summary":"Stripe customer portal (cancel, payment details)","security":[{"session":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["return"],"properties":{"return":{"type":"string"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"}}}}}}}}},"/auth/logout":{"post":{"tags":["accounts"],"summary":"Sign out","security":[{"session":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/auth/logout-all":{"post":{"tags":["accounts"],"summary":"Sign out everywhere","security":[{"session":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/billing/webhook":{"post":{"tags":["billing"],"summary":"Stripe webhook (for Stripe only)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}}}}}},"components":{"securitySchemes":{"editKey":{"type":"http","scheme":"bearer","description":"Edit key from the response of POST /sites (starts with vc_)."},"session":{"type":"apiKey","in":"cookie","name":"__Secure-vc_session","description":"HttpOnly session cookie after Google sign-in (GET /auth/login?provider=google&return=…). Browsers on allowed origins only; writes need a matching Origin header. AI agents use the edit key."}},"schemas":{"Data":{"type":"object","description":"The tool's link parameters: parameter name → text, e.g. { \"to\": \"Sarah\", \"from\": \"Alex\", \"cells\": \"1,3,5\", \"img1\": \"https://…\" }. lang only en/de; cells \"all\", \"any\" or a list of 1–9; img values must be http(s) URLs. At most 40 entries, 4000 characters per value, 16384 bytes in total. No data: URLs – upload images instead.","additionalProperties":{"type":"string"}},"Image":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"contentType":{"type":"string"},"size":{"type":"integer"},"createdAt":{"type":"integer"}}},"Error":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"}}}}}}