{"openapi":"3.0.3","info":{"title":"STJÓRNA API","description":"Multi-tenant product management API (PocketBase). Three tiers derived from the live collection API rules: Public (no auth), Private (authenticated user; the rule restricts records to the caller's tenants), Admin (PocketBase superusers only).","version":"3.1.0","contact":{"name":"STJÓRNA"}},"servers":[{"url":"/api","description":"PocketBase API root"}],"tags":[{"name":"Public","description":"No authentication required"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"},"apiKey":{"type":"http","scheme":"bearer","description":"STJÓRNA API key (stjorna_<prefix>.<secret>)"}},"schemas":{"Error":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"},"data":{"type":"object"}}},"User":{"type":"object","properties":{"id":{"type":"string","readOnly":true},"email":{"type":"string","format":"email"},"emailVisibility":{"type":"boolean"},"verified":{"type":"boolean"},"name":{"type":"string"},"avatar":{"type":"string","description":"File name (upload via multipart/form-data)"},"created":{"type":"string","description":"Date-time, \"YYYY-MM-DD HH:MM:SS.sssZ\"","readOnly":true},"updated":{"type":"string","description":"Date-time, \"YYYY-MM-DD HH:MM:SS.sssZ\"","readOnly":true},"last_tenant":{"type":"string"}}}},"parameters":{"Page":{"name":"page","in":"query","schema":{"type":"integer","default":1}},"PerPage":{"name":"perPage","in":"query","schema":{"type":"integer","default":30}},"Filter":{"name":"filter","in":"query","schema":{"type":"string"}},"Sort":{"name":"sort","in":"query","schema":{"type":"string"}},"Expand":{"name":"expand","in":"query","schema":{"type":"string"}},"Fields":{"name":"fields","in":"query","schema":{"type":"string"}}},"responses":{"Unauthorized":{"description":"Missing or invalid auth token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"Authenticated but not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"BadRequest":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/health":{"get":{"tags":["Public"],"summary":"Health check","responses":{"200":{"description":"Service is healthy","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"integer"},"message":{"type":"string"},"data":{"type":"object"}}}}}}}}},"/collections/users/auth-with-password":{"post":{"tags":["Public"],"summary":"Authenticate a users record (login)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["identity","password"],"properties":{"identity":{"type":"string"},"password":{"type":"string"}}}}}},"responses":{"200":{"description":"Authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string"},"record":{"$ref":"#/components/schemas/User"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"}}}},"/openapi.json":{"get":{"tags":["Public"],"summary":"This OpenAPI document. Anonymous callers get the Public tier, tenant users Public + Private, superusers everything.","responses":{"200":{"description":"OpenAPI 3.0.3 document","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/stjorna/setup-status":{"get":{"tags":["Public"],"summary":"First-run status for the /setup wizard.","responses":{"200":{"description":"Setup status","content":{"application/json":{"schema":{"type":"object","properties":{"superuserExists":{"type":"boolean"},"setupDone":{"type":"boolean"},"setupTokenRequired":{"type":"boolean"},"setupTokenSource":{"type":"string","enum":["env","log"]}}}}}}}}},"/stjorna/setup-bootstrap-superuser":{"post":{"tags":["Public"],"summary":"Create the first superuser. Requires the one-time setup token (STJORNA_SETUP_TOKEN env var or the token printed in the server log) in the X-Stjorna-Setup-Token header. Refuses once a superuser exists or setup is done.","parameters":[{"name":"X-Stjorna-Setup-Token","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string"},"password":{"type":"string"},"passwordConfirm":{"type":"string"}},"required":["email","password","passwordConfirm"]}}}},"responses":{"200":{"description":"Superuser created","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"id":{"type":"string"},"email":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"description":"A superuser already exists or setup is already done"}}}},"/stjorna/oidc-config":{"get":{"tags":["Public"],"summary":"Public OIDC login configuration for the login page (no secrets).","responses":{"200":{"description":"OIDC login configuration","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/stjorna/api-keys/me":{"get":{"tags":["Public"],"summary":"Introspect the bearer API key (Authorization: Bearer stjorna_…).","security":[{"apiKey":[]}],"responses":{"200":{"description":"Tenant + metadata for the verified key","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"tenant":{"type":"string"},"id":{"type":"string"},"prefix":{"type":"string"},"permissions":{"type":"object"},"expires":{"type":"integer","nullable":true,"description":"Epoch ms"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/stjorna/api-keys/exchange":{"post":{"tags":["Public"],"summary":"Exchange an API key (Authorization: Bearer or JSON {key}) for a short-lived, non-refreshable user JWT of the key's service user. Use the JWT for /api/collections/* requests.","security":[{"apiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string"}}}}}},"responses":{"200":{"description":"Short-lived JWT","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"tenant":{"type":"string"},"token":{"type":"string"},"record":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"}}},"permissions":{"type":"object"},"expiresIn":{"type":"integer"},"instructions":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"description":"Key predates the exchange flow; re-issue it"}}}}}}