openapi: 3.1.0 info: title: Forithmus Challenge Platform 2fa challenges API version: 1.0.0 tags: - name: challenges paths: /challenges/meta/categories: get: tags: - challenges summary: List Categories description: 'List all distinct challenge categories currently in use, sorted alphabetically. Used by frontend for dynamic category dropdowns and browse filters.' operationId: list_categories_challenges_meta_categories_get responses: '200': description: Successful Response content: application/json: schema: {} /challenges: get: tags: - challenges summary: List Challenges description: 'List public challenges with pagination. If mine=true (requires auth), returns all challenges the user is an active member of. Returns: { items: [...], total: int, limit: int, offset: int }' operationId: list_challenges_challenges_get parameters: - name: status in: query required: false schema: type: string default: open title: Status - name: category in: query required: false schema: anyOf: - type: string - type: 'null' title: Category - name: mine in: query required: false schema: type: boolean default: false title: Mine - name: limit in: query required: false schema: type: integer maximum: 100 minimum: 1 default: 20 title: Limit - name: offset in: query required: false schema: type: integer minimum: 0 default: 0 title: Offset responses: '200': description: Successful Response content: application/json: schema: {} '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' post: tags: - challenges summary: Create Challenge description: 'Create a new challenge in ''draft'' status. Requires email verification. The creator is automatically added as a ChallengeMember with role=''admin''. After creation, the admin must upload test data and evaluation container, then transition status to ''open'' via PUT.' operationId: create_challenge_challenges_post requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ChallengeCreate' responses: '201': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ChallengeOut' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /challenges/{slug}/registry-usage: get: tags: - challenges summary: Get Registry Usage Endpoint description: Get Docker registry storage usage for this challenge. Admin only. operationId: get_registry_usage_endpoint_challenges__slug__registry_usage_get parameters: - name: slug in: path required: true schema: type: string title: Slug responses: '200': description: Successful Response content: application/json: schema: {} '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /challenges/{slug}/registry-purge: post: tags: - challenges summary: Purge Registry description: Delete all kept Docker images for this challenge. Admin only. operationId: purge_registry_challenges__slug__registry_purge_post parameters: - name: slug in: path required: true schema: type: string title: Slug responses: '200': description: Successful Response content: application/json: schema: {} '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /challenges/{slug}/stats: get: tags: - challenges summary: Get Challenge Stats description: 'Stats for a challenge: participants by country/institution, submission stats. Private challenges require membership. Public challenges are open to all. Cached in Redis for 5 minutes to avoid expensive aggregation queries on every load.' operationId: get_challenge_stats_challenges__slug__stats_get parameters: - name: slug in: path required: true schema: type: string title: Slug responses: '200': description: Successful Response content: application/json: schema: {} '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /challenges/by-id/{challenge_id}: get: tags: - challenges summary: Get Challenge By Id description: Look up a challenge slug by its UUID. Used by notifications. operationId: get_challenge_by_id_challenges_by_id__challenge_id__get parameters: - name: challenge_id in: path required: true schema: type: string title: Challenge Id responses: '200': description: Successful Response content: application/json: schema: {} '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /challenges/{slug}: get: tags: - challenges summary: Get Challenge description: 'Get challenge details. Private challenges require active membership. Platform superadmin/staff can always view.' operationId: get_challenge_challenges__slug__get parameters: - name: slug in: path required: true schema: type: string title: Slug responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ChallengeOut' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' put: tags: - challenges summary: Update Challenge description: 'Update challenge settings. Only challenge admins can update. Platform superadmin/staff also have access (handled by require_challenge_role). Status changes are validated against ALLOWED_STATUS_TRANSITIONS (e.g. draft->open, open->closed). All other fields are freely editable.' operationId: update_challenge_challenges__slug__put parameters: - name: slug in: path required: true schema: type: string title: Slug requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ChallengeUpdate' responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ChallengeOut' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' delete: tags: - challenges summary: Delete Challenge description: 'Delete a challenge and all related data (members, phases, pages, forum, submissions). Only challenge admins or platform superadmin/staff can delete. Cascade delete is handled by the database (ondelete=CASCADE on foreign keys).' operationId: delete_challenge_challenges__slug__delete parameters: - name: slug in: path required: true schema: type: string title: Slug responses: '204': description: Successful Response '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' components: schemas: ChallengeCreate: properties: title: type: string maxLength: 200 minLength: 1 title: Title acronym: type: string maxLength: 20 minLength: 1 title: Acronym description: type: string title: Description default: '' category: type: string title: Category default: Segmentation visibility: type: string title: Visibility default: public tier: type: string title: Tier default: gpu-t4 timeout_minutes: type: integer maximum: 360.0 minimum: 5.0 title: Timeout Minutes default: 60 max_submissions_per_user: type: integer maximum: 100.0 minimum: 1.0 title: Max Submissions Per User default: 10 score_json_path: type: string title: Score Json Path default: $.metrics.dice sort_direction: type: string title: Sort Direction default: desc deadline: anyOf: - type: string format: date-time - type: 'null' title: Deadline type: object required: - title - acronym title: ChallengeCreate description: 'Request body for POST /challenges: creates a new challenge in ''draft'' status.' HTTPValidationError: properties: detail: items: $ref: '#/components/schemas/ValidationError' type: array title: Detail type: object title: HTTPValidationError ValidationError: properties: loc: items: anyOf: - type: string - type: integer type: array title: Location msg: type: string title: Message type: type: string title: Error Type type: object required: - loc - msg - type title: ValidationError ChallengeUpdate: properties: title: anyOf: - type: string maxLength: 200 - type: 'null' title: Title acronym: anyOf: - type: string maxLength: 20 - type: 'null' title: Acronym description: anyOf: - type: string - type: 'null' title: Description category: anyOf: - type: string - type: 'null' title: Category visibility: anyOf: - type: string - type: 'null' title: Visibility status: anyOf: - type: string - type: 'null' title: Status tier: anyOf: - type: string - type: 'null' title: Tier timeout_minutes: anyOf: - type: integer maximum: 360.0 minimum: 5.0 - type: 'null' title: Timeout Minutes max_submissions_per_user: anyOf: - type: integer maximum: 100.0 minimum: 1.0 - type: 'null' title: Max Submissions Per User score_json_path: anyOf: - type: string - type: 'null' title: Score Json Path sort_direction: anyOf: - type: string - type: 'null' title: Sort Direction deadline: anyOf: - type: string format: date-time - type: 'null' title: Deadline forum_enabled: anyOf: - type: boolean - type: 'null' title: Forum Enabled timeline_enabled: anyOf: - type: boolean - type: 'null' title: Timeline Enabled groups_enabled: anyOf: - type: boolean - type: 'null' title: Groups Enabled require_approval: anyOf: - type: boolean - type: 'null' title: Require Approval current_edition: anyOf: - type: string - type: 'null' title: Current Edition editions: anyOf: - items: type: string type: array - type: 'null' title: Editions resource_overrides: anyOf: - items: type: object type: array - type: 'null' title: Resource Overrides eval_cost_limit: anyOf: - type: number maximum: 1000.0 minimum: 1.0 - type: 'null' title: Eval Cost Limit participant_pays_compute: anyOf: - type: boolean - type: 'null' title: Participant Pays Compute spot_enabled: anyOf: - type: boolean - type: 'null' title: Spot Enabled keep_docker_images: anyOf: - type: boolean - type: 'null' title: Keep Docker Images keep_submission_outputs: anyOf: - type: boolean - type: 'null' title: Keep Submission Outputs hide_submission_logs: anyOf: - type: boolean - type: 'null' title: Hide Submission Logs storage_price_per_tb: anyOf: - type: number - type: 'null' title: Storage Price Per Tb storage_free_tier_gb: anyOf: - type: number - type: 'null' title: Storage Free Tier Gb registry_limit_gb: anyOf: - type: number - type: 'null' title: Registry Limit Gb registry_price_per_gb: anyOf: - type: number - type: 'null' title: Registry Price Per Gb output_limit_gb: anyOf: - type: number - type: 'null' title: Output Limit Gb eval_excess_enabled: anyOf: - type: boolean - type: 'null' title: Eval Excess Enabled cover_image_url: anyOf: - type: string - type: 'null' title: Cover Image Url card_image_url: anyOf: - type: string - type: 'null' title: Card Image Url cover_image_original_url: anyOf: - type: string - type: 'null' title: Cover Image Original Url card_image_original_url: anyOf: - type: string - type: 'null' title: Card Image Original Url type: object title: ChallengeUpdate description: 'Request body for PUT /challenges/{slug}: all fields optional (partial update). Note: visibility is intentionally excluded: it is set at creation and cannot be changed.' ChallengeOut: properties: id: type: string format: uuid title: Id slug: type: string title: Slug collection_id: anyOf: - type: string format: uuid - type: 'null' title: Collection Id title: type: string title: Title acronym: type: string title: Acronym default: '' collection_acronym: anyOf: - type: string - type: 'null' title: Collection Acronym description: type: string title: Description category: type: string title: Category visibility: type: string title: Visibility status: type: string title: Status tier: type: string title: Tier timeout_minutes: type: integer title: Timeout Minutes max_submissions_per_user: type: integer title: Max Submissions Per User score_json_path: type: string title: Score Json Path sort_direction: type: string title: Sort Direction submission_count: type: integer title: Submission Count participant_count: type: integer title: Participant Count default: 0 forum_enabled: type: boolean title: Forum Enabled timeline_enabled: type: boolean title: Timeline Enabled default: true groups_enabled: type: boolean title: Groups Enabled default: false require_approval: type: boolean title: Require Approval default: false current_edition: anyOf: - type: string - type: 'null' title: Current Edition editions: items: type: string type: array title: Editions default: [] has_sponsor_pool: type: boolean title: Has Sponsor Pool default: false resource_overrides: items: type: object type: array title: Resource Overrides default: [] eval_cost_limit: type: number title: Eval Cost Limit default: 20.0 participant_pays_compute: type: boolean title: Participant Pays Compute default: false spot_enabled: type: boolean title: Spot Enabled default: false keep_docker_images: type: boolean title: Keep Docker Images default: false keep_submission_outputs: type: boolean title: Keep Submission Outputs default: false registry_purge_after: anyOf: - type: string format: date-time - type: 'null' title: Registry Purge After data_retention_until: anyOf: - type: string format: date-time - type: 'null' title: Data Retention Until hide_submission_logs: type: boolean title: Hide Submission Logs default: false storage_price_per_tb: anyOf: - type: number - type: 'null' title: Storage Price Per Tb storage_free_tier_gb: anyOf: - type: number - type: 'null' title: Storage Free Tier Gb registry_limit_gb: anyOf: - type: number - type: 'null' title: Registry Limit Gb output_limit_gb: anyOf: - type: number - type: 'null' title: Output Limit Gb eval_excess_enabled: type: boolean title: Eval Excess Enabled default: false subscription_status: anyOf: - type: string - type: 'null' title: Subscription Status host_user_id: type: string format: uuid title: Host User Id deadline: anyOf: - type: string format: date-time - type: 'null' title: Deadline cover_image_url: anyOf: - type: string - type: 'null' title: Cover Image Url card_image_url: anyOf: - type: string - type: 'null' title: Card Image Url cover_image_original_url: anyOf: - type: string - type: 'null' title: Cover Image Original Url card_image_original_url: anyOf: - type: string - type: 'null' title: Card Image Original Url created_at: type: string format: date-time title: Created At updated_at: type: string format: date-time title: Updated At type: object required: - id - slug - title - description - category - visibility - status - tier - timeout_minutes - max_submissions_per_user - score_json_path - sort_direction - submission_count - forum_enabled - host_user_id - deadline - created_at - updated_at title: ChallengeOut description: Full challenge representation returned by detail endpoints.