{"openapi":"3.1.0","info":{"title":"Vishvajeet Shukla Portfolio API","version":"1.0.0","description":"Public, AI-agent-friendly endpoints for the Vishvajeet Shukla portfolio. Use these to programmatically list projects, blog posts, and submit inquiries.","contact":{"name":"Vishvajeet Shukla","url":"https://www.vishvajeetshukla.in/contact","email":"vishvajeet4711@gmail.com"},"license":{"name":"Attribution required","url":"https://www.vishvajeetshukla.in/terms-of-service"}},"servers":[{"url":"https://www.vishvajeetshukla.in","description":"Production"}],"paths":{"/api/projects":{"get":{"summary":"List all production projects (case studies)","description":"Returns Schema.org-typed ItemList of projects with metadata, tech stacks, live URLs, and case study URLs.","operationId":"listProjects","responses":{"200":{"description":"List of projects","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectList"}}}}}}},"/api/posts":{"get":{"summary":"List published blog posts (paginated)","operationId":"listPosts","parameters":[{"name":"tag","in":"query","schema":{"type":"string"},"description":"Filter by tag"},{"name":"lastVisible","in":"query","schema":{"type":"string"},"description":"Cursor for pagination"}],"responses":{"200":{"description":"Paginated blog posts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostList"}}}}}}},"/api/contact":{"post":{"summary":"Submit a contact / hiring inquiry","operationId":"submitContact","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactInput"}}}},"responses":{"200":{"description":"Inquiry accepted and emailed."},"400":{"description":"Missing required fields."},"500":{"description":"Server error."}}}},"/api/indexnow":{"post":{"summary":"Push URLs to IndexNow (Bing/Yandex instant indexing)","operationId":"pingIndexNow","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["urls"],"properties":{"urls":{"type":"array","items":{"type":"string","format":"uri"}}}}}}},"responses":{"200":{"description":"URLs submitted to IndexNow"},"400":{"description":"Bad request"},"500":{"description":"Key not configured"}}}},"/api/indexnow/ping-all":{"post":{"summary":"Push EVERY site URL (static + projects + blog + cities) to IndexNow","description":"Builds the full URL list from sitemap data and submits in 10k chunks. Use after deploy.","operationId":"pingAllIndexNow","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"All URLs submitted"},"401":{"description":"Unauthorized (when INDEXNOW_PING_SECRET set)"},"500":{"description":"Key not configured"}}},"get":{"summary":"Preview the URL list that would be pinged","operationId":"previewPingAll","responses":{"200":{"description":"URL list info"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Set when INDEXNOW_PING_SECRET env is configured"}},"schemas":{"Project":{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"tagline":{"type":"string","nullable":true},"description":{"type":"string"},"url":{"type":"string","format":"uri"},"liveUrl":{"type":"string","format":"uri","nullable":true},"image":{"type":"string","format":"uri","nullable":true},"techStack":{"type":"array","items":{"type":"string"}},"features":{"type":"array","items":{"type":"string"}},"author":{"type":"object","properties":{"name":{"type":"string"},"url":{"type":"string","format":"uri"}}}}},"ProjectList":{"type":"object","properties":{"@context":{"type":"string"},"@type":{"type":"string"},"name":{"type":"string"},"numberOfItems":{"type":"integer"},"itemListElement":{"type":"array","items":{"$ref":"#/components/schemas/Project"}}}},"PostList":{"type":"object","properties":{"posts":{"type":"array","items":{"type":"object"}},"totalPages":{"type":"integer"},"totalPosts":{"type":"integer"},"lastVisible":{"type":"string","nullable":true},"hasMore":{"type":"boolean"}}},"ContactInput":{"type":"object","required":["name","email","subject","message"],"properties":{"name":{"type":"string"},"email":{"type":"string","format":"email"},"phone":{"type":"string","nullable":true},"subject":{"type":"string"},"message":{"type":"string"}}}}}}