openapi: 3.0.3 info: title: 'CiberTicket API Documentation' description: '' version: 1.0.0 servers: - url: 'https://api.ciberticket.co' tags: - name: Authentication description: '' - name: Core description: '' - name: Endpoints description: '' - name: Tenant description: '' components: securitySchemes: default: type: http scheme: bearer description: 'You can retrieve your token by visiting your dashboard and clicking Generate API token.' security: - default: [] paths: /api/login: post: summary: Login operationId: login description: "Inicia sesión sin requerir `guard`. Detecta automáticamente si usar `platform` o `tenant`.\nDevuelve token con abilities (guard/team), roles y permisos, y todas las membresías del usuario." parameters: - in: header name: X-Tenant description: '' example: 'string optional Team/Tenant deseado (si se envía, fuerza login en tenant).' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: message: 'Login successful' user: id: 7 name: Edinson email: edinson.vasquez@example.com token: 47|... guard: platform team_id: null roles: platform: - owner tenant: [] permissions: platform: - core.owner.index tenant: [] memberships: - tenant_id: web tenant_name: 'CiberLoto Web' roles: - admin permissions: - tenant.event.create - tenant_id: store-1 tenant_name: 'CiberSnacks Tienda 1' roles: - viewer permissions: - tenant.event.view properties: message: type: string example: 'Login successful' user: type: object properties: id: type: integer example: 7 name: type: string example: Edinson email: type: string example: edinson.vasquez@example.com token: type: string example: 47|... guard: type: string example: platform team_id: type: string example: null roles: type: object properties: platform: type: array example: - owner items: type: string tenant: type: array example: [] permissions: type: object properties: platform: type: array example: - core.owner.index items: type: string tenant: type: array example: [] memberships: type: array example: - tenant_id: web tenant_name: 'CiberLoto Web' roles: - admin permissions: - tenant.event.create - tenant_id: store-1 tenant_name: 'CiberSnacks Tienda 1' roles: - viewer permissions: - tenant.event.view items: type: object properties: tenant_id: type: string example: web tenant_name: type: string example: 'CiberLoto Web' roles: type: array example: - admin items: type: string permissions: type: array example: - tenant.event.create items: type: string tags: - Authentication requestBody: required: true content: application/json: schema: type: object properties: login: type: string description: 'Email o user_name.' example: edinson.vasquez@example.com nullable: false password: type: string description: Contraseña. example: secret123 nullable: false remember: type: boolean description: 'Mantener sesión (si el guard es stateful).' example: true nullable: false required: - login - password security: [] /api/core/owner: get: summary: 'Owner - List all owners.' operationId: ownerListAllOwners description: 'This endpoint retrieves all users who have the "owner" role assigned.' parameters: [] responses: 200: description: '' content: application/json: schema: type: array items: type: object example: - id: 1 name: John surname: Doe email: john.doe@example.com phone: '+57 3001234567' avatar_url: 'https://example.com/avatar.jpg' locale: es timezone: America/Bogota status: active - id: 2 name: Jane surname: Smith email: jane.smith@example.com phone: '+57 3019876543' avatar_url: null locale: en timezone: UTC status: active tags: - Core post: summary: 'Owner - Create a new Owner user' operationId: ownerCreateANewOwnerUser description: "This endpoint allows you to create a new **Owner** user.\nThe user is not yet associated with any tenant.\nBy default, the role `owner` will be assigned in the `tenant` guard." parameters: [] responses: 201: description: '' content: text/plain: schema: type: string example: "{\n \"message\": \"Owner successfully created\",\n \"user\": {\n \"id\": 1,\n \"name\": \"John\",\n \"surname\": \"Doe\",\n \"email\": \"john.doe@example.com\",\n \"phone_code\": \"+57\",\n \"phone\": \"3181234567\",\n },\n \"roles\": [\"owner\"]\n}" tags: - Core requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'The first name of the user.' example: John nullable: false surname: type: string description: 'The surname of the user.' example: Doe nullable: false email: type: string description: 'The email address of the user. Must be unique.' example: john.doe@example.com nullable: false phone_code: type: string description: 'The phone code of the user.' example: '+57' nullable: false phone: type: string description: 'The phone number of the user. Must be unique.' example: '31812345678' nullable: false password: type: string description: 'The password for the user account. Must be at least 8 characters.' example: myStrongP@ssw0rd nullable: false avatar_url: type: string description: 'optional The URL of the avatar image.' example: 'https://example.com/avatar.jpg' nullable: true locale: type: string description: 'optional The preferred locale of the user.' example: en nullable: true timezone: type: string description: 'optional The preferred timezone of the user.' example: America/New_York nullable: true password_confirmation: type: string description: 'The password confirmation. Must match the password field.' example: myStrongP@ssw0rd nullable: false required: - name - surname - email - phone_code - phone - password - password_confirmation '/api/core/owner/{id}': put: summary: 'Owner - Update an existing user.' operationId: ownerUpdateAnExistingUser description: "This endpoint allows updating an existing user.\nYou can change personal information, email, phone, avatar, locale, timezone,\nand optionally update the password." parameters: [] responses: 201: description: '' content: application/json: schema: type: object example: message: 'Owner successfully updated' user: id: 5 name: John surname: Doe email: john.doe@example.com phone_code: '+57' phone: '3001234567' roles: - owner properties: message: type: string example: 'Owner successfully updated' user: type: object properties: id: type: integer example: 5 name: type: string example: John surname: type: string example: Doe email: type: string example: john.doe@example.com phone_code: type: string example: '+57' phone: type: string example: '3001234567' roles: type: array example: - owner items: type: string 422: description: '' content: application/json: schema: type: object example: message: 'The given data was invalid.' errors: email: - 'The email has already been taken.' properties: message: type: string example: 'The given data was invalid.' errors: type: object properties: email: type: array example: - 'The email has already been taken.' items: type: string tags: - Core requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'The first name of the user.' example: John nullable: false surname: type: string description: 'The surname of the user.' example: Doe nullable: false email: type: string description: 'The email address of the user. Must be unique.' example: john.doe@example.com nullable: false phone: type: string description: 'The user phone number (without country code).' example: '3001234567' nullable: true avatar_url: type: string description: 'The URL of the user avatar.' example: 'https://example.com/avatar.jpg' nullable: true locale: type: string description: 'The user locale/language. Default: es.' example: en nullable: true timezone: type: string description: 'The user timezone. Default: America/Bogota.' example: UTC nullable: true password: type: string description: 'The new password for the user. Must be at least 8 characters.' example: password123 nullable: true password_confirmation: type: string description: 'The password confirmation.' example: password123 nullable: false required: - name - surname - email get: summary: 'Owner - Show user by ID.' operationId: ownerShowUserByID description: 'This endpoint retrieves the details of a specific user by their ID.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: id: 1 name: John surname: Doe email: john.doe@example.com phone: '+57 3001234567' avatar_url: 'https://example.com/avatar.jpg' locale: es timezone: America/Bogota status: active created_at: '2025-01-15T10:00:00.000000Z' updated_at: '2025-02-20T14:35:00.000000Z' properties: id: type: integer example: 1 name: type: string example: John surname: type: string example: Doe email: type: string example: john.doe@example.com phone: type: string example: '+57 3001234567' avatar_url: type: string example: 'https://example.com/avatar.jpg' locale: type: string example: es timezone: type: string example: America/Bogota status: type: string example: active created_at: type: string example: '2025-01-15T10:00:00.000000Z' updated_at: type: string example: '2025-02-20T14:35:00.000000Z' 404: description: '' content: application/json: schema: type: object example: message: 'No query results for model [App\Models\User] 999' properties: message: type: string example: 'No query results for model [App\Models\User] 999' tags: - Core delete: summary: 'Owner - Delete (soft) a user.' operationId: ownerDeletesoftAUser description: "This endpoint marks an existing user as deleted by updating their `status` field to `deleted`.\nThe user record is not physically removed from the database." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: 'Owner successfully deleted' properties: message: type: string example: 'Owner successfully deleted' 404: description: '' content: application/json: schema: type: object example: message: 'Owner not found or unauthorized.' properties: message: type: string example: 'Owner not found or unauthorized.' tags: - Core parameters: - in: path name: id description: 'The ID of the owner.' example: architecto required: true schema: type: string /api/core/tenant: post: summary: 'Tenant - Crear tenant (ASYNC provisioning)' operationId: tenantCrearTenantASYNCProvisioning description: '' parameters: [] responses: 202: description: '' content: application/json: schema: type: object example: message: 'Tenant provisioning queued' data: id: web domain: web.cibertickets.co owner_id: 7 provisioning: queued properties: message: type: string example: 'Tenant provisioning queued' data: type: object properties: id: type: string example: web domain: type: string example: web.cibertickets.co owner_id: type: integer example: 7 provisioning: type: string example: queued tags: - Core requestBody: required: true content: application/json: schema: type: object properties: id: type: string description: 'Slug único del tenant.' example: web nullable: false domain: type: string description: 'Dominio del tenant.' example: web.cibertickets.co nullable: true brand_name: type: string description: '' example: CiberTickets nullable: false currency: type: string description: '' example: COP nullable: false timezone: type: string description: '' example: America/Bogota nullable: false contact_email: type: string description: '' example: soporte@cibertickets.co nullable: false logo_url: type: string description: 'Opcionales estéticos (si los pasas ahora; si no, el Job pone defaults). Must be a valid URL. Must not be greater than 255 characters.' example: 'https://www.gulgowski.com/nihil-accusantium-harum-mollitia-modi-deserunt' nullable: true logo_light_url: type: string description: 'Must be a valid URL. Must not be greater than 255 characters.' example: 'http://www.dubuque.net/quo-omnis-nostrum-aut-adipisci' nullable: true logo_dark_url: type: string description: 'Must be a valid URL. Must not be greater than 255 characters.' example: 'https://cronin.com/incidunt-iure-odit-et-et-modi-ipsum.html' nullable: true favicon_url: type: string description: 'Must be a valid URL. Must not be greater than 255 characters.' example: 'http://www.predovic.biz/consequatur-aut-dolores-enim-non-facere-tempora.html' nullable: true color_primary: type: string description: '' example: null nullable: true color_secondary: type: string description: '' example: null nullable: true color_accent: type: string description: '' example: null nullable: true color_background: type: string description: '' example: null nullable: true color_surface: type: string description: '' example: null nullable: true color_text: type: string description: '' example: null nullable: true color_success: type: string description: '' example: null nullable: true color_warning: type: string description: '' example: null nullable: true color_danger: type: string description: '' example: null nullable: true color_info: type: string description: '' example: null nullable: true font_heading: type: string description: 'Must not be greater than 50 characters.' example: t nullable: true font_body: type: string description: 'Must not be greater than 50 characters.' example: u nullable: true theme_mode: type: string description: '' example: null nullable: true rounded_ui: type: boolean description: '' example: false nullable: true border_radius: type: integer description: 'Must be at least 0. Must not be greater than 40.' example: 3 nullable: true brand_domain: type: string description: 'Must not be greater than 191 characters.' example: w nullable: true brand_support_url: type: string description: 'Must be a valid URL. Must not be greater than 255 characters.' example: 'https://labadie.com/deleniti-distinctio-eum-doloremque-id-aut.html' nullable: true social_links: type: object description: '' example: [] nullable: false properties: instagram: type: string description: 'Must be a valid URL. Must not be greater than 255 characters.' example: q nullable: true facebook: type: string description: 'Must be a valid URL. Must not be greater than 255 characters.' example: b nullable: true x: type: string description: 'Must be a valid URL. Must not be greater than 255 characters.' example: e nullable: true tiktok: type: string description: 'Must be a valid URL. Must not be greater than 255 characters.' example: w nullable: true youtube: type: string description: 'Must be a valid URL. Must not be greater than 255 characters.' example: t nullable: true required: - id - brand_name - currency - timezone - contact_email /api/core/tenant/users/index: get: summary: 'User Tenant - List users across all tenants managed by the owner (including per-tenant roles)' operationId: userTenantListUsersAcrossAllTenantsManagedByTheOwnerincludingPerTenantRoles description: "Returns all users linked to the tenants that the authenticated platform user manages,\nand for each user, the list of those tenants with the user's roles within each tenant." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: 'Users and tenant roles retrieved' data: - id: 15 name: John surname: Doe email: john.doe@example.com status: active tenants: - id: academy-1 name: AleAcademy role_hint: admin roles: - Administrative - Coach - id: club-22 name: 'City Club' role_hint: viewer roles: - Player properties: message: type: string example: 'Users and tenant roles retrieved' data: type: array example: - id: 15 name: John surname: Doe email: john.doe@example.com status: active tenants: - id: academy-1 name: AleAcademy role_hint: admin roles: - Administrative - Coach - id: club-22 name: 'City Club' role_hint: viewer roles: - Player items: type: object properties: id: type: integer example: 15 name: type: string example: John surname: type: string example: Doe email: type: string example: john.doe@example.com status: type: string example: active tenants: type: array example: - id: academy-1 name: AleAcademy role_hint: admin roles: - Administrative - Coach - id: club-22 name: 'City Club' role_hint: viewer roles: - Player items: type: object properties: id: type: string example: academy-1 name: type: string example: AleAcademy role_hint: type: string example: admin roles: type: array example: - Administrative - Coach items: type: string tags: - Core /api/core/tenant/users/store: post: summary: 'User Tenant - Create a user and assign per-tenant roles' operationId: userTenantCreateAUserAndAssignPerTenantRoles description: "Creates a global user and links it to one or more tenants, assigning roles within each tenant.\nRoles must exist with guard `tenant` (e.g., admin, organizer, finance, scanner)." parameters: [] responses: 201: description: '' content: application/json: schema: type: object example: message: 'User created and roles assigned' data: user: id: 101 name: John surname: Doe email: john.doe@example.com status: active tenants: - id: academy-1 name: AleAcademy role_hint: admin roles: - admin - organizer - id: club-22 name: 'City Club' role_hint: organizer roles: - organizer properties: message: type: string example: 'User created and roles assigned' data: type: object properties: user: type: object properties: id: type: integer example: 101 name: type: string example: John surname: type: string example: Doe email: type: string example: john.doe@example.com status: type: string example: active tenants: type: array example: - id: academy-1 name: AleAcademy role_hint: admin roles: - admin - organizer - id: club-22 name: 'City Club' role_hint: organizer roles: - organizer items: type: object properties: id: type: string example: academy-1 name: type: string example: AleAcademy role_hint: type: string example: admin roles: type: array example: - admin - organizer items: type: string tags: - Core requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'First name.' example: John nullable: false surname: type: string description: 'Last name.' example: Doe nullable: false email: type: string description: 'Unique email.' example: john.doe@example.com nullable: false password: type: string description: 'nullable Min: 8 chars.' example: MyStr0ngP@ss nullable: true tenants: type: array description: 'List of tenant-role assignments.' example: - architecto items: type: string required: - name - surname - email - tenants '/api/core/tenant/users/{userId}/update': put: summary: 'User Tenant - Update a user and (optionally) per-tenant roles/membership' operationId: userTenantUpdateAUserAndoptionallyPerTenantRolesmembership description: "Updates basic user fields. Optionally syncs roles for specific tenants and/or detaches the user\nfrom other tenants. Roles must exist with guard `tenant` (e.g., admin, organizer, finance, scanner)." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: 'User updated' data: user: id: 101 name: John surname: Doe email: john.doe@example.com status: active tenants: - id: academy-1 name: AleAcademy role_hint: admin roles: - admin - organizer - id: club-22 name: 'City Club' role_hint: viewer roles: - organizer properties: message: type: string example: 'User updated' data: type: object properties: user: type: object properties: id: type: integer example: 101 name: type: string example: John surname: type: string example: Doe email: type: string example: john.doe@example.com status: type: string example: active tenants: type: array example: - id: academy-1 name: AleAcademy role_hint: admin roles: - admin - organizer - id: club-22 name: 'City Club' role_hint: viewer roles: - organizer items: type: object properties: id: type: string example: academy-1 name: type: string example: AleAcademy role_hint: type: string example: admin roles: type: array example: - admin - organizer items: type: string tags: - Core requestBody: required: false content: application/json: schema: type: object properties: name: type: string description: 'optional First name.' example: John nullable: false surname: type: string description: 'optional Last name.' example: Doe nullable: false email: type: string description: 'optional Unique email.' example: john.doe@example.com nullable: false password: type: string description: 'optional Min: 8 chars.' example: MyStr0ngP@ss nullable: true tenants: type: array description: 'optional List of per-tenant role assignments to sync (only for those tenants).' example: - architecto items: type: string nullable: true detach_tenants: type: array description: 'optional Tenant IDs to detach the user from (removes membership and clears roles for those tenants).' example: - architecto items: type: string 'detach_tenants[]': type: string description: 'A tenant ID.' example: club-22 nullable: false parameters: - in: path name: userId description: '' example: 1 required: true schema: type: integer - in: path name: user description: 'The user ID.' example: 101 required: true schema: type: integer '/api/core/tenant/users/{userId}/destroy': delete: summary: 'User Tenant - Archive (soft-delete) a user by status' operationId: userTenantArchivesoftDeleteAUserByStatus description: "Marks the user as deleted (`status = 'deleted'`). Due to the global scope\n(NonDeletedScope), archived users stop appearing in listings by default.\nNo tenant memberships or roles are removed." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: 'User archived' data: user: id: 101 name: John surname: Doe email: john.doe@example.com status: deleted properties: message: type: string example: 'User archived' data: type: object properties: user: type: object properties: id: type: integer example: 101 name: type: string example: John surname: type: string example: Doe email: type: string example: john.doe@example.com status: type: string example: deleted 404: description: '' content: application/json: schema: type: object example: message: 'User not found in your tenants.' properties: message: type: string example: 'User not found in your tenants.' tags: - Core parameters: - in: path name: userId description: '' example: 1 required: true schema: type: integer - in: path name: user description: 'The user ID.' example: 101 required: true schema: type: integer /api/documentation: get: summary: 'Handles the API request and renders the Swagger documentation view.' operationId: handlesTheAPIRequestAndRendersTheSwaggerDocumentationView description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: status: error message: 'Route [l5-swagger.default.docs] not defined.' properties: status: type: string example: error message: type: string example: 'Route [l5-swagger.default.docs] not defined.' tags: - Endpoints security: [] /api/oauth2-callback: get: summary: 'Handles the OAuth2 callback and retrieves the required file for the redirect.' operationId: handlesTheOAuth2CallbackAndRetrievesTheRequiredFileForTheRedirect description: '' parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: "\n\n\n Swagger UI: OAuth2 Redirect\n\n\n\n\n\n" tags: - Endpoints security: [] /api/logout: post: summary: '' operationId: postApiLogout description: '' parameters: [] responses: { } tags: - Endpoints security: [] /api/event: post: summary: "POST /events\nPermiso requerido: tenant.event.create" operationId: pOSTeventsPermisoRequeridoTenanteventcreate description: '' parameters: [] responses: { } tags: - Endpoints security: [] get: summary: 'Event - index' operationId: eventIndex description: "List all events in the current tenant.\nRequires permission: tenant.event.view" parameters: - in: header name: X-Tenant description: '' example: '{tenant_id}' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: allowed: true permission: tenant.event.view note: 'You can list events in this tenant.' properties: allowed: type: boolean example: true permission: type: string example: tenant.event.view note: type: string example: 'You can list events in this tenant.' tags: - Tenant '/api/event/{id}': get: summary: "GET /events/{id}\nPermiso requerido: tenant.event.show" operationId: gETeventsidPermisoRequeridoTenanteventshow description: '' parameters: [] responses: 500: description: '' content: application/json: schema: type: object example: status: error message: Unauthenticated. properties: status: type: string example: error message: type: string example: Unauthenticated. tags: - Endpoints security: [] put: summary: "PUT/PATCH /events/{id}\nPermiso requerido: tenant.event.update" operationId: pUTPATCHeventsidPermisoRequeridoTenanteventupdate description: '' parameters: [] responses: { } tags: - Endpoints security: [] delete: summary: "DELETE /events/{id}\nPermiso requerido: tenant.event.delete" operationId: dELETEeventsidPermisoRequeridoTenanteventdelete description: '' parameters: [] responses: { } tags: - Endpoints security: [] parameters: - in: path name: id description: 'The ID of the event.' example: architecto required: true schema: type: string /api/settings: get: summary: 'Settings - Visual Configuration' operationId: settingsVisualConfiguration description: 'Devuelve la configuración visual del tenant (colores, logos, fuentes, etc.).' parameters: - in: header name: X-Tenant description: '' example: 'string required El ID del tenant a consultar. Example: web' schema: type: string responses: 200: description: '' content: application/json: schema: type: object example: brand_name: CiberTickets currency: COP timezone: America/Bogota contact_email: soporte@cibertickets.co logo: default: null light: null dark: null favicon: null colors: primary: '#00E5FF' secondary: '#7C3AED' accent: '#22C55E' fonts: heading: Poppins body: Inter theme_mode: system properties: brand_name: type: string example: CiberTickets currency: type: string example: COP timezone: type: string example: America/Bogota contact_email: type: string example: soporte@cibertickets.co logo: type: object properties: default: type: string example: null light: type: string example: null dark: type: string example: null favicon: type: string example: null colors: type: object properties: primary: type: string example: '#00E5FF' secondary: type: string example: '#7C3AED' accent: type: string example: '#22C55E' fonts: type: object properties: heading: type: string example: Poppins body: type: string example: Inter theme_mode: type: string example: system tags: - Tenant security: []