{"openapi":"3.0.3","info":{"title":"Sharif Mohammad Nasrullah — Portfolio API","version":"1.0.0","description":"Public API endpoints for the portfolio. All endpoints return JSON. Public endpoints require no authentication. The MCP endpoint at /api/mcp requires a bearer token and exposes 39 tools for content management.","contact":{"name":"Sharif Mohammad Nasrullah","email":"hello@sharif.dev","url":"https://sharif.dev"},"license":{"name":"Proprietary"}},"servers":[{"url":"https://sharif.dev","description":"Production"}],"tags":[{"name":"Health","description":"Health check and monitoring endpoints"},{"name":"Stats","description":"Public portfolio statistics"},{"name":"Content","description":"Public content listings (projects, blog, services, etc.)"},{"name":"Infrastructure","description":"Server metrics and status"},{"name":"Contact","description":"Contact form and newsletter signup"},{"name":"Documentation","description":"API documentation endpoints"},{"name":"Feeds","description":"RSS and JSON feeds for blog posts"},{"name":"Indie Web","description":"Webmention and indie web compatibility endpoints"}],"paths":{"/api/health":{"get":{"tags":["Health"],"summary":"Health check","description":"Lightweight health-check endpoint for Docker, Coolify, and uptime monitors. No DB query.","responses":{"200":{"description":"Server is healthy","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"ok"},"timestamp":{"type":"string","format":"date-time"},"version":{"type":"string","example":"1.0.0"},"uptime":{"type":"integer","description":"Uptime in seconds"},"environment":{"type":"string","example":"production"}}}}}}}}},"/api/stats":{"get":{"tags":["Stats"],"summary":"Portfolio statistics","description":"Public portfolio statistics — content counts, engagement metrics, infrastructure status, and featured projects.","responses":{"200":{"description":"Portfolio statistics","content":{"application/json":{"schema":{"type":"object","properties":{"brand":{"type":"object"},"content":{"type":"object"},"engagement":{"type":"object"},"infrastructure":{"type":"object"},"featuredProjects":{"type":"array"},"generatedAt":{"type":"string","format":"date-time"}}}}}}}}},"/api/projects":{"get":{"tags":["Content"],"summary":"List published projects","description":"List all published case study projects with tech stack, timeline, engagement value, and live URLs.","responses":{"200":{"description":"Array of projects","content":{"application/json":{"schema":{"type":"array"}}}}}}},"/api/blog":{"get":{"tags":["Content"],"summary":"List published blog posts","description":"List all published blog posts with category, tags, reading time, and view counts.","responses":{"200":{"description":"Array of blog posts","content":{"application/json":{"schema":{"type":"array"}}}}}}},"/api/services":{"get":{"tags":["Content"],"summary":"List published services","description":"List all published service offerings with deliverables, pricing, and timelines.","responses":{"200":{"description":"Array of services","content":{"application/json":{"schema":{"type":"array"}}}}}}},"/api/faqs":{"get":{"tags":["Content"],"summary":"List published FAQs","description":"List all published FAQ entries grouped by category.","responses":{"200":{"description":"Array of FAQs","content":{"application/json":{"schema":{"type":"array"}}}}}}},"/api/skills":{"get":{"tags":["Content"],"summary":"List tech skills","description":"List all tech skills grouped by category with proficiency levels.","responses":{"200":{"description":"Array of skills","content":{"application/json":{"schema":{"type":"array"}}}}}}},"/api/server-metrics":{"get":{"tags":["Infrastructure"],"summary":"Server metrics","description":"Live server infrastructure metrics — server name, region, status, latency, uptime, active connections.","responses":{"200":{"description":"Array of server metrics","content":{"application/json":{"schema":{"type":"array"}}}}}}},"/api/docs":{"get":{"tags":["Documentation"],"summary":"API documentation (JSON)","description":"Machine-readable API documentation catalog. Useful for AI agents and integrations discovering the API surface.","responses":{"200":{"description":"API documentation catalog","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/feed.xml":{"get":{"tags":["Feeds"],"summary":"RSS 2.0 feed","description":"RSS 2.0 XML feed for blog posts. Standard format for traditional feed readers. Includes title, link, description, pubDate, and category tags.","responses":{"200":{"description":"RSS 2.0 XML feed","content":{"application/rss+xml":{"schema":{"type":"string"}}}}}}},"/feed.json":{"get":{"tags":["Feeds"],"summary":"JSON Feed 1.1","description":"JSON Feed 1.1 for blog posts. Modern alternative to RSS. Includes title, url, summary, date_published, tags, and reading time.","responses":{"200":{"description":"JSON Feed 1.1 document","content":{"application/feed+json":{"schema":{"type":"object"}}}}}}},"/api/contact":{"post":{"tags":["Contact"],"summary":"Submit contact form","description":"Submit a contact/qualification form. Validates name, email, bottleneck, project type, timeline, and budget. Rate limited.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","email","bottleneck","projectType","timeline","budget"],"properties":{"name":{"type":"string"},"email":{"type":"string","format":"email"},"company":{"type":"string"},"bottleneck":{"type":"string"},"currentStack":{"type":"string"},"projectType":{"type":"string","enum":["MVP","Enterprise Scaling","Audit","Rescue"]},"timeline":{"type":"string"},"budget":{"type":"string"},"message":{"type":"string"}}}}}},"responses":{"200":{"description":"Form submitted successfully"},"400":{"description":"Validation error"},"429":{"description":"Rate limit exceeded"}}}},"/api/newsletter":{"post":{"tags":["Contact"],"summary":"Newsletter signup","description":"Subscribe to the newsletter. Validates email, deduplicates, sets active=true. Rate limited.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"name":{"type":"string"},"source":{"type":"string"}}}}}},"responses":{"200":{"description":"Subscribed successfully"},"400":{"description":"Validation error"},"429":{"description":"Rate limit exceeded"}}}},"/api/webmention":{"post":{"tags":["Indie Web"],"summary":"Receive a Webmention","description":"W3C Webmention endpoint. Receive notifications when another site links to this one. Accepts form-encoded or JSON with source and target URLs. Verifies the link synchronously. Rate limited: 10 req/min.","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","required":["source","target"],"properties":{"source":{"type":"string","format":"uri","description":"URL of the page linking to this site"},"target":{"type":"string","format":"uri","description":"URL on this site that was linked to"}}}},"application/json":{"schema":{"type":"object","required":["source","target"],"properties":{"source":{"type":"string","format":"uri"},"target":{"type":"string","format":"uri"}}}}}},"responses":{"200":{"description":"Webmention received","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["verified","pending"]},"source":{"type":"string"},"target":{"type":"string"},"title":{"type":"string","nullable":true},"message":{"type":"string"}}}}}},"400":{"description":"Missing source or target"},"403":{"description":"Target not on this domain"},"429":{"description":"Rate limit exceeded"}}}},"/api/pingback":{"post":{"tags":["Indie Web"],"summary":"Receive a Pingback","description":"Pingback 1.0 endpoint (XML-RPC fallback to Webmention). Accepts XML-RPC methodCall, JSON, or form-encoded with source and target URLs. Rate limited: 10 req/min.","requestBody":{"required":true,"content":{"text/xml":{"schema":{"type":"string","description":"XML-RPC methodCall with pingback.ping method"}},"application/json":{"schema":{"type":"object","required":["source","target"],"properties":{"source":{"type":"string","format":"uri"},"target":{"type":"string","format":"uri"}}}}}},"responses":{"200":{"description":"Pingback received (XML-RPC methodResponse or JSON)","content":{"text/xml":{"schema":{"type":"string"}},"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"message":{"type":"string"},"source":{"type":"string"},"target":{"type":"string"}}}}}},"400":{"description":"Missing source or target"},"403":{"description":"Target not on this domain"},"429":{"description":"Rate limit exceeded"}}}},"/api/mentions":{"get":{"tags":["Indie Web"],"summary":"List approved mentions","description":"Public list of approved webmentions and pingbacks for a target URL. Only returns mentions that have been approved by an admin.","parameters":[{"name":"target","in":"query","required":true,"description":"The target URL to filter mentions by","schema":{"type":"string","format":"uri"}}],"responses":{"200":{"description":"List of approved mentions","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["webmention","pingback"]},"source":{"type":"string","format":"uri"},"title":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"}}}}}}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"snmcp_","description":"MCP API token. Create at /admin/mcp. Format: snmcp_<43chars>"}}},"externalDocs":{"description":"Human-readable API documentation","url":"https://sharif.dev/docs"}}