{"openapi":"3.1.0","info":{"title":"Debajoyti Paul, Portfolio API","description":"REST API for Debajoyti Paul's portfolio site. Provides read-only access to projects, blog posts, testimonials, tech stack, experiences, social links, and SEO metadata. Admin endpoints require NextAuth session authentication.\n\n## When to Use\nUse this API when you need structured data about Debajoyti Paul's work, projects, blog posts, or professional background. The public GET endpoints return published content only.\n\n## Authentication\nPublic endpoints (GET on most resources) require no authentication. Admin write operations require a valid NextAuth session with `role: 'admin'`. Use `/api/auth/signin` to authenticate.\n\n## Versioning & Deprecation Policy\nThe current stable major version is **v1** (see `info.version`). Unversioned paths (`/api/blogs`) always track the latest version; a permanent alias serves v1 explicitly under `/api/v1/*` (e.g., `/api/v1/blogs`). Pin integrations to the `/api/v1/` alias to opt out of future breaking moves.\n\nWhen an endpoint is deprecated it is served with `Deprecation` and `Sunset` response headers announcing the removal date, and at least 90 days of overlap are maintained before shutdown. Breaking changes bump the major version instead of silently altering existing responses.\n\n## Rate Limiting\nAPI requests are limited to **120 requests per minute per IP**. Every API response carries `RateLimit-Policy`, `RateLimit-Limit`, `RateLimit-Remaining`, and `RateLimit-Reset` headers so agents can self-throttle in real time. When the limit is exceeded the API returns HTTP 429 with a structured JSON error (`error.code: RATE_LIMITED`) plus a `Retry-After` header. Auth routes (`/api/auth/*`) and internal cron/upload routes are exempt.","version":"1.0.0","contact":{"name":"Debajoyti Paul","email":"debajyoti5000@gmail.com","url":"https://debajoyti.vercel.app"}},"servers":[{"url":"https://debajoyti.vercel.app","description":"Production"}],"externalDocs":{"description":"Developer portal, quickstart, rate limits, versioning policy","url":"https://debajoyti.vercel.app/developers"},"paths":{"/api/blogs":{"get":{"operationId":"listBlogs","summary":"List blog posts","description":"Returns published blog posts. Admin users can see unpublished posts. Results are sorted by creation date (newest first).","tags":["Blog"],"parameters":[{"name":"published","in":"query","description":"Filter to published posts only","schema":{"type":"string","enum":["true"]}}],"responses":{"200":{"description":"List of blog posts","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Blog"}}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/blogs/{id}":{"get":{"operationId":"getBlog","summary":"Get a blog post by ID","description":"Returns a single blog post. Unpublished posts return 404 for non-admin users.","tags":["Blog"],"parameters":[{"name":"id","in":"path","required":true,"description":"MongoDB ObjectId of the blog post","schema":{"type":"string"}}],"responses":{"200":{"description":"Blog post found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Blog"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/projects":{"get":{"operationId":"listProjects","summary":"List projects","description":"Returns published projects sorted by order. Admin users can see unpublished projects.","tags":["Projects"],"parameters":[{"name":"published","in":"query","schema":{"type":"string","enum":["true"]}}],"responses":{"200":{"description":"List of projects","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Project"}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/projects/{id}":{"get":{"operationId":"getProject","summary":"Get a project by ID","description":"Returns a single project by its MongoDB ObjectId.","tags":["Projects"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/projects/featured":{"get":{"operationId":"listFeaturedProjects","summary":"List featured projects","description":"Returns all published projects sorted by order. Useful for display on landing pages.","tags":["Projects"],"responses":{"200":{"description":"List of featured projects","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Project"}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/categories":{"get":{"operationId":"listCategories","summary":"List categories","description":"Returns all categories sorted alphabetically.","tags":["Categories"],"responses":{"200":{"description":"List of categories","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Category"}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/testimonials":{"get":{"operationId":"listTestimonials","summary":"List testimonials","description":"Returns published testimonials sorted by order.","tags":["Testimonials"],"parameters":[{"name":"published","in":"query","schema":{"type":"string","enum":["true"]}}],"responses":{"200":{"description":"List of testimonials","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Testimonial"}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/testimonials/{id}":{"get":{"operationId":"getTestimonial","summary":"Get a testimonial by ID","description":"Returns a single testimonial by its MongoDB ObjectId.","tags":["Testimonials"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Testimonial"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/favorites":{"get":{"operationId":"listFavorites","summary":"List favorites","description":"Returns published favorites sorted by order. Admins also receive drafts.","tags":["Favorites"],"parameters":[{"name":"published","in":"query","schema":{"type":"string","enum":["true"]}},{"name":"category","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"List of favorites","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Favorite"}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/favorites/{id}":{"get":{"operationId":"getFavorite","summary":"Get a favorite by ID","description":"Returns a single favorite by its MongoDB ObjectId.","tags":["Favorites"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Favorite"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/tech-stack":{"get":{"operationId":"listTechStack","summary":"List tech stack entries","description":"Returns published tech stack entries sorted by order.","tags":["Tech Stack"],"parameters":[{"name":"published","in":"query","schema":{"type":"string","enum":["true"]}}],"responses":{"200":{"description":"List of tech stack entries","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TechStack"}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/tech-stack/{id}":{"get":{"operationId":"getTechStack","summary":"Get a tech stack entry by ID","description":"Returns a single tech stack entry by its MongoDB ObjectId.","tags":["Tech Stack"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TechStack"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/experiences":{"get":{"operationId":"listExperiences","summary":"List work experiences","description":"Returns published experiences sorted by order.","tags":["Experiences"],"parameters":[{"name":"published","in":"query","schema":{"type":"string","enum":["true"]}}],"responses":{"200":{"description":"List of experiences","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Experience"}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/experiences/{id}":{"get":{"operationId":"getExperience","summary":"Get an experience by ID","description":"Returns a single work experience by its MongoDB ObjectId.","tags":["Experiences"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Experience"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/social-links":{"get":{"operationId":"listSocialLinks","summary":"List social links","description":"Returns published social links sorted by order.","tags":["Social Links"],"parameters":[{"name":"published","in":"query","schema":{"type":"string","enum":["true"]}}],"responses":{"200":{"description":"List of social links","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SocialLink"}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/social-links/{id}":{"get":{"operationId":"getSocialLink","summary":"Get a social link by ID","description":"Returns a single social link by its MongoDB ObjectId.","tags":["Social Links"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SocialLink"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/seo":{"get":{"operationId":"listSEORecords","summary":"List SEO metadata records","description":"Returns all page SEO metadata records sorted by page path.","tags":["SEO"],"responses":{"200":{"description":"List of SEO records","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SEORecord"}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/settings":{"get":{"operationId":"getSettings","summary":"Get site settings","description":"Returns all site settings as a key-value map. Some settings may contain sensitive data, use caution.","tags":["Settings"],"responses":{"200":{"description":"Settings key-value map","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/tracks":{"get":{"operationId":"listTracks","summary":"List music tracks","description":"Returns published music tracks sorted by order.","tags":["Tracks"],"parameters":[{"name":"published","in":"query","schema":{"type":"string","enum":["true"]}}],"responses":{"200":{"description":"List of tracks","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Track"}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/tracks/{id}":{"get":{"operationId":"getTrack","summary":"Get a track by ID","description":"Returns a single music track by its MongoDB ObjectId.","tags":["Tracks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Track"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/unsplash/search":{"get":{"operationId":"searchUnsplash","summary":"Search Unsplash images","description":"Search Unsplash for landscape photos. Returns up to 12 results. Requires UNSPLASH_ACCESS_KEY environment variable.","tags":["Media"],"parameters":[{"name":"q","in":"query","required":true,"description":"Search query","schema":{"type":"string"}}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"thumb":{"type":"string","format":"uri"},"regular":{"type":"string","format":"uri"},"alt":{"type":"string"},"photographer":{"type":"string"},"photographerUrl":{"type":"string","format":"uri"}}}}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/mcp":{"post":{"operationId":"mcpRpc","summary":"MCP Streamable HTTP endpoint (JSON-RPC 2.0)","description":"Model Context Protocol server over Streamable HTTP (JSON-RPC 2.0). Send JSON-RPC messages: initialize, notifications/initialized, ping, tools/list, tools/call. Read-only tools for portfolio data. Live handshake is also served directly at /.well-known/mcp (POST), which returns discovery metadata on GET.","tags":["MCP"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method"],"properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"id":{"type":["string","number"],"description":"Omit for notifications"},"method":{"type":"string","enum":["initialize","notifications/initialized","ping","tools/list","tools/call"]},"params":{"type":"object"}}}}}},"responses":{"200":{"description":"JSON-RPC 2.0 response","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"id":{"type":["string","number","null"]},"result":{"type":"object"},"error":{"type":"object","properties":{"code":{"type":"number"},"message":{"type":"string"},"data":{}}}}}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"202":{"description":"Accepted (notification only, no body)","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"400":{"description":"Parse error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"405":{"description":"Method not allowed (use POST)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}}},"429":{"$ref":"#/components/responses/RateLimited"}}}}},"components":{"headers":{"RateLimitPolicy":{"description":"Rate limit policy: limit;w=window-seconds (RFC 9331)","schema":{"type":"string","example":"120;w=60"}},"RateLimitLimit":{"description":"Requests allowed per window","schema":{"type":"integer","example":120}},"RateLimitRemaining":{"description":"Requests remaining in the current window","schema":{"type":"integer"}},"RateLimitReset":{"description":"Seconds until the window resets","schema":{"type":"integer"}},"RetryAfter":{"description":"Seconds to wait before retrying after a 429","schema":{"type":"integer"}}},"responses":{"RateLimited":{"description":"Rate limit exceeded (120 requests per minute per IP)","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Blog":{"type":"object","properties":{"_id":{"type":"string","description":"MongoDB ObjectId"},"title":{"type":"string"},"slug":{"type":"string"},"excerpt":{"type":"string"},"content":{"type":"string"},"coverImage":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"category":{"oneOf":[{"type":"string"},{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"}}}]},"published":{"type":"boolean"},"featured":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"scheduledAt":{"type":["string","null"],"format":"date-time","description":"Future publish time when the post is queued by the scheduler"},"publishedAt":{"type":["string","null"],"format":"date-time","description":"Actual time the post was published"},"metaTitle":{"type":"string"},"metaDescription":{"type":"string"}}},"BlogCreate":{"type":"object","required":["title","slug","content"],"properties":{"title":{"type":"string"},"slug":{"type":"string"},"excerpt":{"type":"string"},"content":{"type":"string"},"coverImage":{"type":"string"},"category":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"published":{"type":"boolean"},"featured":{"type":"boolean"},"metaTitle":{"type":"string"},"metaDescription":{"type":"string"},"metaKeywords":{"type":"string"},"canonicalUrl":{"type":"string"},"ogImage":{"type":"string"},"focusKeyword":{"type":"string"},"imageAlt":{"type":"string"},"readingTime":{"type":"number"},"scheduledAt":{"type":"string","format":"date-time","description":"Future publish time, the post stays unpublished until then, then auto-publishes via the hourly scheduler"}}},"BlogUpdate":{"type":"object","properties":{"title":{"type":"string"},"slug":{"type":"string"},"excerpt":{"type":"string"},"content":{"type":"string"},"coverImage":{"type":"string"},"category":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"published":{"type":"boolean"},"featured":{"type":"boolean"},"scheduledAt":{"type":["string","null"],"format":"date-time","description":"Set a future time to schedule publication, or null to clear the schedule. Must be in the future; ignored (cleared) when published is true."}}},"Project":{"type":"object","properties":{"_id":{"type":"string"},"title":{"type":"string"},"slug":{"type":"string"},"tagline":{"type":"string"},"description":{"type":"string"},"fullDescription":{"type":"string"},"role":{"type":"string"},"timeline":{"type":"string"},"stack":{"type":"array","items":{"type":"string"}},"features":{"type":"array","items":{"type":"string"}},"github":{"type":"string"},"demo":{"type":"string"},"image":{"type":"string"},"color":{"type":"string"},"published":{"type":"boolean"},"status":{"type":"string","enum":["backlog","in-progress","completed"]},"order":{"type":"number"},"createdAt":{"type":"string","format":"date-time"}}},"ProjectCreate":{"type":"object","required":["title","slug"],"properties":{"title":{"type":"string"},"slug":{"type":"string"},"tagline":{"type":"string"},"description":{"type":"string"},"fullDescription":{"type":"string"},"role":{"type":"string"},"timeline":{"type":"string"},"stack":{"type":"array","items":{"type":"string"}},"features":{"type":"array","items":{"type":"string"}},"github":{"type":"string"},"demo":{"type":"string"},"image":{"type":"string"},"color":{"type":"string"},"published":{"type":"boolean"},"status":{"type":"string"}}},"ProjectUpdate":{"type":"object","properties":{"title":{"type":"string"},"tagline":{"type":"string"},"description":{"type":"string"},"fullDescription":{"type":"string"},"published":{"type":"boolean"},"status":{"type":"string"}}},"Category":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"description":{"type":"string"}}},"Testimonial":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"content":{"type":"string"},"role":{"type":"string"},"company":{"type":"string"},"avatar":{"type":"string"},"rating":{"type":"number"},"featured":{"type":"boolean"},"published":{"type":"boolean"},"order":{"type":"number"}}},"Favorite":{"type":"object","properties":{"_id":{"type":"string"},"title":{"type":"string"},"url":{"type":"string"},"domain":{"type":"string"},"note":{"type":"string"},"category":{"type":"string"},"color":{"type":"string"},"order":{"type":"number"},"published":{"type":"boolean"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}}},"TechStack":{"type":"object","properties":{"_id":{"type":"string"},"category":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"statement":{"type":"string"},"icon":{"type":"string"},"color":{"type":"string"},"published":{"type":"boolean"},"items":{"type":"array","items":{"type":"string"}},"order":{"type":"number"}}},"Experience":{"type":"object","properties":{"_id":{"type":"string"},"company":{"type":"string"},"role":{"type":"string"},"location":{"type":"string"},"duration":{"type":"string"},"description":{"type":"string"},"published":{"type":"boolean"},"order":{"type":"number"}}},"SocialLink":{"type":"object","properties":{"_id":{"type":"string"},"platform":{"type":"string"},"url":{"type":"string","format":"uri"},"label":{"type":"string"},"order":{"type":"number"}}},"SEORecord":{"type":"object","properties":{"_id":{"type":"string"},"page":{"type":"string"},"metaTitle":{"type":"string"},"metaDescription":{"type":"string"},"metaKeywords":{"type":"string"},"ogImage":{"type":"string"},"canonicalUrl":{"type":"string"}}},"Track":{"type":"object","properties":{"_id":{"type":"string"},"title":{"type":"string"},"audioUrl":{"type":"string","format":"uri"},"artist":{"type":"string"},"fileId":{"type":"string"},"cover":{"type":"string"},"published":{"type":"boolean"},"order":{"type":"number"}}},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code"},"message":{"type":"string","description":"Human-readable error message"},"hint":{"type":"string","description":"Suggested resolution for the agent"}},"required":["code","message"]}}},"PublishRun":{"type":"object","properties":{"published":{"type":"number","description":"Posts successfully published in this run"},"failed":{"type":"number","description":"Posts that failed to publish"},"notifyErrors":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"channel":{"type":"string","enum":["telegram","linkedin"]},"error":{"type":"string"}}},"description":"Notification failures (the posts themselves are still published)"},"results":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"status":{"type":"string","enum":["published","failed"]},"error":{"type":"string"}}}},"message":{"type":"string","description":"Present when nothing was due"}}}},"securitySchemes":{"sessionAuth":{"type":"apiKey","in":"cookie","name":"next-auth.session-token","description":"NextAuth session cookie. Authenticate via /api/auth/signin."},"cronSecret":{"type":"http","scheme":"bearer","description":"Static bearer token for internal scheduler routes. Value must match the CRON_SECRET environment variable."}}}}