openapi: 3.1.0 info: title: Fotospiel Support API version: 1.1.0 description: Support-only management API for super admins. servers: - url: /api/v1 security: - BearerAuth: [] components: securitySchemes: BearerAuth: type: http scheme: bearer schemas: SupportAuthResponse: type: object properties: token: type: string token_type: type: string abilities: type: array items: type: string user: type: object additionalProperties: true SupportResourceList: type: object properties: data: type: array items: type: object additionalProperties: true meta: type: object additionalProperties: true SupportResourceItem: type: object properties: data: type: object additionalProperties: true SupportResourcePayload: type: object properties: data: type: object additionalProperties: true SupportError: type: object properties: error: type: object properties: code: type: string title: type: string message: type: string meta: type: object additionalProperties: true SupportEventPayload: type: object properties: data: type: object properties: name: type: object properties: de: { type: string } en: { type: string } description: type: object properties: de: { type: string } en: { type: string } slug: { type: string } date: { type: string, format: date-time } location: { type: string, nullable: true } max_participants: { type: integer, nullable: true } event_type_id: { type: integer, nullable: true } default_locale: { type: string } is_active: { type: boolean } status: { type: string, enum: [draft, published, archived] } settings: { type: object, additionalProperties: true } join_link_enabled: { type: boolean } photo_upload_enabled: { type: boolean } task_checklist_enabled: { type: boolean } SupportPhotoPayload: type: object properties: data: type: object properties: status: { type: string, enum: [pending, approved, rejected, hidden] } moderation_notes: { type: string, nullable: true } is_featured: { type: boolean } emotion_id: { type: integer, nullable: true } task_id: { type: integer, nullable: true } SupportBlogPostPayload: type: object properties: data: type: object properties: blog_category_id: { type: integer } slug: { type: string } banner: { type: string, nullable: true } published_at: { type: string, format: date-time, nullable: true } is_published: { type: boolean } title: type: object properties: de: { type: string } en: { type: string } content: type: object properties: de: { type: string } en: { type: string } excerpt: type: object properties: de: { type: string } en: { type: string } meta_title: type: object properties: de: { type: string } en: { type: string } meta_description: type: object properties: de: { type: string } en: { type: string } SupportEmotionPayload: type: object properties: data: type: object properties: name: type: object properties: de: { type: string } en: { type: string } description: type: object properties: de: { type: string } en: { type: string } icon: { type: string, nullable: true } color: { type: string, nullable: true } sort_order: { type: integer } is_active: { type: boolean } tenant_id: { type: integer, nullable: true } SupportTaskPayload: type: object properties: data: type: object properties: emotion_id: { type: integer } event_type_id: { type: integer, nullable: true } title: type: object properties: de: { type: string } en: { type: string } description: type: object properties: de: { type: string } en: { type: string } example_text: type: object properties: de: { type: string } en: { type: string } difficulty: { type: string, enum: [easy, medium, hard] } sort_order: { type: integer } is_active: { type: boolean } paths: /support/auth/token: post: summary: Issue a support access token tags: [support-auth] requestBody: required: true content: application/json: schema: type: object properties: login: { type: string } password: { type: string } abilities: type: array items: { type: string } required: [login, password] responses: '200': description: Token issued content: application/json: schema: $ref: '#/components/schemas/SupportAuthResponse' /support/auth/me: get: summary: Get current support user tags: [support-auth] responses: '200': description: Current user content: application/json: schema: type: object properties: user: type: object additionalProperties: true abilities: type: array items: { type: string } /support/auth/logout: post: summary: Revoke current support token tags: [support-auth] responses: '200': description: Token revoked content: application/json: schema: type: object properties: ok: { type: boolean } /support/settings/guest-policy: get: summary: Get guest policy settings tags: [support-settings] responses: '200': description: Guest policy content: application/json: schema: $ref: '#/components/schemas/SupportResourceItem' patch: summary: Update guest policy settings tags: [support-settings] requestBody: required: true content: application/json: schema: type: object additionalProperties: true responses: '200': description: Updated guest policy content: application/json: schema: $ref: '#/components/schemas/SupportResourceItem' /support/settings/watermark: get: summary: Get watermark settings tags: [support-settings] responses: '200': description: Watermark settings content: application/json: schema: $ref: '#/components/schemas/SupportResourceItem' patch: summary: Update watermark settings tags: [support-settings] requestBody: required: true content: application/json: schema: type: object additionalProperties: true responses: '200': description: Updated watermark settings content: application/json: schema: $ref: '#/components/schemas/SupportResourceItem' /support/tenants/{tenant}/actions/activate: post: summary: Activate tenant tags: [support-tenants] parameters: - in: path name: tenant required: true schema: { type: integer } responses: '200': { description: Activated } /support/tenants/{tenant}/actions/deactivate: post: summary: Deactivate tenant tags: [support-tenants] parameters: - in: path name: tenant required: true schema: { type: integer } responses: '200': { description: Deactivated } /support/tenants/{tenant}/actions/suspend: post: summary: Suspend tenant tags: [support-tenants] parameters: - in: path name: tenant required: true schema: { type: integer } responses: '200': { description: Suspended } /support/tenants/{tenant}/actions/unsuspend: post: summary: Unsuspend tenant tags: [support-tenants] parameters: - in: path name: tenant required: true schema: { type: integer } responses: '200': { description: Unsuspended } /support/tenants/{tenant}/actions/schedule-deletion: post: summary: Schedule tenant deletion tags: [support-tenants] parameters: - in: path name: tenant required: true schema: { type: integer } requestBody: required: true content: application/json: schema: type: object properties: pending_deletion_at: { type: string, format: date-time } send_warning: { type: boolean } required: [pending_deletion_at] responses: '200': { description: Scheduled } /support/tenants/{tenant}/actions/cancel-deletion: post: summary: Cancel tenant deletion tags: [support-tenants] parameters: - in: path name: tenant required: true schema: { type: integer } responses: '200': { description: Cancelled } /support/tenants/{tenant}/actions/anonymize: post: summary: Anonymize tenant tags: [support-tenants] parameters: - in: path name: tenant required: true schema: { type: integer } responses: '200': { description: Anonymize requested } /support/tenants/{tenant}/actions/add-package: post: summary: Add package to tenant tags: [support-tenants] parameters: - in: path name: tenant required: true schema: { type: integer } requestBody: required: true content: application/json: schema: type: object properties: package_id: { type: integer } expires_at: { type: string, format: date-time } reason: { type: string } required: [package_id] responses: '200': { description: Package added } /support/tenants/{tenant}/actions/update-limits: post: summary: Update tenant limits tags: [support-tenants] parameters: - in: path name: tenant required: true schema: { type: integer } requestBody: required: true content: application/json: schema: type: object properties: max_photos_per_event: { type: integer } max_storage_mb: { type: integer } note: { type: string } required: [max_photos_per_event, max_storage_mb] responses: '200': { description: Limits updated } /support/tenants/{tenant}/actions/update-subscription-expires-at: post: summary: Update tenant subscription expiry tags: [support-tenants] parameters: - in: path name: tenant required: true schema: { type: integer } requestBody: required: true content: application/json: schema: type: object properties: subscription_expires_at: { type: string, format: date-time } note: { type: string } responses: '200': { description: Subscription expiry updated } /support/tenants/{tenant}/actions/set-grace-period: post: summary: Set tenant grace period tags: [support-tenants] parameters: - in: path name: tenant required: true schema: { type: integer } requestBody: required: true content: application/json: schema: type: object properties: grace_period_ends_at: { type: string, format: date-time } note: { type: string } required: [grace_period_ends_at] responses: '200': { description: Grace period set } /support/tenants/{tenant}/actions/clear-grace-period: post: summary: Clear tenant grace period tags: [support-tenants] parameters: - in: path name: tenant required: true schema: { type: integer } responses: '200': { description: Grace period cleared } /support/{resource}: get: summary: List support resource tags: [support-resources] parameters: - in: path name: resource required: true schema: type: string enum: [tenants, users, events, event-types, photos, event-purchases, purchases, purchase-histories, packages, package-addons, tenant-packages, coupons, gift-vouchers, tenant-feedback, tenant-announcements, media-storage-targets, retention-overrides, data-exports, photobooth-settings, legal-pages, blog-categories, blog-posts, emotions, tasks, task-collections, super-admin-action-logs, infrastructure-action-logs] - in: query name: search schema: { type: string } - in: query name: sort schema: { type: string } - in: query name: per_page schema: { type: integer } responses: '200': description: Resource list content: application/json: schema: $ref: '#/components/schemas/SupportResourceList' post: summary: Create support resource tags: [support-resources] parameters: - in: path name: resource required: true schema: { type: string } requestBody: required: true content: application/json: schema: oneOf: - $ref: '#/components/schemas/SupportBlogPostPayload' - $ref: '#/components/schemas/SupportEmotionPayload' - $ref: '#/components/schemas/SupportTaskPayload' responses: '201': description: Resource created content: application/json: schema: $ref: '#/components/schemas/SupportResourceItem' /support/{resource}/{record}: get: summary: Get support resource tags: [support-resources] parameters: - in: path name: resource required: true schema: { type: string } - in: path name: record required: true schema: { type: string } responses: '200': description: Resource content: application/json: schema: $ref: '#/components/schemas/SupportResourceItem' patch: summary: Update support resource tags: [support-resources] parameters: - in: path name: resource required: true schema: { type: string } - in: path name: record required: true schema: { type: string } requestBody: required: true content: application/json: schema: oneOf: - $ref: '#/components/schemas/SupportEventPayload' - $ref: '#/components/schemas/SupportPhotoPayload' - $ref: '#/components/schemas/SupportBlogPostPayload' - $ref: '#/components/schemas/SupportEmotionPayload' - $ref: '#/components/schemas/SupportTaskPayload' responses: '200': description: Resource updated content: application/json: schema: $ref: '#/components/schemas/SupportResourceItem' delete: summary: Delete support resource tags: [support-resources] parameters: - in: path name: resource required: true schema: { type: string } - in: path name: record required: true schema: { type: string } responses: '200': description: Resource deleted content: application/json: schema: type: object properties: ok: { type: boolean }