{"openapi":"3.0.0","info":{"title":"TicketDaddy API","version":"2.0.0","description":"Complete REST API for TicketDaddy - Events, Tickets, and NFT Minting."},"servers":[{"url":"https://api.ticketdaddy.io"}],"tags":[{"name":"Health","description":"Service health checks - no authentication required","x-tagGroup":"Health Checks"},{"name":"Events","description":"Event CRUD operations","x-tagGroup":"Events API"},{"name":"Categories","description":"Ticket category management","x-tagGroup":"Events API"},{"name":"Sales & Stats","description":"Door sales and analytics","x-tagGroup":"Events API"},{"name":"Scanning","description":"Ticket validation for event entry","x-tagGroup":"Tickets API"},{"name":"Ticket Lookup","description":"Ticket retrieval and search","x-tagGroup":"Tickets API"},{"name":"Ticket Management","description":"Cancel and reactivate tickets","x-tagGroup":"Tickets API"},{"name":"Minting","description":"NFT minting operations","x-tagGroup":"Mints API"},{"name":"USSD Events","description":"Event discovery via USSD","x-tagGroup":"USSD API"},{"name":"USSD Purchase","description":"Ticket purchase via mobile money","x-tagGroup":"USSD API"}],"x-tagGroups":[{"name":"Health Checks","tags":["Health"]},{"name":"Events API","tags":["Events","Categories","Sales & Stats"]},{"name":"Tickets API","tags":["Scanning","Ticket Lookup","Ticket Management"]},{"name":"Mints API","tags":["Minting"]},{"name":"USSD API","tags":["USSD Events","USSD Purchase"]}],"paths":{"/api/events/health":{"get":{"summary":"Events API Health","description":"Check Events API service health. No authentication required.","tags":["Health"],"responses":{"200":{"description":"Service healthy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"503":{"description":"Service unhealthy"}}}},"/api/tickets/health":{"get":{"summary":"Tickets API Health","description":"Check Tickets API service health. No authentication required.","tags":["Health"],"responses":{"200":{"description":"Service healthy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"503":{"description":"Service unhealthy"}}}},"/api/web3/mint/health":{"get":{"summary":"Minting API Health","description":"Check NFT minting service health including Redis and worker status. No authentication required.","tags":["Health"],"responses":{"200":{"description":"Service healthy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintHealthResponse"}}}},"503":{"description":"Service degraded or unhealthy"}}}},"/api/events":{"get":{"summary":"List Events","description":"List all events for your organization with pagination and filtering.","tags":["Events"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"organizationId","in":"query","schema":{"type":"string"},"description":"Organization ID"},{"name":"status","in":"query","schema":{"type":"string","enum":["DRAFT","PUBLISHED","UPCOMING","ONGOING","COMPLETED","CANCELLED","POSTPONED"]}},{"name":"limit","in":"query","schema":{"type":"integer","default":50}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Events list with pagination"}}},"post":{"summary":"Create Event","description":"Create a new event. Slug is auto-generated from name.","tags":["Events"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEventInput"}}}},"responses":{"200":{"description":"Event created successfully"},"400":{"description":"Validation failed"},"404":{"description":"Organization not found"}}}},"/api/events/{id}":{"get":{"summary":"Get Event","description":"Get event details with ticket categories.","tags":["Events"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Event details"},"404":{"description":"Not found"}}},"put":{"summary":"Update Event","description":"Update event details. Only provided fields are changed.","tags":["Events"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEventInput"}}}},"responses":{"200":{"description":"Event updated"},"404":{"description":"Not found"}}},"delete":{"summary":"Delete Event","description":"Soft delete an event.","tags":["Events"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Event deleted"},"404":{"description":"Not found"}}}},"/api/events/{eventId}/categories":{"get":{"summary":"List Categories","description":"Get all ticket categories for an event.","tags":["Categories"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of categories"}}},"post":{"summary":"Create Category","description":"Create a new ticket category (VIP, Regular, etc.).","tags":["Categories"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCategoryInput"}}}},"responses":{"200":{"description":"Category created"}}}},"/api/events/{eventId}/categories/{paycode}":{"get":{"summary":"Get Category","tags":["Categories"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"}},{"name":"paycode","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Category details"},"404":{"description":"Not found"}}},"put":{"summary":"Update Category","tags":["Categories"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"}},{"name":"paycode","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCategoryInput"}}}},"responses":{"200":{"description":"Category updated"}}},"delete":{"summary":"Delete Category","tags":["Categories"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"}},{"name":"paycode","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Category deleted"},"400":{"description":"Has tickets"}}}},"/api/events/{eventId}/sale":{"post":{"summary":"Door Sale","description":"Create tickets on-the-spot for door/POS sales. Supports cash, mobile money, and card payments. Buyer info is optional for walk-in customers.","tags":["Sales & Stats"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["categoryId"],"properties":{"categoryId":{"type":"string","description":"Ticket category ID (paycode)"},"quantity":{"type":"integer","default":1,"minimum":1,"maximum":10,"description":"Number of tickets (1-10)"},"paymentMethod":{"type":"string","enum":["cash","mobile_money","card"],"default":"cash","description":"Payment method"},"phoneNumber":{"type":"string","description":"Customer phone (required for mobile_money)"},"buyer":{"type":"string","description":"Buyer name (optional - defaults to 'Walk-in')"},"buyerEmail":{"type":"string","format":"email","description":"Buyer's email (optional)"},"recipient":{"type":"string","description":"Recipient name if different from buyer"},"teller":{"type":"string","description":"Name of person making the sale"}}}}}},"responses":{"200":{"description":"Tickets created with receipt","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"receiptCode":{"type":"string","description":"Transaction receipt code (DS-YYYYMMDD-XXXXXX)"},"tickets":{"type":"array","items":{"type":"object","properties":{"ticketCode":{"type":"string"},"recipient":{"type":"string"},"category":{"type":"string"}}}}}},"summary":{"type":"object","properties":{"receiptCode":{"type":"string"},"quantity":{"type":"integer"},"category":{"type":"string"},"categoryId":{"type":"string"},"unitPrice":{"type":"string"},"currency":{"type":"string"},"total":{"type":"number"},"paymentMethod":{"type":"string"},"buyer":{"type":"string"}}}}}}}},"400":{"description":"Sold out or validation error"}}}},"/api/events/{eventId}/sales":{"get":{"summary":"List Sales","description":"Get list of all sold tickets for an event with filtering by date and method.","tags":["Sales & Stats"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"}},{"name":"date","in":"query","schema":{"type":"string"},"description":"Filter by date (YYYY-MM-DD)"},{"name":"method","in":"query","schema":{"type":"string"},"description":"Filter by method (Door Sale, E-Ticket)"},{"name":"limit","in":"query","schema":{"type":"integer","default":100}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Sales list with pagination"}}}},"/api/events/{eventId}/stats/sales":{"get":{"summary":"Sales Statistics","description":"Get sales stats per category with revenue totals.","tags":["Sales & Stats"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sales statistics"}}}},"/api/events/{eventId}/stats/scans":{"get":{"summary":"Scan Statistics","description":"Get check-in stats and recent scans.","tags":["Sales & Stats"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Scan statistics"}}}},"/api/tickets/scan":{"post":{"summary":"Scan Ticket","description":"Validate a ticket for event entry. Detects duplicates and cancelled tickets.","tags":["Scanning"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ticketCode","eventId","organizationId"],"properties":{"ticketCode":{"type":"string","example":"AFRI-ABC123XYZ"},"eventId":{"type":"string"},"organizationId":{"type":"string"}}}}}},"responses":{"200":{"description":"Scan result","content":{"application/json":{"schema":{"type":"object","properties":{"isValid":{"type":"boolean"},"status":{"type":"string","enum":["valid","duplicate","cancelled","invalid"]},"message":{"type":"string"},"ticket":{"type":"object"},"scannedAt":{"type":"string"}}}}}}}}},"/api/tickets/{ticketId}":{"get":{"summary":"Get Ticket by ID","tags":["Ticket Lookup"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"ticketId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Ticket details"},"404":{"description":"Not found"}}}},"/api/tickets/code/{ticketCode}":{"get":{"summary":"Lookup by Code","description":"Find ticket using QR code value.","tags":["Ticket Lookup"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"ticketCode","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Ticket found"},"404":{"description":"Not found"}}}},"/api/tickets/event/{eventId}":{"get":{"summary":"List Event Tickets","description":"Get all tickets for an event with pagination.","tags":["Ticket Lookup"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","default":50}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}},{"name":"sold","in":"query","schema":{"type":"integer","enum":[0,1]}}],"responses":{"200":{"description":"Tickets list"}}}},"/api/tickets/{ticketId}/cancel":{"post":{"summary":"Cancel Ticket","description":"Deactivate a ticket. Will show as invalid when scanned.","tags":["Ticket Management"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"ticketId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string"}}}}}},"responses":{"200":{"description":"Cancelled"},"400":{"description":"Already cancelled"}}}},"/api/tickets/{ticketId}/reactivate":{"post":{"summary":"Reactivate Ticket","description":"Reactivate a previously cancelled ticket.","tags":["Ticket Management"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"ticketId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Reactivated"},"400":{"description":"Already active"}}}},"/api/ussd/health":{"get":{"summary":"USSD API Health","description":"Check USSD API service health. Requires X-USSD-Secret header.","tags":["USSD Events"],"security":[{"UssdSecretAuth":[]}],"responses":{"200":{"description":"Service healthy","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"ok"},"service":{"type":"string","example":"ussd-api"}}}}}}}}},"/api/ussd/events":{"get":{"summary":"List Events by Country","description":"Browse active/published events in a specific country. Used by the USSD menu to show available events.","tags":["USSD Events"],"security":[{"UssdSecretAuth":[]}],"parameters":[{"name":"country","in":"query","required":true,"schema":{"type":"string","enum":["UG","RW"]},"description":"2-letter country code"},{"name":"limit","in":"query","schema":{"type":"integer","default":10,"maximum":50}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Events list with pagination","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UssdEventsResponse"}}}},"400":{"description":"Invalid country code or query parameters"}}}},"/api/ussd/events/{eventId}":{"get":{"summary":"Get Event Details + Ticket Categories","description":"Fetch event details and available ticket categories with pricing and real-time availability.","tags":["USSD Events"],"security":[{"UssdSecretAuth":[]}],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Event details with ticket categories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UssdEventDetailResponse"}}}},"404":{"description":"Event not found"}}}},"/api/ussd/purchase":{"post":{"summary":"Initiate Ticket Purchase","description":"Create a PENDING transaction and send a Flutterwave direct mobile money charge (USSD push) to the buyer's phone. Country and currency are auto-detected from the phone number prefix.","tags":["USSD Purchase"],"security":[{"UssdSecretAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UssdPurchaseInput"}}}},"responses":{"200":{"description":"Payment prompt sent to phone","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UssdPurchaseResponse"}}}},"400":{"description":"Validation error, unsupported country, event not available, or insufficient availability"},"404":{"description":"Event or category not found"},"500":{"description":"Payment config error"},"502":{"description":"Flutterwave charge failed"}}}},"/api/ussd/purchase/{txRef}/status":{"get":{"summary":"Check Purchase Status","description":"Poll transaction status. The USSD menu should poll this every few seconds after initiating a purchase. Returns tickets when COMPLETED.","tags":["USSD Purchase"],"security":[{"UssdSecretAuth":[]}],"parameters":[{"name":"txRef","in":"path","required":true,"schema":{"type":"string"},"description":"Transaction reference from purchase response"}],"responses":{"200":{"description":"Transaction status (PENDING, COMPLETED, or FAILED)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UssdPurchaseStatusResponse"}}}},"404":{"description":"Transaction not found"}}}},"/api/web3/mint":{"post":{"summary":"Batch Mint NFTs","description":"Mint NFT tickets on blockchain. Supports batch minting with gas optimization.","tags":["Minting"],"security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["organizationId","eventId","tickets"],"properties":{"organizationId":{"type":"string"},"eventId":{"type":"string"},"chain":{"type":"string","enum":["lisk","lisk-sepolia"],"default":"lisk-sepolia"},"tickets":{"type":"array","items":{"type":"object","required":["ticketId","recipientAddress"],"properties":{"ticketId":{"type":"string"},"recipientAddress":{"type":"string"},"tokenURI":{"type":"string"}}}}}}}}},"responses":{"200":{"description":"Minting queued"},"400":{"description":"Validation failed"}}}},"/api/web3/mint/status/{jobId}":{"get":{"summary":"Get Mint Status","description":"Check the status of a minting job.","tags":["Minting"],"security":[{"BearerAuth":[]}],"parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job status"},"404":{"description":"Job not found"}}}}},"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","description":"API key from Business Dashboard. Format: Bearer sk_xxx..."},"UssdSecretAuth":{"type":"apiKey","in":"header","name":"X-USSD-Secret","description":"Shared secret for server-to-server USSD API access."}},"schemas":{"HealthResponse":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","unhealthy"],"example":"healthy"},"timestamp":{"type":"string","format":"date-time"},"service":{"type":"string","example":"events-api"}}},"MintHealthResponse":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","unhealthy"]},"timestamp":{"type":"string","format":"date-time"},"service":{"type":"string","example":"minting-api"},"components":{"type":"object","properties":{"redis":{"type":"boolean"},"worker":{"type":"boolean"}}}}},"CreateEventInput":{"type":"object","required":["organizationId","name","category","location","date"],"properties":{"organizationId":{"type":"string"},"name":{"type":"string","example":"AfriFest 2026"},"description":{"type":"string"},"category":{"type":"string","example":"Music"},"location":{"type":"string","example":"Lugogo Cricket Oval"},"date":{"type":"string","example":"2026-03-15"},"startTime":{"type":"string","example":"18:00"},"endTime":{"type":"string","example":"23:00"},"currency":{"type":"string","default":"UGX"},"status":{"type":"string","default":"DRAFT"}}},"UpdateEventInput":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"location":{"type":"string"},"date":{"type":"string"},"status":{"type":"string"}}},"CreateCategoryInput":{"type":"object","required":["category","price"],"properties":{"category":{"type":"string","example":"VIP"},"price":{"type":"number","example":150000},"currency":{"type":"string","default":"UGX"},"admits":{"type":"integer","default":1},"maxLimit":{"type":"integer","default":0}}},"UpdateCategoryInput":{"type":"object","properties":{"category":{"type":"string"},"price":{"type":"number"},"maxLimit":{"type":"integer"}}},"UssdEventsResponse":{"type":"object","properties":{"success":{"type":"boolean"},"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","example":"evt_abc123"},"name":{"type":"string","example":"Nyege Nyege Festival"},"date":{"type":"string","example":"2026-09-15"},"location":{"type":"string","example":"Jinja, Uganda"},"currency":{"type":"string","example":"UGX"},"image":{"type":"string"}}}},"pagination":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"hasNextPage":{"type":"boolean"}}}}},"UssdEventDetailResponse":{"type":"object","properties":{"success":{"type":"boolean"},"event":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"date":{"type":"string"},"startTime":{"type":"string"},"endTime":{"type":"string"},"location":{"type":"string"},"currency":{"type":"string"},"country":{"type":"string"},"image":{"type":"string"},"description":{"type":"string"}}},"categories":{"type":"array","items":{"type":"object","properties":{"paycode":{"type":"string","description":"Ticket category ID"},"name":{"type":"string","example":"VIP"},"price":{"type":"number","example":150000},"currency":{"type":"string","example":"UGX"},"available":{"type":"integer","nullable":true,"description":"Remaining tickets. null = unlimited."}}}}}},"UssdPurchaseInput":{"type":"object","required":["eventId","categoryId","phoneNumber"],"properties":{"eventId":{"type":"string","description":"Event ID"},"categoryId":{"type":"string","description":"Ticket category paycode"},"quantity":{"type":"integer","default":1,"minimum":1,"maximum":10,"description":"Number of tickets (1-10)"},"phoneNumber":{"type":"string","example":"+256712345678","description":"Buyer phone with country prefix (+256 for Uganda, +250 for Rwanda)"},"recipients":{"type":"array","items":{"type":"string"},"description":"Ticket delivery recipients (email or phone). Defaults to buyer phone."},"buyerName":{"type":"string","default":"USSD User","description":"Buyer display name"}}},"UssdPurchaseResponse":{"type":"object","properties":{"success":{"type":"boolean"},"txRef":{"type":"string","example":"USSD-evt_abc1-a7Bx9kQ2mN"},"status":{"type":"string","enum":["PENDING"]},"amount":{"type":"number","example":100000},"currency":{"type":"string","example":"UGX"},"message":{"type":"string","example":"Payment prompt sent to your phone. Please confirm."}}},"UssdPurchaseStatusResponse":{"type":"object","properties":{"success":{"type":"boolean"},"txRef":{"type":"string"},"status":{"type":"string","enum":["PENDING","COMPLETED","FAILED"]},"amount":{"type":"number"},"currency":{"type":"string"},"errorMessage":{"type":"string","description":"Error details when status is FAILED"},"tickets":{"type":"array","description":"Issued tickets when status is COMPLETED","items":{"type":"object","properties":{"ticketCode":{"type":"string"},"recipient":{"type":"string"},"ticketUrl":{"type":"string"}}}}}}}}}