{"openapi":"3.0.3","info":{"title":"OpenInfo API","description":"REST API for OpenInfo.no - Access blog posts, team members, services, events, partners, and more. AI agents can request access tokens to use authenticated endpoints.","version":"1.0.0","contact":{"name":"OpenInfo","url":"https:\/\/openinfo.no"}},"servers":[{"url":"https:\/\/openinfo.no\/api","description":"Production"}],"security":[],"paths":{"\/auth\/login":{"post":{"tags":["Authentication"],"summary":"Login and get API token","requestBody":{"required":true,"content":{"application\/json":{"schema":{"type":"object","required":["email","password","device_name"],"properties":{"email":{"type":"string","format":"email"},"password":{"type":"string"},"device_name":{"type":"string","example":"my-agent"}}}}}},"responses":{"200":{"description":"Login successful","content":{"application\/json":{"schema":{"type":"object","properties":{"token":{"type":"string"},"user":{"$ref":"#\/components\/schemas\/User"}}}}}},"422":{"description":"Invalid credentials"}}}},"\/posts":{"get":{"tags":["Blog Posts"],"summary":"List published blog posts","parameters":[{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"per_page","in":"query","schema":{"type":"integer","default":15}},{"name":"status","in":"query","schema":{"type":"string","enum":["all"]},"description":"Use \"all\" with admin auth to see all posts"}],"responses":{"200":{"description":"Paginated list of posts","content":{"application\/json":{"schema":{"$ref":"#\/components\/schemas\/PaginatedPosts"}}}}}},"post":{"tags":["Blog Posts"],"summary":"Create a new blog post","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"$ref":"#\/components\/schemas\/PostInput"}}}},"responses":{"201":{"description":"Post created","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#\/components\/schemas\/Post"}}}}}},"403":{"description":"Admin access required"}}}},"\/posts\/{id}":{"get":{"tags":["Blog Posts"],"summary":"Get a single blog post","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Post details","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#\/components\/schemas\/Post"}}}}}}}},"put":{"tags":["Blog Posts"],"summary":"Update a blog post","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"$ref":"#\/components\/schemas\/PostInput"}}}},"responses":{"200":{"description":"Post updated"},"403":{"description":"Admin access required"}}},"delete":{"tags":["Blog Posts"],"summary":"Delete a blog post","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Post deleted"},"403":{"description":"Admin access required"}}}},"\/team-members":{"get":{"tags":["Team Members"],"summary":"List all active team members","responses":{"200":{"description":"List of team members","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#\/components\/schemas\/TeamMember"}}}}}}}}}},"\/team-members\/{id}":{"get":{"tags":["Team Members"],"summary":"Get a single team member","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Team member details","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#\/components\/schemas\/TeamMember"}}}}}}}}},"\/services":{"get":{"tags":["Services"],"summary":"List all active services\/projects","responses":{"200":{"description":"List of services","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#\/components\/schemas\/Service"}}}}}}}}}},"\/services\/{id}":{"get":{"tags":["Services"],"summary":"Get a single service","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Service details","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#\/components\/schemas\/Service"}}}}}}}}},"\/events":{"get":{"tags":["Events"],"summary":"List published events","parameters":[{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"per_page","in":"query","schema":{"type":"integer","default":15}},{"name":"upcoming","in":"query","schema":{"type":"boolean"},"description":"Filter for upcoming events only"},{"name":"past","in":"query","schema":{"type":"boolean"},"description":"Filter for past events only"}],"responses":{"200":{"description":"Paginated list of events"}}}},"\/events\/{id}":{"get":{"tags":["Events"],"summary":"Get a single event","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Event details","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#\/components\/schemas\/Event"}}}}}}}}},"\/partners":{"get":{"tags":["Partners"],"summary":"List all active partners","responses":{"200":{"description":"List of partners","content":{"application\/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#\/components\/schemas\/Partner"}}}}}}}}}},"\/partners\/{id}":{"get":{"tags":["Partners"],"summary":"Get a single partner","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Partner details"}}}},"\/categories":{"get":{"tags":["Categories & Tags"],"summary":"List all blog categories","responses":{"200":{"description":"List of categories"}}}},"\/tags":{"get":{"tags":["Categories & Tags"],"summary":"List all blog tags","responses":{"200":{"description":"List of tags"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API token obtained via \/auth\/login or agent access request"}},"schemas":{"TranslatedField":{"type":"object","properties":{"en":{"type":"string","description":"English text"},"nb":{"type":"string","description":"Norwegian (Bokm\u00e5l) text"}}},"User":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"email":{"type":"string","format":"email"},"is_admin":{"type":"boolean"}}},"Post":{"type":"object","properties":{"id":{"type":"integer"},"title":{"$ref":"#\/components\/schemas\/TranslatedField"},"slug":{"$ref":"#\/components\/schemas\/TranslatedField"},"excerpt":{"$ref":"#\/components\/schemas\/TranslatedField"},"body":{"$ref":"#\/components\/schemas\/TranslatedField"},"featured_image":{"type":"string","format":"uri","nullable":true},"status":{"type":"string","enum":["draft","published","archived"]},"published_at":{"type":"string","format":"date-time","nullable":true},"meta_title":{"$ref":"#\/components\/schemas\/TranslatedField"},"meta_description":{"$ref":"#\/components\/schemas\/TranslatedField"},"author":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"}},"nullable":true},"categories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"name":{"$ref":"#\/components\/schemas\/TranslatedField"},"slug":{"$ref":"#\/components\/schemas\/TranslatedField"}}}},"tags":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"name":{"$ref":"#\/components\/schemas\/TranslatedField"},"slug":{"$ref":"#\/components\/schemas\/TranslatedField"}}}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"PostInput":{"type":"object","required":["title_en","slug_en","body_en"],"properties":{"title_en":{"type":"string"},"title_nb":{"type":"string"},"slug_en":{"type":"string"},"slug_nb":{"type":"string"},"excerpt_en":{"type":"string"},"excerpt_nb":{"type":"string"},"body_en":{"type":"string"},"body_nb":{"type":"string"},"featured_image":{"type":"string","format":"binary"},"remove_featured_image":{"type":"boolean"},"status":{"type":"string","enum":["draft","published","archived"]},"published_at":{"type":"string","format":"date-time"},"meta_title_en":{"type":"string"},"meta_title_nb":{"type":"string"},"meta_description_en":{"type":"string"},"meta_description_nb":{"type":"string"},"category_ids":{"type":"array","items":{"type":"integer"}},"tag_ids":{"type":"array","items":{"type":"integer"}}}},"PaginatedPosts":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#\/components\/schemas\/Post"}},"current_page":{"type":"integer"},"last_page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"}}},"TeamMember":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"slug":{"type":"string"},"title":{"$ref":"#\/components\/schemas\/TranslatedField"},"bio":{"$ref":"#\/components\/schemas\/TranslatedField"},"photo":{"type":"string","format":"uri","nullable":true},"email":{"type":"string","format":"email","nullable":true},"linkedin":{"type":"string","nullable":true},"sort_order":{"type":"integer"},"is_active":{"type":"boolean"}}},"Service":{"type":"object","properties":{"id":{"type":"integer"},"title":{"$ref":"#\/components\/schemas\/TranslatedField"},"slug":{"$ref":"#\/components\/schemas\/TranslatedField"},"description":{"$ref":"#\/components\/schemas\/TranslatedField"},"body":{"$ref":"#\/components\/schemas\/TranslatedField"},"icon":{"type":"string","format":"uri","nullable":true},"featured_image":{"type":"string","format":"uri","nullable":true},"sort_order":{"type":"integer"},"is_active":{"type":"boolean"}}},"Event":{"type":"object","properties":{"id":{"type":"integer"},"title":{"$ref":"#\/components\/schemas\/TranslatedField"},"slug":{"$ref":"#\/components\/schemas\/TranslatedField"},"description":{"$ref":"#\/components\/schemas\/TranslatedField"},"body":{"$ref":"#\/components\/schemas\/TranslatedField"},"featured_image":{"type":"string","format":"uri","nullable":true},"status":{"type":"string","enum":["draft","published","cancelled","completed"]},"starts_at":{"type":"string","format":"date-time","nullable":true},"ends_at":{"type":"string","format":"date-time","nullable":true},"is_virtual":{"type":"boolean"},"location":{"type":"string","nullable":true},"event_url":{"type":"string","format":"uri","nullable":true},"registration_url":{"type":"string","format":"uri","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Partner":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"slug":{"type":"string"},"logo":{"type":"string","format":"uri","nullable":true},"website_url":{"type":"string","format":"uri","nullable":true},"description":{"$ref":"#\/components\/schemas\/TranslatedField"},"sort_order":{"type":"integer"},"is_active":{"type":"boolean"}}}}}}