openapi: 3.1.0 info: title: px0 API description: | px[0] is an open-source prompt infrastructure toolkit for managing prompts in production. It replaces hardcoded prompt strings with versioned templates, in-process caching, and OpenTelemetry observability, so teams can iterate on prompts without touching application code. This is the OpenAPI specification for all the public APIs of px0. version: 1.0.0 servers: - url: http://localhost:3000 description: Local development server paths: /v1/health: get: summary: Health Check description: Verifies that the service is running. operationId: healthCheck tags: - Health responses: '200': description: Service is healthy. content: application/json: schema: type: object properties: status: type: string example: OK required: - status /v1/auth/register: post: summary: Register a new user description: Registers a new user with an email and password. This endpoint can be called unauthenticated to register a new admin, or authenticated (as an admin) to register a standard user into a specific team. operationId: register tags: - Auth security: - {} - BearerAuth: [] x-edge-cases: - Fails with 400 Bad Request if email or password are empty, password is shorter than 8 characters, or password does not meet complexity requirements. - Fails with 400 Bad Request if email format is invalid. - Fails with 409 Conflict if email is already registered. - If admin registers a user (authenticated with Bearer token), they can optionally pass team_id to join an existing team (which must belong to an organization that the admin belongs to). If team_id is not passed, a Default Org and Default Team are created automatically. - If public user registers (unauthenticated), team_id is forbidden. - If Bearer token is provided but is invalid, expired, unverified, or not an admin, returns 401/403 appropriately. x-test-coverage: - 'TestRegister_Success: Verifies standard register returns 201 and User model.' - 'TestRegister_EmptyFields: Verifies empty fields reject with 400 and ''email and password are required''.' - 'TestRegister_ShortPassword: Verifies password shorter than 8 chars rejects with 400 and ''password must be at least 8 characters''.' - 'TestRegister_InvalidEmail: Verifies that invalid email format rejects with 400.' - 'TestRegister_WeakPassword: Verifies that a password without required complexity rejects with 400.' - 'TestRegister_DuplicateEmail: Verifies registering an existing email rejects with 409 and ''email already registered''.' - 'TestRegister_AdminSuccess: Verifies that an admin can successfully register a user into their organization''s team.' - 'TestRegister_AdminInvalidTeam: Verifies 404 if the specified team_id does not exist.' - 'TestRegister_AdminTeamNoOrg: Verifies 400 if the specified team does not belong to any organization.' - 'TestRegister_AdminDifferentOrg: Verifies 403 if the admin caller does not belong to the same organization as the specified team.' - 'TestRegister_PublicForbiddenTeamID: Verifies 403 if a public (unauthenticated) call attempts to pass a team_id.' - 'TestRegister_InvalidToken: Verifies 401 if an invalid Authorization header is provided.' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RegisterRequest' responses: '201': description: User registered successfully content: application/json: schema: type: object properties: user: $ref: '#/components/schemas/User' required: - user '400': description: Invalid inputs content: application/json: schema: $ref: '#/components/schemas/APIError' examples: invalid_body: summary: Invalid JSON body structure value: error: invalid request body missing_fields: summary: Missing email or password value: error: email and password are required short_password: summary: Password is less than 8 characters long value: error: password must be at least 8 characters invalid_email: summary: Invalid email format value: error: invalid email format weak_password: summary: Password lacks complexity value: error: password must contain at least one uppercase letter, one lowercase letter, one digit, and one special character team_no_org: summary: Specified team does not belong to any organization value: error: team does not belong to any organization '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: unauthorized '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/APIError' examples: only_admins_team: summary: Public register with team_id value: error: only admins can register users with a team_id different_org: summary: Admin registering user to different organization value: error: user does not belong to the organization of the specified team user_not_verified: summary: Caller is not verified value: error: user is not verified forbidden_caller: summary: Caller is not an admin value: error: forbidden '404': description: Team Not Found content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: team not found '409': description: Conflict (Email registered) content: application/json: schema: $ref: '#/components/schemas/APIError' examples: duplicate_email: summary: Email is already in use value: error: email already registered '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: internal error /v1/auth/login: post: summary: Login description: Authenticates a user and creates a new access token. operationId: login tags: - Auth x-edge-cases: - Accepts JSON body. Session duration is configurable via SESSION_DURATION_HOURS environment variable (defaults to 24 hours). x-test-coverage: - 'TestLogin_Success: Verifies successful authentication and returns a token and expiry.' - 'TestLogin_InvalidCredentials: Verifies that incorrect passwords or emails reject with 401 and ''invalid credentials''.' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/LoginRequest' responses: '200': description: Login successful content: application/json: schema: type: object properties: token: type: string description: The access token to be used in standard Bearer authentication. example: f47ac10b-58cc-4372-a567-0e02b2c3d479 expires_at: type: string format: date-time description: The timestamp when this access token expires. user: $ref: '#/components/schemas/User' required: - token - expires_at - user '400': description: Invalid request body content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: invalid request body '401': description: Invalid credentials content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: invalid credentials '403': description: User is not verified content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: user is not verified '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: internal error /v1/auth/verify-email: post: summary: Verify User Email description: Verifies a user's email address using a numeric code sent via email. operationId: verifyEmail tags: - Auth x-edge-cases: - Fails with 400 Bad Request if verification code is invalid or expired. x-test-coverage: - 'TestRegister_AndVerifyFlow: Verifies the complete user verification flow.' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/VerifyRequest' responses: '200': description: Email verified successfully content: application/json: schema: type: object properties: message: type: string example: email verified successfully required: - message '400': description: Invalid code or expired code content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: invalid verification code '401': description: User not found content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: invalid credentials '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: internal error get: summary: Trigger Verification Email description: Triggers a new email verification code and sends it to the user's email. operationId: triggerVerificationEmail tags: - Auth parameters: - name: email in: query required: true schema: type: string format: email description: The user's email address to trigger verification for. x-edge-cases: - Fails with 400 Bad Request if email query parameter is missing. - Fails with 400 Bad Request if user is already verified. - Fails with 404 Not Found if user is not found. x-test-coverage: - 'TestTriggerVerification: Verifies triggering a verification email.' responses: '200': description: Verification email sent successfully content: application/json: schema: type: object properties: message: type: string example: verification email sent successfully required: - message '400': description: Missing email, invalid email, or user already verified content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: email is required '404': description: User not found content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: user not found '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: internal error /v1/auth/session: delete: summary: Logout description: Destroys the active access token, logging the user out. operationId: logout tags: - Auth security: - BearerAuth: [] x-edge-cases: - If Bearer token is missing, the route returns 204 directly without throwing errors. x-test-coverage: - 'TestLogout_Success: Verifies standard 204 response and session deletion.' responses: '204': description: Logged out successfully (No content) /v1/auth/me: get: summary: Me description: Returns the profile of the currently logged-in user. operationId: me tags: - Profile security: - BearerAuth: [] x-test-coverage: - 'TestMe_WithSession: Verifies self profile lookup.' responses: '200': description: User profile content: application/json: schema: type: object properties: user: $ref: '#/components/schemas/User' required: - user '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: unauthorized put: summary: Update Me description: Updates the profile of the currently logged-in user. operationId: updateMe tags: - Profile security: - BearerAuth: [] x-test-coverage: - 'TestUpdateMe: Verifies that updating user profile succeeds.' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateMeRequest' responses: '200': description: User profile updated successfully content: application/json: schema: type: object properties: user: $ref: '#/components/schemas/User' required: - user '400': description: Invalid email format or missing fields content: application/json: schema: $ref: '#/components/schemas/APIError' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '409': description: Email already taken content: application/json: schema: $ref: '#/components/schemas/APIError' delete: summary: Delete Me description: Deletes the currently logged-in user's account. operationId: deleteMe tags: - Profile security: - BearerAuth: [] x-test-coverage: - 'TestDeleteMe: Verifies that deleting a user account succeeds.' responses: '204': description: Account deleted successfully '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/auth/me/change-password: post: summary: Change Password description: Changes the currently logged-in user's password. operationId: changePassword tags: - Profile security: - BearerAuth: [] x-test-coverage: - 'TestChangePassword: Verifies changing authenticated password.' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ChangePasswordRequest' responses: '200': description: Password changed successfully content: application/json: schema: type: object properties: message: type: string example: password changed successfully required: - message '400': description: Password too short or too weak content: application/json: schema: $ref: '#/components/schemas/APIError' '401': description: Unauthorized or invalid current password content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/auth/password-reset/trigger: post: summary: Trigger Password Reset description: Generates a password reset code and sends it via email to the user. operationId: triggerPasswordReset tags: - Auth x-edge-cases: - Fails with 400 Bad Request if email is missing. - Fails with 404 Not Found if user with specified email does not exist. x-test-coverage: - 'TestPasswordReset_Flow: Verifies triggering password reset and completing it successfully.' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/TriggerPasswordResetRequest' responses: '200': description: Password reset email sent successfully content: application/json: schema: type: object properties: message: type: string example: password reset email sent successfully required: - message '400': description: Missing email content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: email is required '404': description: User not found content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: user not found '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: internal error /v1/auth/password-reset/reset: post: summary: Reset Password description: Resets a user's password using a valid reset code and a new password, deriving the user from the code in the database. operationId: resetPassword tags: - Auth x-edge-cases: - Fails with 400 Bad Request if code or new password is empty. - Fails with 400 Bad Request if new password is too short or too weak. - Fails with 400 Bad Request if reset code is invalid or expired. x-test-coverage: - 'TestPasswordReset_Flow: Verifies complete password reset flow.' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ResetPasswordRequest' responses: '200': description: Password reset successfully content: application/json: schema: type: object properties: message: type: string example: password reset successfully email: type: string format: email example: user@example.com required: - message - email '400': description: Invalid input or invalid/expired code content: application/json: schema: $ref: '#/components/schemas/APIError' examples: missing_fields: summary: Missing code or password value: error: code and new_password are required short_password: summary: Password too short value: error: password must be at least 8 characters weak_password: summary: Password lacks complexity value: error: password must contain at least one uppercase letter, one lowercase letter, one digit, and one special character invalid_code: summary: Reset code is invalid or expired value: error: invalid or expired password reset code '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: internal error /v1/api-keys: post: summary: Create an API Key description: | Generates a new programmatic API key for accessing authorized resources. The full, secret API key is returned ONLY once in this response and cannot be recovered later. operationId: createAPIKey tags: - API Keys security: - BearerAuth: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateAPIKeyRequest' responses: '201': description: API key created successfully content: application/json: schema: $ref: '#/components/schemas/APIKeyCreatedResponse' '400': description: Invalid request content: application/json: schema: $ref: '#/components/schemas/APIError' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/APIError' '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/APIError' get: summary: List API Keys description: Lists metadata for all programmatic API keys. Secret key values are omitted. operationId: listAPIKeys tags: - API Keys security: - BearerAuth: [] parameters: - name: org_id in: query required: true schema: type: string format: uuid responses: '200': description: List of API keys content: application/json: schema: type: object properties: api_keys: type: array items: $ref: '#/components/schemas/APIKey' required: - api_keys '400': description: Bad Request '401': description: Unauthorized '403': description: Forbidden '500': description: Internal Server Error /v1/api-keys/{id}: delete: summary: Delete an API Key description: Revokes and permanently deletes an API key by its unique UUID. operationId: deleteAPIKey tags: - API Keys security: - BearerAuth: [] parameters: - name: id in: path required: true description: The unique UUID of the API Key to delete. schema: type: string format: uuid responses: '204': description: API key successfully deleted '400': description: Invalid UUID format '401': description: Unauthorized '403': description: Forbidden '404': description: API key not found '500': description: Internal Server Error /v1/me/teams: get: summary: List User Teams description: Returns a list of teams the authenticated user belongs to. operationId: listUserTeams tags: - Profile security: - BearerAuth: [] responses: '200': description: A list of teams content: application/json: schema: type: object properties: teams: type: array items: $ref: '#/components/schemas/Team' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/me/teams/{teamID}: delete: summary: Leave Team description: Allows the authenticated user to voluntarily leave a team they belong to. operationId: leaveTeam tags: - Teams security: - BearerAuth: [] parameters: - name: teamID in: path required: true schema: type: string format: uuid responses: '204': description: Left team successfully (No Content) '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '404': description: Team not found or user not a member of the team content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/me/orgs: get: summary: List User Organizations description: Returns a list of organizations the authenticated user belongs to. operationId: listUserOrgs tags: - Profile security: - BearerAuth: [] responses: '200': description: A list of organizations with roles content: application/json: schema: type: object properties: organizations: type: array items: $ref: '#/components/schemas/OrganizationWithRole' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/me/inbox: get: summary: Get Admin Inbox description: Returns a list of pending join requests that the authenticated user is authorized to approve or reject. operationId: getAdminInbox tags: - Inbox security: - BearerAuth: [] x-edge-cases: - Only returns pending join requests for teams where the user is an admin or is a system admin. - Returns a generic inbox item containing the `type` property as 'join_request' and an embedded `team` object. x-test-coverage: - 'TestJoinRequestsFlow: Verifies that the created team join request is properly listed in the admin''s inbox, showing correct embedded team details and user email.' responses: '200': description: A list of pending join requests content: application/json: schema: type: object properties: inbox: type: array items: $ref: '#/components/schemas/InboxItem' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/orgs/{orgID}/teams: post: summary: Create Team description: Creates a new team under a specific organization. Requires Org Admin privileges (admin on the Default Team). Team admins or editors of other custom teams are not authorized to create teams. operationId: createTeam tags: - Team Management security: - BearerAuth: [] x-edge-cases: - Requires Org Admin privileges (admin on the Default Team). - Team admins or editors of other custom teams are forbidden from creating teams. - Fails with 400 if name is empty. - Fails with 409 if the team name already exists under the target organization. x-test-coverage: - 'TestRolesAndPermissions: Verifies that a Team Admin of a custom team is forbidden from creating a team (returns 403 Forbidden).' - 'TestRolesAndPermissions: Verifies that an Org Admin (admin of Default Team) can create a team (returns 201 Created).' parameters: - name: orgID in: path required: true schema: type: string format: uuid description: The ID of the organization to create the team under. requestBody: required: true content: application/json: schema: type: object required: - name properties: name: type: string example: Engineering responses: '201': description: Created content: application/json: schema: type: object properties: team: $ref: '#/components/schemas/Team' '400': description: Bad Request content: application/json: schema: $ref: '#/components/schemas/APIError' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/APIError' get: summary: List Org Teams description: Returns a list of all teams within the specified organization. operationId: listOrgTeams tags: - Team Management security: - BearerAuth: [] parameters: - name: orgID in: path required: true schema: type: string format: uuid description: The ID of the organization to list teams for. responses: '200': description: A list of teams content: application/json: schema: type: object properties: teams: type: array items: $ref: '#/components/schemas/Team' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/teams/{id}: put: summary: Update Team description: Updates an existing team. Requires Org Admin, Team Admin, or Team Editor privileges. Team Members (viewers) are not authorized. operationId: updateTeam tags: - Team Management security: - BearerAuth: [] x-edge-cases: - Requires Org Admin, Team Admin, or Team Editor privileges. - Team Members (viewers) are forbidden from updating team details. - Returns 404 if the team does not exist. - Returns 409 if the updated team name already exists under the target organization. x-test-coverage: - 'TestRolesAndPermissions: Verifies that a Viewer (Team Member) cannot update a team (returns 403 Forbidden).' - 'TestRolesAndPermissions: Verifies that an Editor (Team Editor) can update a team (returns 200 OK).' - 'TestRolesAndPermissions: Verifies that an Admin (Team Admin) can update a team (returns 200 OK).' parameters: - name: id in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: type: object required: - name properties: name: type: string example: Engineering org_id: type: string format: uuid example: f47ac10b-58cc-4372-a567-0e02b2c3d479 responses: '200': description: Updated content: application/json: schema: type: object properties: team: $ref: '#/components/schemas/Team' '400': description: Bad Request content: application/json: schema: $ref: '#/components/schemas/APIError' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/APIError' '404': description: Not Found content: application/json: schema: $ref: '#/components/schemas/APIError' delete: summary: Delete Team description: Deletes an existing team. Requires Org Admin, Team Admin, or Team Editor privileges. Team Members (viewers) are not authorized. operationId: deleteTeam tags: - Team Management security: - BearerAuth: [] x-edge-cases: - Requires Org Admin, Team Admin, or Team Editor privileges. - Team Members (viewers) are forbidden from deleting the team. - Returns 404 if the team does not exist. x-test-coverage: - 'TestRolesAndPermissions: Verifies that a Viewer (Team Member) cannot delete a team (returns 403 Forbidden).' - 'TestRolesAndPermissions: Verifies that an Editor (Team Editor) can delete a team (returns 204 No Content).' - 'TestRolesAndPermissions: Verifies that an Admin (Team Admin) can delete a team (returns 204 No Content).' parameters: - name: id in: path required: true schema: type: string format: uuid responses: '204': description: Team deleted successfully '401': description: Unauthorized '403': description: Forbidden '404': description: Not Found /v1/teams/{id}/members: get: summary: List Team Members description: Returns a paginated list of members for a given team. Requires at least viewer access. operationId: listTeamMembers tags: - User Management security: - BearerAuth: [] parameters: - name: id in: path required: true schema: type: string format: uuid - name: page in: query required: false schema: type: integer default: 1 responses: '200': description: Paginated list of members content: application/json: schema: type: object properties: members: type: array items: $ref: '#/components/schemas/TeamMemberResponse' page: type: integer limit: type: integer total: type: integer '400': description: Bad Request '401': description: Unauthorized '403': description: Forbidden post: summary: Add Team Member description: Adds a user to a team. Requires admin privileges. operationId: addTeamMember tags: - User Management security: - BearerAuth: [] parameters: - name: id in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: type: object required: - user_id properties: user_id: type: string format: uuid responses: '204': description: No Content '400': description: Bad Request '401': description: Unauthorized '403': description: Forbidden /v1/teams/{id}/members/{userID}: delete: summary: Remove Team Member description: Removes a user from a team. Requires admin privileges. operationId: removeTeamMember tags: - User Management security: - BearerAuth: [] parameters: - name: id in: path required: true schema: type: string format: uuid - name: userID in: path required: true schema: type: string format: uuid responses: '204': description: No Content '400': description: Bad Request '401': description: Unauthorized '403': description: Forbidden /v1/teams/{id}/members/{userID}/role: put: summary: Update Team Member Role description: Updates a team member's role. Requires team admin privileges. operationId: updateTeamMemberRole tags: - User Management security: - BearerAuth: [] parameters: - name: id in: path required: true schema: type: string format: uuid - name: userID in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: type: object required: - role properties: role: type: string enum: - admin - editor - viewer example: admin responses: '200': description: Role updated successfully content: application/json: schema: type: object properties: message: type: string '400': description: Bad Request '401': description: Unauthorized '403': description: Forbidden '404': description: Not Found /v1/teams/{id}/join-requests: post: summary: Request to Join Team description: Creates a pending request for the authenticated user to join a specific team. operationId: createJoinRequest tags: - Teams security: - BearerAuth: [] parameters: - name: id in: path required: true schema: type: string format: uuid description: The ID of the team to request to join. responses: '201': description: Join request created successfully content: application/json: schema: $ref: '#/components/schemas/TeamJoinRequest' '400': description: Bad Request (already a member) content: application/json: schema: $ref: '#/components/schemas/APIError' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '404': description: Team Not Found content: application/json: schema: $ref: '#/components/schemas/APIError' '409': description: Conflict (already has a pending request) content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/join-requests/{id}: put: summary: Resolve Join Request description: Approves or rejects a pending join request. operationId: resolveJoinRequest tags: - Inbox security: - BearerAuth: [] parameters: - name: id in: path required: true schema: type: string format: uuid description: The ID of the join request to resolve. requestBody: required: true content: application/json: schema: type: object required: - status properties: status: type: string enum: - approved - rejected example: approved x-edge-cases: - Only authorized admins of the team can approve or reject the request. - Join request must be in pending status to be resolved. x-test-coverage: - 'TestJoinRequestsFlow: Verifies that a join request can be approved, updating the user''s role and membership.' responses: '200': description: Resolved request details content: application/json: schema: $ref: '#/components/schemas/TeamJoinRequest' '400': description: Bad Request content: application/json: schema: $ref: '#/components/schemas/APIError' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '403': description: Forbidden (not authorized to approve) content: application/json: schema: $ref: '#/components/schemas/APIError' '404': description: Join Request Not Found content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/orgs: post: summary: Create Organization description: Creates a new organization. Requires admin privileges. operationId: createOrg tags: - Organizations security: - BearerAuth: [] requestBody: required: true content: application/json: schema: type: object required: - name properties: name: type: string example: Acme Corp responses: '201': description: Created content: application/json: schema: type: object properties: org: $ref: '#/components/schemas/Organization' '400': description: Bad Request content: application/json: schema: $ref: '#/components/schemas/APIError' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/orgs/{id}: put: summary: Update Organization description: Updates an existing organization's metadata. Requires admin privileges. operationId: updateOrg tags: - Organizations security: - BearerAuth: [] parameters: - name: id in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: type: object required: - name properties: name: type: string example: Acme Industries responses: '200': description: Updated successfully content: application/json: schema: type: object properties: org: $ref: '#/components/schemas/Organization' '400': description: Bad Request content: application/json: schema: $ref: '#/components/schemas/APIError' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/APIError' '404': description: Not Found content: application/json: schema: $ref: '#/components/schemas/APIError' delete: summary: Delete Organization description: Deletes an organization and all cascading dependencies. Requires Org Admin. operationId: deleteOrg tags: - Organizations security: - BearerAuth: [] parameters: - name: id in: path required: true schema: type: string format: uuid responses: '204': description: Deleted successfully (No Content) '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/APIError' '404': description: Not Found content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/orgs/{orgID}/people: get: summary: List Org People description: Returns a paginated list of distinct people who are members of any team in the organization. operationId: listOrgPeople tags: - Organizations security: - BearerAuth: [] parameters: - name: orgID in: path required: true schema: type: string format: uuid description: The ID of the organization to list people for. - name: page in: query required: false schema: type: integer default: 1 - name: limit in: query required: false schema: type: integer default: 10 responses: '200': description: Paginated list of people content: application/json: schema: type: object required: - people - page - limit - total properties: people: type: array items: $ref: '#/components/schemas/User' page: type: integer limit: type: integer total: type: integer '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/APIError' '404': description: Organization Not Found content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/orgs/{orgID}/members/{userID}: delete: summary: Remove Member from Organization description: Removes a user from an organization by removing them from all teams in that organization. Requires Org Admin privileges. operationId: removeOrgMember tags: - Organizations security: - BearerAuth: [] x-edge-cases: - Only Org Admins and system administrators can remove members from an organization. - Returns 403 Forbidden if a standard user tries to remove a member. - Returns 404 Not Found if the user is not a member of the organization. x-test-coverage: - 'TestOrg_RemoveMember: Verifies that an Org Admin can successfully remove a member from the organization, removing them from all teams.' - 'TestOrg_RemoveMember: Verifies that a standard user cannot remove a member (returns 403 Forbidden).' - 'TestOrg_RemoveMember: Verifies that removing a user who is not a member of the organization returns 404 Not Found.' parameters: - name: orgID in: path required: true schema: type: string format: uuid description: The ID of the organization. - name: userID in: path required: true schema: type: string format: uuid description: The ID of the user to remove from the organization. responses: '204': description: User successfully removed from the organization '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/APIError' '404': description: Not Found content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/teams/{teamID}/prompts: post: summary: Create a Prompt description: Creates a new prompt container. operationId: createPrompt tags: - Prompts security: - BearerAuth: [] parameters: - name: teamID in: path required: true schema: type: string format: uuid description: The ID of the team. x-test-coverage: - 'TestCreatePrompt_Success: Verifies prompt creation and response payload.' - 'TestCreatePrompt_MissingName: Verifies that missing name returns 400 and ''name is required''.' - 'TestCreatePrompt_Unauthorized: Verifies that unauthenticated request returns 401.' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreatePromptRequest' responses: '201': description: Prompt created successfully content: application/json: schema: type: object properties: prompt: $ref: '#/components/schemas/Prompt' required: - prompt '400': description: Invalid request content: application/json: schema: $ref: '#/components/schemas/APIError' examples: invalid_body: value: error: invalid request body name_required: value: error: name is required '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: unauthorized '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: internal error get: summary: List Prompts description: Lists all available prompt containers. operationId: listPrompts tags: - Prompts security: - BearerAuth: [] parameters: - name: teamID in: path required: true schema: type: string format: uuid description: The ID of the team. - name: archived in: query required: false description: Optional boolean to filter prompts by archive state. schema: type: boolean x-test-coverage: - 'TestListPrompts: Verifies listing populated prompt containers.' - 'TestListPrompts_Empty: Verifies that listing when empty returns an empty array.' responses: '200': description: List of prompts content: application/json: schema: type: object properties: prompts: type: array items: $ref: '#/components/schemas/Prompt' required: - prompts '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: unauthorized '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: internal error /v1/prompts: get: summary: List all prompts with team filter description: Returns a list of prompts. If team_id query parameter is not provided, returns an empty list by default. Users can filter by a team they are a member of. operationId: listAllPrompts tags: - Prompts security: - BearerAuth: [] parameters: - name: team_id in: query required: false description: Optional UUID of the team to filter prompts (alias of team). schema: type: string format: uuid - name: team in: query required: false description: Optional UUID of the team to filter prompts (alias of team_id). schema: type: string format: uuid - name: archived in: query required: false description: Optional boolean to filter prompts by archive state. schema: type: boolean x-edge-cases: - By default with no team_id query parameter, returns an empty list of prompts. - If a team_id is provided, checks if the user is a member of that team, otherwise returns 403 Forbidden. x-test-coverage: - 'TestListAllPrompts: Verifies that no team_id returns 200 with an empty list.' - 'TestListAllPrompts: Verifies that a valid team_id returns 200 with prompts of that team.' - 'TestListAllPrompts: Verifies that an unallowed team_id returns 403 Forbidden.' responses: '200': description: A list of prompts content: application/json: schema: type: object properties: prompts: type: array items: $ref: '#/components/schemas/Prompt' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/APIError' '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/prompts/{id}: get: summary: Get a Prompt description: Returns details of a specific prompt container by its unique UUID or unique slug. Optionally retrieves version or tag details if requested via query parameters. operationId: getPrompt tags: - Prompts security: - BearerAuth: [] parameters: - name: id in: path required: true description: The unique UUID or unique slug of the prompt. schema: type: string - name: version in: query required: false description: Optional version sequence number (integer) or version tag (string) to retrieve along with the prompt details. schema: type: string - name: tag in: query required: false description: Optional version tag (string) to retrieve along with the prompt details. schema: type: string x-test-coverage: - 'TestGetPrompt_Success: Verifies finding a prompt by ID.' - 'TestGetPrompt_BySlugAndVersion: Verifies finding a prompt by slug, with version, and with tag query parameter.' - 'TestGetPrompt_NotFound: Verifies 404 response on missing prompt ID.' responses: '200': description: Prompt details content: application/json: schema: type: object properties: prompt: $ref: '#/components/schemas/Prompt' version: $ref: '#/components/schemas/PromptVersion' required: - prompt '400': description: Invalid UUID format content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: invalid prompt id '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: unauthorized '404': description: Prompt not found content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: prompt not found '500': description: Internal error content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: internal error put: summary: Update a Prompt description: Updates the description of a specific prompt by its unique UUID. operationId: updatePrompt tags: - Prompts security: - BearerAuth: [] parameters: - name: id in: path required: true description: The unique UUID of the prompt. schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdatePromptRequest' x-edge-cases: - 'Forbidden: Attempting to update a prompt with viewer permissions.' - 'NotFound: Attempting to update a non-existent prompt ID or a prompt under an unauthorized team.' x-test-coverage: - 'TestUpdatePrompt_Success: Verifies updating description with editor token.' - 'TestUpdatePrompt_ViewerForbidden: Verifies viewer gets a 403 response.' - 'TestUpdatePrompt_NotFound: Verifies 404 response on missing prompt ID.' responses: '200': description: Prompt updated successfully content: application/json: schema: type: object properties: prompt: $ref: '#/components/schemas/Prompt' required: - prompt '400': description: Invalid input or invalid UUID format content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: invalid request body '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: unauthorized '403': description: Forbidden - Viewer or unauthorized team member content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: forbidden '404': description: Prompt not found content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: prompt not found '500': description: Internal error content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/prompts/{id}/archive: post: summary: Archive a Prompt description: Archives a specific prompt container, setting `status` to 'archived'. The prompt still exists in the system and people can call it and use it, so a prompt is never deleted. Requires Org Admin or Team Admin privileges (GitHub repo owner model). Team Editors and Team Members are not authorized to archive prompts. operationId: archivePrompt tags: - Prompts security: - BearerAuth: [] x-edge-cases: - Only Org Admins and Team Admins can archive a prompt. - Team Editors and Team Members (viewers) are forbidden from archiving prompts. x-test-coverage: - 'TestArchivePrompt_Permissions: Verifies that a Team Member (viewer) cannot archive a prompt (returns 403 Forbidden).' - 'TestArchivePrompt_Permissions: Verifies that a Team Editor cannot archive a prompt (returns 403 Forbidden).' - 'TestArchivePrompt_Permissions: Verifies that a Team Admin can successfully archive a prompt (returns 200 OK with prompt details).' parameters: - name: id in: path required: true description: The unique UUID of the prompt to archive. schema: type: string format: uuid responses: '200': description: Prompt successfully archived content: application/json: schema: type: object properties: prompt: $ref: '#/components/schemas/Prompt' required: - prompt '400': description: Invalid UUID format content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: invalid prompt id '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: unauthorized '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: forbidden '404': description: Prompt not found content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: prompt not found '500': description: Internal error content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: internal error /v1/prompts/{id}/restore: post: summary: Restore a Prompt description: Restores a previously archived prompt setting `status` back to 'active'. Requires Team Admin or Org Admin. operationId: restorePrompt tags: - Prompts security: - BearerAuth: [] parameters: - name: id in: path required: true schema: type: string format: uuid responses: '200': description: Prompt successfully restored content: application/json: schema: type: object properties: prompt: $ref: '#/components/schemas/Prompt' required: - prompt '400': description: Invalid UUID format content: application/json: schema: $ref: '#/components/schemas/APIError' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/APIError' '404': description: Prompt not found content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/prompts/{id}/move: post: summary: Move a Prompt description: Moves a prompt from its current team to another team. Requires admin privileges on both teams. operationId: movePrompt tags: - Prompts security: - BearerAuth: [] parameters: - name: id in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: type: object required: - team_id properties: team_id: type: string format: uuid responses: '200': description: Prompt successfully moved content: application/json: schema: type: object properties: prompt: $ref: '#/components/schemas/Prompt' required: - prompt '400': description: Invalid UUID format or team_id content: application/json: schema: $ref: '#/components/schemas/APIError' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/APIError' '404': description: Prompt not found content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/prompts/{id}/versions/diff: get: summary: Diff Prompt Versions description: Compares the templates of two prompt versions side-by-side and returns a unified diff. Requires read access to the prompt. operationId: diffVersions tags: - Prompt Versions security: - BearerAuth: [] parameters: - name: id in: path required: true schema: type: string format: uuid - name: from in: query required: true schema: type: integer description: The source version number to compare from. - name: to in: query required: true schema: type: integer description: The target version number to compare to. responses: '200': description: Versions compared successfully content: application/json: schema: type: object properties: from_version: type: integer example: 1 to_version: type: integer example: 2 from_template: type: string example: Hello {{ .name }} to_template: type: string example: |- Hello {{ .name }}! Welcome to px0. diff: type: string example: | --- v1 +++ v2 @@ -1 +1,2 @@ -Hello {{ .name }} +Hello {{ .name }}! +Welcome to px0. required: - from_version - to_version - from_template - to_template - diff '400': description: Missing or invalid parameters content: application/json: schema: $ref: '#/components/schemas/APIError' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '404': description: Prompt or version not found content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/prompts/{slug}/render: post: summary: Render Live Prompt Version description: Renders the active 'live' template version of a prompt using supplied variables. operationId: renderLive tags: - Prompt Renders security: - BearerAuth: [] parameters: - name: slug in: path required: true description: Unique prompt slug. schema: type: string x-edge-cases: - Fails with 404 if no live version is found. - Fails with 422 if template execution fails due to invalid parameters or template syntax mismatches. x-test-coverage: - 'TestRenderLive_Success: Verifies rendering with complete variables returning 200 OK.' - 'TestRenderLive_NoLiveVersion: Verifies that requesting a render with only ''draft'' versions fails with 404 and ''no live version found for this prompt''.' - 'TestRenderLive_NoVariables: Verifies static templates render correctly when empty variables are supplied.' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RenderRequest' responses: '200': description: Rendered template string content: application/json: schema: $ref: '#/components/schemas/RenderResponse' '400': description: Invalid slug or bad body JSON content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: invalid prompt slug '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: unauthorized '404': description: Prompt or live version not found content: application/json: schema: $ref: '#/components/schemas/APIError' examples: prompt_not_found: value: error: prompt not found no_live_version: value: error: no live version found for this prompt '422': description: Render execution failed content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: 'template execution failed: ...' '500': description: Internal error content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: internal error /v1/prompts/{id}/versions: post: summary: Create a Prompt Version description: Creates a new version of the prompt template in 'draft' state. operationId: createVersion tags: - Prompt Versions security: - BearerAuth: [] parameters: - name: id in: path required: true description: Unique prompt UUID. schema: type: string format: uuid x-edge-cases: - Validates template string syntax using Go's text/template parser before creating the entry. x-test-coverage: - 'TestCreateVersion_Success: Verifies version number is incremented to draft status 1.' - 'TestCreateVersion_InvalidTemplate: Verifies syntax check fails with 400 and ''invalid template''.' - 'TestCreateVersion_MissingTemplate: Verifies missing template rejects with 400 and ''template is required''.' - 'TestCreateVersion_PromptNotFound: Verifies 404 response on missing parent prompt UUID.' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateVersionRequest' responses: '201': description: Version created successfully content: application/json: schema: type: object properties: version: $ref: '#/components/schemas/PromptVersion' required: - version '400': description: Invalid template or syntax error content: application/json: schema: $ref: '#/components/schemas/APIError' examples: missing_template: value: error: template is required syntax_error: value: error: 'invalid template: template parse error...' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: unauthorized '404': description: Prompt not found content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: prompt not found '500': description: Internal error content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: internal error get: summary: List Prompt Versions description: Lists all template versions associated with a prompt container. operationId: listVersions tags: - Prompt Versions security: - BearerAuth: [] parameters: - name: id in: path required: true description: Unique prompt UUID. schema: type: string format: uuid - name: tags in: query required: false description: Optional comma-separated list of tags to filter prompt versions. schema: type: string - name: status in: query required: false description: Optional status to filter prompt versions by (draft, live, archived). schema: type: string enum: - draft - live - archived x-test-coverage: - 'TestListVersions: Verifies active versions listing.' responses: '200': description: List of versions content: application/json: schema: type: object properties: versions: type: array items: $ref: '#/components/schemas/PromptVersion' required: - versions '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: unauthorized '404': description: Prompt not found content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: prompt not found /v1/prompts/{id}/versions/{version}: get: summary: Get Prompt Version description: Retrieves details of a specific prompt template version by version number. operationId: getVersion tags: - Prompt Versions security: - BearerAuth: [] parameters: - name: id in: path required: true description: Unique prompt UUID. schema: type: string format: uuid - name: version in: path required: true description: Version sequence number (integer) or version tag (string). schema: type: string x-test-coverage: - 'TestGetVersion: Verifies details retrieval of specific version.' - 'TestGetVersion_NotFound: Verifies 404 response on missing version sequence number.' responses: '200': description: Prompt version details content: application/json: schema: type: object properties: version: $ref: '#/components/schemas/PromptVersion' required: - version '400': description: Invalid path formatting content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: invalid version number '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: unauthorized '404': description: Version not found content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: version not found put: summary: Update Prompt Version Draft description: | Updates the draft template code of a specific version. Only versions currently in the 'draft' status may be modified. operationId: updateVersion tags: - Prompt Versions security: - BearerAuth: [] parameters: - name: id in: path required: true description: Unique prompt UUID. schema: type: string format: uuid - name: version in: path required: true description: Version sequence number (integer) or version tag (string) to update. schema: type: string x-edge-cases: - Fails with 422 Unprocessable Entity if the version status is not 'draft' (e.g. attempting to update a live/archived template). x-test-coverage: - 'TestUpdateVersion_Draft: Verifies modification updates template content and returns 200.' - 'TestUpdateVersion_LiveVersionRejected: Verifies that updating a published live template version fails with 422 and ''only draft versions can be modified''.' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateVersionRequest' responses: '200': description: Version updated successfully content: application/json: schema: type: object properties: version: $ref: '#/components/schemas/PromptVersion' required: - version '400': description: Invalid syntax or missing template content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: template is required '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: unauthorized '404': description: Version not found content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: version not found '422': description: Only draft versions can be modified content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: only draft versions can be modified delete: summary: Delete Prompt Version Draft description: | Deletes a specific prompt template version. Only versions currently in the 'draft' status may be deleted. operationId: deletePromptVersion tags: - Prompt Versions security: - BearerAuth: [] parameters: - name: id in: path required: true description: Unique prompt UUID. schema: type: string format: uuid - name: version in: path required: true description: Version sequence number (integer) or version tag (string) to delete. schema: type: string x-edge-cases: - Fails with 422 Unprocessable Entity if the version status is not 'draft' (e.g. attempting to delete a live/archived template). x-test-coverage: - 'TestDeleteVersion_Draft: Verifies deletion of specific draft version returns 204.' - 'TestDeleteVersion_LiveVersionRejected: Verifies that deleting a published live template version fails with 422 and ''only draft versions can be deleted''.' responses: '204': description: Version deleted successfully '400': description: Invalid path formatting content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: invalid version number '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: unauthorized '404': description: Version not found content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: version not found '422': description: Only draft versions can be deleted content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: only draft versions can be deleted /v1/prompts/{id}/versions/{version}/promote: post: summary: Promote Prompt Version description: | Promotes a version of the prompt template along the lifecycle: draft -> stable -> live. Promoting from draft makes it stable (read-only). Promoting from stable makes it live. When promoting a version to live, any previous live version is demoted to stable. operationId: promoteVersion tags: - Prompt Versions security: - BearerAuth: [] parameters: - name: id in: path required: true description: Unique prompt UUID. schema: type: string format: uuid - name: version in: path required: true description: Version sequence number (integer) or version tag (string) to promote. schema: type: string x-edge-cases: - Promotes draft to stable, or stable to live. - Switches previous live versions to stable status automatically. - Returns 422 if the specified version is already live or archived. x-test-coverage: - 'TestPromoteVersion: Verifies promotion path draft -> stable -> live.' - 'TestPromoteVersion_DemotesPreviousLive: Verifies demoting previous live version to stable.' responses: '200': description: Version promoted successfully content: application/json: schema: type: object properties: version: $ref: '#/components/schemas/PromptVersion' required: - version '400': description: Bad parameters content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: invalid version number '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: unauthorized '404': description: Version not found content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: version not found '422': description: Promotion error content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: cannot promote version /v1/prompts/{id}/versions/{version}/demote: post: summary: Demote Prompt Version description: Demotes a live prompt version to stable (making it inactive but remaining read-only). operationId: demoteVersion tags: - Prompt Versions security: - BearerAuth: [] parameters: - name: id in: path required: true description: Unique prompt UUID. schema: type: string format: uuid - name: version in: path required: true description: Version sequence number (integer) or version tag (string) to demote. schema: type: string x-edge-cases: - Returns 422 if version is not live. x-test-coverage: - 'TestDemoteVersion_Success: Verifies demoting live version to stable.' responses: '200': description: Version demoted successfully content: application/json: schema: type: object properties: version: $ref: '#/components/schemas/PromptVersion' required: - version '400': description: Bad parameters content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: invalid version number '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: unauthorized '404': description: Version not found content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: version not found '422': description: Demotion error content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: only live versions can be demoted /v1/prompts/{id}/versions/{version}/archive: post: summary: Archive Prompt Version description: Archives a prompt version, marking its status as archived. operationId: archiveVersion tags: - Prompt Versions security: - BearerAuth: [] parameters: - name: id in: path required: true description: Unique prompt UUID. schema: type: string format: uuid - name: version in: path required: true description: Version sequence number (integer) or version tag (string) to archive. schema: type: string x-edge-cases: - Returns 422 if version is already archived. x-test-coverage: - 'TestArchiveVersion_Success: Verifies archiving a version.' responses: '200': description: Version archived successfully content: application/json: schema: type: object properties: version: $ref: '#/components/schemas/PromptVersion' required: - version '400': description: Bad parameters content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: invalid version number '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: unauthorized '404': description: Version not found content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: version not found '422': description: Archiving error content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: version is already archived /v1/prompts/{id}/versions/{version}/duplicate: post: summary: Duplicate Prompt Version description: | Copies the specified prompt version's template to create a new prompt version in draft state. This operation does not copy any associated payloads, only the prompt template and other metadata. operationId: duplicateVersion tags: - Prompt Versions security: - BearerAuth: [] parameters: - name: id in: path required: true description: Unique prompt UUID. schema: type: string format: uuid - name: version in: path required: true description: Version sequence number (integer) or version tag (string) to duplicate from. schema: type: string x-edge-cases: - Returns 404 if source version or prompt is not found. - Returns 401 if user is unauthorized. x-test-coverage: - 'TestDuplicateVersion_Success: Verifies duplicating a version creates a new draft version.' - 'TestDuplicateVersion_Errors: Verifies error responses for invalid prompt, missing version, etc.' responses: '201': description: Prompt version duplicated and new draft version created successfully content: application/json: schema: type: object properties: version: $ref: '#/components/schemas/PromptVersion' required: - version '400': description: Bad parameters content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: invalid version number '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: unauthorized '404': description: Version or prompt not found content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: version not found /v1/prompts/{slug}/versions/{version}/render: post: summary: Render Specific Prompt Version description: Renders a specific template version of a prompt (even draft status) using supplied variables. operationId: renderVersion tags: - Prompt Renders security: - BearerAuth: [] parameters: - name: slug in: path required: true description: Unique prompt slug. schema: type: string - name: version in: path required: true description: Version sequence number (integer) or version tag (string) to render. schema: type: string x-test-coverage: - 'TestRenderVersion_Draft: Verifies that rendering works on draft templates.' - 'TestRenderVersion_NotFound: Verifies 404 response if the requested version sequence number does not exist.' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RenderRequest' responses: '200': description: Rendered template string content: application/json: schema: $ref: '#/components/schemas/RenderResponse' '400': description: Invalid path formatting content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: invalid version number '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: unauthorized '404': description: Prompt or version not found content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: version not found '422': description: Execution failure content: application/json: schema: $ref: '#/components/schemas/APIError' example: error: 'template execution failed: ...' /v1/prompts/{id}/versions/{version}/tags: post: summary: Attach/Set Version Tag description: Attaches a unique string tag (e.g. 'prod') to the specified prompt version, replacing the tag on any other version of this prompt if it was already assigned. operationId: setVersionTag tags: - Prompt Versions security: - BearerAuth: [] parameters: - name: id in: path required: true description: Unique prompt UUID. schema: type: string format: uuid - name: version in: path required: true description: Version sequence number (integer) or version tag (string) to tag. schema: type: string requestBody: required: true content: application/json: schema: type: object properties: tag: type: string description: Tag string (alphanumeric, dots, dashes, underscores). example: prod maxLength: 50 required: - tag responses: '200': description: Tag attached successfully. Returns the updated version. content: application/json: schema: type: object properties: version: $ref: '#/components/schemas/PromptVersion' required: - version '400': description: Invalid request or tag format content: application/json: schema: $ref: '#/components/schemas/APIError' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/APIError' '404': description: Prompt or version not found content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/prompts/{id}/tags: get: summary: List Prompt Version Tags description: Lists all tags associated with versions of this prompt. operationId: listVersionTags tags: - Prompt Versions security: - BearerAuth: [] parameters: - name: id in: path required: true description: Unique prompt UUID. schema: type: string format: uuid responses: '200': description: List of prompt tags content: application/json: schema: type: object properties: tags: type: array items: type: object properties: tag: type: string version: type: integer required: - tag - version required: - tags '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '404': description: Prompt not found content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/prompts/{id}/tags/{tag}: delete: summary: Remove Version Tag description: Removes/deletes the specified version tag from the prompt. operationId: removeVersionTag tags: - Prompt Versions security: - BearerAuth: [] parameters: - name: id in: path required: true description: Unique prompt UUID. schema: type: string format: uuid - name: tag in: path required: true description: Tag string to remove. schema: type: string responses: '204': description: Tag removed successfully '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/APIError' '404': description: Prompt or tag not found content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/prompts/{id}/payloads: post: summary: Create a Prompt Payload description: Creates a new sample payload for the specified prompt. Only editors of the team can create. operationId: createPromptPayload tags: - Prompt Payloads security: - BearerAuth: [] parameters: - name: id in: path required: true description: Unique prompt UUID. schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreatePromptPayloadRequest' responses: '201': description: Prompt payload created successfully content: application/json: schema: type: object properties: payload: $ref: '#/components/schemas/PromptPayload' required: - payload '400': description: Invalid request content: application/json: schema: $ref: '#/components/schemas/APIError' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/APIError' '404': description: Prompt not found content: application/json: schema: $ref: '#/components/schemas/APIError' get: summary: List Prompt Payloads description: Lists all sample payloads associated with the specified prompt. operationId: listPromptPayloads tags: - Prompt Payloads security: - BearerAuth: [] parameters: - name: id in: path required: true description: Unique prompt UUID. schema: type: string format: uuid responses: '200': description: List of prompt payloads content: application/json: schema: type: object properties: payloads: type: array items: $ref: '#/components/schemas/PromptPayload' required: - payloads '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '404': description: Prompt not found content: application/json: schema: $ref: '#/components/schemas/APIError' /v1/prompts/{id}/payloads/{payloadID}: get: summary: Get a Prompt Payload description: Retrieves a specific sample payload by its ID and prompt ID. operationId: getPromptPayload tags: - Prompt Payloads security: - BearerAuth: [] parameters: - name: id in: path required: true description: Unique prompt UUID. schema: type: string format: uuid - name: payloadID in: path required: true description: Unique payload UUID. schema: type: string format: uuid responses: '200': description: Prompt payload details content: application/json: schema: type: object properties: payload: $ref: '#/components/schemas/PromptPayload' required: - payload '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '404': description: Prompt or payload not found content: application/json: schema: $ref: '#/components/schemas/APIError' put: summary: Update a Prompt Payload description: Updates an existing sample payload's variables and/or optional name. Only editors can update. operationId: updatePromptPayload tags: - Prompt Payloads security: - BearerAuth: [] parameters: - name: id in: path required: true description: Unique prompt UUID. schema: type: string format: uuid - name: payloadID in: path required: true description: Unique payload UUID. schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdatePromptPayloadRequest' responses: '200': description: Prompt payload updated successfully content: application/json: schema: type: object properties: payload: $ref: '#/components/schemas/PromptPayload' required: - payload '400': description: Invalid request content: application/json: schema: $ref: '#/components/schemas/APIError' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/APIError' '404': description: Prompt or payload not found content: application/json: schema: $ref: '#/components/schemas/APIError' delete: summary: Delete a Prompt Payload description: Deletes a specific sample payload. Only editors can delete. operationId: deletePromptPayload tags: - Prompt Payloads security: - BearerAuth: [] parameters: - name: id in: path required: true description: Unique prompt UUID. schema: type: string format: uuid - name: payloadID in: path required: true description: Unique payload UUID. schema: type: string format: uuid responses: '204': description: Prompt payload deleted successfully '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/APIError' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/APIError' '404': description: Prompt or payload not found content: application/json: schema: $ref: '#/components/schemas/APIError' components: securitySchemes: BearerAuth: type: http scheme: bearer description: Use an access token retrieved from login (Bearer sess_...) or a programmatic API key (Bearer ak_...). schemas: APIError: type: object properties: error: type: string example: invalid credentials required: - error User: type: object properties: id: type: string format: uuid description: Unique user identifier. email: type: string format: email description: Email address of the user. is_verified: type: boolean description: Whether the user's email has been verified. is_admin: type: boolean description: Whether the user is an admin. created_at: type: string format: date-time description: Timestamp when the user was created. required: - id - email - is_verified - is_admin - created_at APIKey: type: object properties: id: type: string format: uuid description: Unique API Key identifier. name: type: string description: Human-readable name given to the API key. org_id: type: string format: uuid description: UUID of the organization. team_id: type: string format: uuid nullable: true description: Optional UUID of the team. operation: type: string enum: - read_render - all - admin description: The scope of operations. created_at: type: string format: date-time description: Timestamp when the API Key was created. last_used_at: type: string format: date-time nullable: true description: Timestamp when the API Key was last used. Null if never used. required: - id - name - org_id - operation - created_at Organization: type: object required: - id - name - created_at properties: id: type: string format: uuid name: type: string created_at: type: string format: date-time OrganizationWithRole: type: object required: - id - name - role - created_at properties: id: type: string format: uuid name: type: string role: type: string enum: - ADMIN - MEMBER example: ADMIN created_at: type: string format: date-time Team: type: object required: - id - name - created_at properties: id: type: string format: uuid org_id: type: string format: uuid name: type: string created_at: type: string format: date-time TeamJoinRequest: type: object required: - id - team_id - user_id - status - created_at - updated_at properties: id: type: string format: uuid team_id: type: string format: uuid user_id: type: string format: uuid status: type: string enum: - pending - approved - rejected created_at: type: string format: date-time updated_at: type: string format: date-time InboxItem: type: object required: - id - type - status - created_at - updated_at - payload properties: id: type: string format: uuid type: type: string enum: - join_request example: join_request status: type: string enum: - pending - approved - rejected created_at: type: string format: date-time updated_at: type: string format: date-time payload: oneOf: - $ref: '#/components/schemas/JoinRequestPayload' JoinRequestPayload: type: object required: - user_id - user_email - team_id - team properties: user_id: type: string format: uuid user_email: type: string format: email team_id: type: string format: uuid team: $ref: '#/components/schemas/Team' Prompt: type: object properties: id: type: string format: uuid description: Unique identifier. team_id: type: string format: uuid description: Unique identifier of the team. slug: type: string description: Unique slug within the team. name: type: string description: Name of the prompt container. description: type: string description: Brief summary explaining the prompt purpose. status: type: string enum: - active - archived description: Current status of the prompt container (active, archived). created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - team_id - slug - name - description - status - created_at - updated_at PromptVersion: type: object properties: id: type: string format: uuid description: Unique version identifier. prompt_id: type: string format: uuid description: Reference to parent Prompt ID. version: type: integer description: Incrementing sequence number of the version. template: type: string description: The template syntax code with Go template parameters. example: Hello {{.name}}! status: type: string enum: - draft - stable - live - archived description: Active lifecycle status of this template version. created_at: type: string format: date-time published_at: type: string format: date-time nullable: true description: Timestamp when status was set to live. Null if draft. tags: type: array items: type: string description: List of tag strings attached to this version. required: - id - prompt_id - version - template - status - created_at - published_at - tags RenderRequest: type: object properties: variables: type: object additionalProperties: true description: Key-value dictionary of arguments interpolated into the prompt template. example: name: Alice count: 5 RenderResponse: type: object properties: rendered: type: string description: Fully parsed template response with variable replacements. example: Hello, Alice! Count is 5. version: type: integer description: Sequence version number that was executed. example: 1 slug: type: string description: Unique prompt slug. example: my_prompt tags: type: array items: type: string description: List of tag strings assigned to this version. required: - rendered - version - slug - tags PromptPayload: type: object properties: id: type: string format: uuid description: Unique payload identifier. prompt_id: type: string format: uuid description: Reference to parent Prompt ID. name: type: string nullable: true description: Optional name for this sample payload. variables: type: object description: Standard JSON object containing variable names and sample values. example: user: Arpit role: Admin created_at: type: string format: date-time updated_at: type: string format: date-time required: - id - prompt_id - variables - created_at - updated_at CreatePromptPayloadRequest: type: object properties: variables: type: object description: JSON object containing variable names and sample values. example: user: Arpit role: Admin required: - variables UpdatePromptPayloadRequest: type: object properties: name: type: string description: Optional name for this sample payload. example: Admin Sample variables: type: object description: JSON object containing variable names and sample values. example: user: Alice role: Editor UpdatePromptRequest: type: object properties: description: type: string description: Brief summary explaining the prompt purpose. example: Useful greeting prompt RegisterRequest: type: object properties: email: type: string format: email example: user@example.com password: type: string minLength: 8 example: secretpassword123 team_id: type: string format: uuid example: f47ac10b-58cc-4372-a567-0e02b2c3d479 required: - email - password LoginRequest: type: object properties: email: type: string format: email example: user@example.com password: type: string example: secretpassword123 required: - email - password VerifyRequest: type: object properties: email: type: string format: email example: user@example.com code: type: string example: '123456' required: - email - code UpdateMeRequest: type: object properties: email: type: string format: email example: newemail@example.com required: - email ChangePasswordRequest: type: object properties: current_password: type: string example: OldSecretPassword123! new_password: type: string minLength: 8 example: NewSecretPassword123! required: - current_password - new_password TriggerPasswordResetRequest: type: object properties: email: type: string format: email example: user@example.com required: - email ResetPasswordRequest: type: object properties: code: type: string example: '123456' new_password: type: string minLength: 8 example: NewSecretPassword123! required: - code - new_password CreateAPIKeyRequest: type: object properties: name: type: string description: Descriptive name for the key. example: ci-pipeline org_id: type: string format: uuid team_ids: type: array items: type: string format: uuid operation: type: string enum: - read_render - all - admin default: read_render required: - name - org_id APIKeyCreatedResponse: type: object properties: id: type: string format: uuid description: Unique API Key identifier. name: type: string description: Human-readable name of the key. key: type: string description: The fully generated secure raw API Key string. This is returned ONLY ONCE. example: ak_7f9ba3271cf881309d9be8c9c0fcae47a95b8d29c3f0b2da8e89cf21e5c3df01 operation: type: string created_at: type: string format: date-time description: Timestamp of creation. required: - id - name - key - operation - created_at TeamMemberResponse: type: object required: - user_id - email - role - created_at properties: user_id: type: string format: uuid email: type: string role: type: string created_at: type: string format: date-time CreatePromptRequest: type: object properties: name: type: string example: My Prompt description: type: string example: Useful prompt slug: type: string example: my_prompt required: - name CreateVersionRequest: type: object properties: template: type: string example: Hello, {{.name}}! required: - template UpdateVersionRequest: type: object properties: template: type: string example: Hello, {{.name}}! Count is {{.count}}. required: - template