/** * Luqta SDK Types * * This file contains all TypeScript interfaces and types for the Luqta SDK. * The SDK supports two modes: * 1. Custom UI Mode - Developer builds their own UI, SDK provides API integration * 2. Pre-configured UI Mode - SDK provides complete UI with branding customization * * And two API access types: * 1. Application-level APIs - Only require API Key + App ID * 2. End-user APIs - Require API Key + App ID + End User identification */ /** * SDK usage mode */ export type SDKMode = 'custom' | 'preconfigured'; /** * Base configuration shared by both modes */ export interface BaseConfig { /** * Your API key for authentication * @required */ apiKey: string; /** * Application ID * @required */ appId: string; /** * Use production environment * @default false */ production?: boolean; /** * Base URL for API requests (optional, auto-generated based on environment) */ baseURL?: string; /** * Request timeout in milliseconds * @default 30000 */ timeout?: number; /** * Custom headers to include in all requests */ headers?: Record; /** * Enable zero-storage mode (no PII stored, identifier is hashed) * @default false */ zeroStorage?: boolean; /** * Optional full user profile. When provided alongside `user`, the SDK * will automatically call `syncAndInitializeUser` if `initializeUser` * fails with "sync user first" (SDK-USER-001). Covers first-time users * not yet synced to Luqta. */ userProfile?: UserProfile; } /** * Configuration for Custom UI Mode (API-only mode) * Use this when you want to build your own UI and just use the SDK for API calls */ export interface CustomModeConfig extends BaseConfig { /** * SDK mode - 'custom' for API-only integration */ mode: 'custom'; /** * User identification information (required for end-user APIs) * At least one of email, phone_number, username, or uuid is required */ user?: { /** * User email address * Must be a valid email format * @example "user@example.com" */ email?: string; /** * User phone number * Must be in international format with country code * @example "+923001234567" */ phone_number?: string; /** * Username / SDK username * @example "john_doe" */ username?: string; /** * UUID identifier for the user * Must be a valid UUID v4 format * @example "550e8400-e29b-41d4-a716-446655440000" */ uuid?: string; }; } /** * UI Configuration for the configure() method * Used to set up the pre-configured UI after SDK initialization */ export interface UIConfig { /** * Container element ID where SDK UI will be rendered * @required */ containerId: string; /** * Branding customization options */ branding?: BrandingConfig; /** * Language/locale * @default "en" */ locale?: 'en' | 'ar'; /** * Enable RTL layout for Arabic * @default false */ rtl?: boolean; /** * Screens to include in the UI * @default ['contests', 'quizzes', 'rewards', 'profile'] */ screens?: ('contests' | 'quizzes' | 'rewards' | 'profile' | 'notifications' | 'leaderboard')[]; /** * Callback when user completes an action */ onAction?: (action: UIAction) => void; /** * Callback when error occurs */ onError?: (error: LuqtaError) => void; /** * Show a draggable floating profile icon when user is initialized * @default false */ showProfileIcon?: boolean; } /** * Branding configuration for Pre-configured UI Mode */ export interface BrandingConfig { /** * Primary brand color (hex format) * @default "#5304fb" */ primaryColor?: string; /** * Secondary brand color (hex format) * @default "#8f67fd" */ secondaryColor?: string; /** * Background color (hex format) * @default "#ffffff" */ backgroundColor?: string; /** * Text color (hex format) * @default "#111827" */ textColor?: string; /** * Logo URL */ logoUrl?: string; /** * App name to display */ appName?: string; /** * Border radius for UI elements (in pixels) * @default 8 */ borderRadius?: number; /** * Font family * @default "system-ui, -apple-system, sans-serif" */ fontFamily?: string; } /** * Configuration for Pre-configured UI Mode * SDK provides complete UI with customizable branding */ export interface PreconfiguredModeConfig extends BaseConfig { /** * SDK mode - 'preconfigured' for complete UI */ mode: 'preconfigured'; /** * Container element ID where SDK UI will be rendered * @required */ containerId: string; /** * User identification information (required for end-user APIs) * At least one of email, phone_number, username, or uuid is required */ user?: { email?: string; phone_number?: string; username?: string; uuid?: string; }; /** * Branding customization options */ branding?: BrandingConfig; /** * Language/locale * @default "en" */ locale?: 'en' | 'ar'; /** * Enable RTL layout for Arabic * @default false */ rtl?: boolean; /** * Screens to include in the UI * @default ['contests', 'quizzes', 'rewards', 'profile'] */ screens?: ('contests' | 'quizzes' | 'rewards' | 'profile' | 'notifications' | 'leaderboard')[]; /** * Callback when user completes an action */ onAction?: (action: UIAction) => void; /** * Callback when error occurs */ onError?: (error: LuqtaError) => void; /** * Show a draggable floating profile icon when user is initialized * @default false */ showProfileIcon?: boolean; } /** * Union type for SDK configuration */ export type LuqtaConfig = CustomModeConfig | PreconfiguredModeConfig; /** * Legacy config format (for backward compatibility) * @deprecated Use CustomModeConfig or PreconfiguredModeConfig instead */ export interface LegacyConfig { apiKey: string; appId: string; production?: boolean; baseURL?: string; user: { email?: string; phone_number?: string; username?: string; uuid?: string; }; timeout?: number; headers?: Record; } /** * User profile data for sync operations. * At least one identifier (email, phone_number, username, or uuid) is required. */ export interface UserProfile { /** * User's email address */ email?: string; /** * User's phone number (E.164 format) * @example "+923001234567" */ phone_number?: string; /** * Username / SDK username identifier * @example "john_doe" */ username?: string; /** * UUID identifier for the user (v4 format) * @example "550e8400-e29b-41d4-a716-446655440000" */ uuid?: string; /** * External user ID from your system */ user_id?: string; /** * SDK-specific user ID */ sdk_user_id?: string; /** * User's full name */ name?: string; /** * User's date of birth (YYYY-MM-DD format) */ dob?: string | null; /** * User's gender */ gender?: 'male' | 'female' | 'other' | string; /** * User's country code (ISO 3166-1 alpha-2) * @example "PK", "US", "UK" */ country?: string; /** * Whether user is verified */ Verified?: boolean; /** * Profile image URL */ image_url?: string; /** * List of user interests */ interested_in?: string[]; /** * Whether user accepted policy/terms */ policy_accept?: boolean; } /** * User identification for end-user APIs. * At least one identifier is required: email, phone_number, username, or uuid. */ export interface UserIdentification { email?: string; phone_number?: string; username?: string; uuid?: string; } /** * User profile response (from /sdk/app/user/profile API) */ export interface UserProfileResponse { success: boolean; data: { user: { id: number; name: string; email: string; phone_number: string; verified: boolean; total_points: number; profile_image?: string; }; statistics: { total_contests_joined: number; completed_contests: number; in_progress_contests: number; total_levels_completed: number; }; }; } /** * User sync response (from /sdk/app/user/sync API) */ export interface UserSyncResponse { success: boolean; code: 'SDK-USER-CREATED' | 'SDK-USER-UPDATED' | 'SDK-USER-NO-CHANGES'; user: { id: number; name: string; email: string; phone_number: string; country: string; status: string; verified: boolean; total_points: number; profile_image?: string; }; changes?: { fields_updated: string[]; updated_count: number; }; } /** * HTTP request options */ export interface RequestOptions { method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; headers?: Record; body?: any; params?: Record; } /** * API Response wrapper */ export interface ApiResponse { success: boolean; data?: T; message?: string; code?: string; error?: { code: string; message: string; }; } /** * Paginated API Response */ export interface PaginatedResponse { success: boolean; message?: string; data: { items: T[]; itemsReceived: number; curPage: number; nextPage: number | null; prevPage: number | null; offset: number; itemsTotal: number; pageTotal: number; }; } /** * Contest entity (from /sdk/app/contest/all API) */ export interface Contest { id: number; name: string; arabic_name?: string; details: string; arabic_details?: string; type: 'public' | 'private'; no_of_users: number; format_of_contest: 'integrated' | 'non-integrated' | string; /** Contest start date — ISO-8601 string or numeric epoch (usually ms). */ start_date: string | number; /** Contest end date — ISO-8601 string or numeric epoch (usually ms). */ end_date: string | number; prize_announce_date?: string | number; status: 'approved' | 'rejected' | 'pending' | 'draft' | 'completed'; total_points: number; number_of_winners: number; View_Type?: 'VIP' | 'Recent Contest' | 'Regular'; sharingSetting?: 'shared' | 'single'; active?: boolean; is_draw_completed?: boolean; banners: ContestBanner[]; levels?: Level[]; prizes?: Prize[]; participate_progress?: ParticipateProgress; user_ids?: ContestCompany[]; trending_score?: number; participant_stats?: { total_joined: number; completed: number; in_progress: number; }; } /** * Company associated with a contest */ export interface ContestCompany { company: { id: number; created_at: number; name: string; email?: string; business_logo?: ContestBanner[]; business_banner?: ContestBanner[] | null; }; } export interface ContestBanner { url: string; name: string; type: string; mime: string; size?: number; } export interface ParticipateProgress { participant_id?: number; status: 'in_progress' | 'completed' | 'not_started'; participate_details?: { id: number; name: string; total_points: number; }; } /** * Contest progress response (from /sdk/app/contest/compete API) */ export interface ContestProgressResponse { contest_id: number; contest_name: string; status: 'in_progress' | 'completed'; show_congratulations: boolean; isratingpopupshow: boolean; progress: { total_levels: number; completed_levels: number; completion_percentage: number; points_earned: number; time_spent_ms: number; }; levels: LevelWithProgress[]; prizes: Prize[]; } /** * Contest details with progress (from /sdk/app/contest/details-progress API) */ export interface ContestDetailsProgress { id: number; name: string; details: string; start_date: string | number; end_date: string | number; status: string; levels: LevelWithProgress[]; contest_prizes: Prize[]; draw_rules?: Record; } /** * Contest level */ export interface Level { id: number; contest_id?: number; level_type: 'text' | 'qr' | 'link' | 'image' | 'quiz' | 'client_webhook' | 'luqta_webhook' | 'luqta_weebhook'; name: string; arabic_name?: string; description: string; arabic_description?: string; points: number; /** * Start date. Backend may emit either an ISO-8601 string or a numeric * epoch timestamp (usually milliseconds). */ start_date?: string | number; /** * End date. Same type rules as [start_date]. */ end_date?: string | number; /** * End-of-level marker used by the backend. May arrive as an ISO string * or a numeric epoch (seconds or milliseconds). Used as a fallback when * `end_date` is absent. */ level_timeline?: string | number; textContent?: string; qrData?: string; link?: string; image?: LevelImage; quizzes_id?: number; /** * Luqta-hosted webhook URL for `luqta_webhook` levels. UI shows a button * that opens this URL in a new tab; visiting the URL marks the step done. */ luqta_webhook_url?: string; /** * Client-hosted webhook URL for `client_webhook` levels. Variables * collected from [client_variables] are POSTed to this URL. */ client_webhook_url?: string; /** Variable descriptors driving the dynamic `client_webhook` form. */ client_variables?: ClientVariable[]; } /** * One input descriptor for a `client_webhook` level. Drives a single field * in the dynamically-rendered completion form. */ export interface ClientVariable { variable_name: string; display_name: string; datatype: string; } /** * Level progress item from API */ export interface LevelProgressItem { id?: number; created_at?: number; status: 'completed' | 'in_progress' | 'not_started'; } /** * Level with progress status (from contest/details-progress API) * Note: level_progress is an ARRAY from the API, not an object */ export interface LevelWithProgress extends Level { level_progress?: LevelProgressItem[] | LevelProgressItem; isCompleted?: boolean; completed_at?: string; } export interface LevelImage { url: string; name: string; type: string; mime: string; } /** * Level completion request */ export interface LevelCompleteRequest { level_id: number; textContent?: string; qrCode?: string; link?: string; image?: string; } /** * Level completion response (from /sdk/app/contest/level/complete API) */ export interface LevelCompleteResponse { success: boolean; level: { id: number; name: string; type: string; points: number; isComplete: boolean; }; user: { id: number; name: string; }; progress: { status: 'completed'; points_earned: number; }; match_details?: { type: string; provided: string; matched: boolean; }; } /** * Level congratulation response (from /sdk/app/level/congratulation API) */ export interface LevelCongratulationResponse { success: boolean; points_earned: number; time_spent_in_level: string; level_name: string; contest_name: string; share_points?: number; next_level_id?: number; is_contest_completed?: boolean; } /** * Quiz entity */ export interface Quiz { id: number; title: string; description: string; total_questions: number; total_marks: number; passing_marks: number; has_time_tracking: boolean; max_time_seconds?: number; } /** * Quiz question */ export interface QuizQuestion { id: number; question: string; question_order: number; marks: number; question_number?: number; options: QuizOption[]; is_answered: boolean; selected_option_id?: number | null; is_correct?: boolean | null; } export interface QuizOption { id: number; option_text: string; } /** * Quiz attempt */ export interface QuizAttempt { id: number; quiz_id: number; user_id: number; started_at: string; status: 'in_progress' | 'completed'; is_new: boolean; elapsed_time_seconds: number; } /** * Quiz progress */ export interface QuizProgress { current_question_index: number; current_question_number?: number; total_questions: number; answered_questions: number; remaining_questions: number; progress_percentage: number; correct_answers: number; is_completed: boolean; } /** * Quiz start response (from /sdk/app/quiz/start API) */ export interface QuizStartResponse { success: boolean; data: { attempt: QuizAttempt; quiz: Quiz; progress: QuizProgress; current_question: QuizQuestion; full_quiz: QuizQuestion[]; instructions: { flow: 'progressive'; rules: string[]; navigation: { can_skip: boolean; must_answer_correctly: boolean; }; }; }; } /** * Quiz answer response (from /sdk/app/quiz/attempt/answer API) */ export interface QuizAnswerResponse { success: boolean; message: string; data: { answer: { question_id: number; option_id: number; is_correct: boolean; is_update: boolean; answered_at: string; }; current_question: QuizQuestion | null; progress: QuizProgress; navigation: { has_next_question: boolean; can_proceed: boolean; }; timing: { elapsed_seconds: number; max_time_seconds: number | null; time_remaining_seconds: number | null; }; can_proceed: boolean; }; } /** * Quiz submit response (from /sdk/app/quiz/attempt/submit API) */ export interface QuizSubmitResponse { success: boolean; attempt: { id: number; status: 'completed'; submitted_at: string; }; results: { completed_successfully: boolean; obtained_marks: number; total_marks: number; score_percentage: number; result_status: string; }; statistics: { total_questions: number; answered: number; unanswered: number; correct_answers: number; incorrect_answers: number; accuracy_percentage: number; }; time: { time_taken_seconds: number; time_taken_formatted: string; max_time_seconds: number | null; }; performance: { grade: 'A+' | 'A' | 'B' | 'C' | 'D' | 'F'; remarks: string; }; } /** * Quiz result (simplified for UI) */ export interface QuizResult { score: number; total_marks: number; percentage: number; grade: 'A+' | 'A' | 'B' | 'C' | 'D' | 'F'; passed: boolean; correct_count: number; incorrect_count: number; time_taken: string; } /** * Prize entity */ export interface Prize { id: number; name: string; description: string; value: number; contest_id: number; timeline?: string; reward_status?: string; categories_id?: number; image?: { url: string; name: string; }; } /** * Reward entity */ export interface Reward { id: number; name: string; description: string; points_required: number; image_url?: string; category?: string; } /** * User earnings */ export interface UserEarnings { total_points: number; available_points: number; redeemed_points: number; pending_points: number; } /** * Notification entity */ export interface Notification { id: number; title: string; message: string; type: 'contest' | 'level' | 'reward' | 'system'; is_read: boolean; created_at: string; data?: Record; } /** * UI action types for callbacks */ export interface UIAction { type: 'contest_joined' | 'level_completed' | 'quiz_completed' | 'reward_redeemed' | 'profile_updated'; data: Record; } /** * Error class for API errors */ export declare class LuqtaError extends Error { message: string; code: string; status?: number | undefined; payload?: any | undefined; constructor(message: string, code: string, status?: number | undefined, payload?: any | undefined); } /** * Application-level API endpoints (only require API Key + App ID) * These don't need end-user authentication */ export declare const APPLICATION_ENDPOINTS: { readonly GET_ALL_CONTESTS: "/sdk/app/contest/all"; readonly GET_TRENDING_CONTESTS: "/sdk/app/contest/trending"; readonly GET_PREMIUM_CONTESTS: "/sdk/app/contest/premium"; readonly GET_RECENT_CONTESTS: "/sdk/app/contest/recently"; readonly GET_CATEGORIES: "/sdk/app/categories"; readonly GET_REWARDS: "/sdk/app/reward/list"; }; /** * End-user API endpoints (require API Key + App ID + User identification) * These require user to be authenticated */ export declare const USER_ENDPOINTS: { readonly INITIALIZE: "/sdk/app/initialize"; readonly INITIALIZE_USER: "/sdk/app/initialize/user"; readonly SYNC_USER: "/sdk/app/user/sync"; readonly GET_PROFILE: "/sdk/app/user/profile"; readonly DELETE_ACCOUNT: "/sdk/app/contest/account-delete"; readonly PARTICIPATE: "/sdk/app/contest/participate"; readonly GET_CONTEST_PROGRESS: "/sdk/app/contest/details-progress"; readonly GET_CONTEST_HISTORY: "/sdk/app/contest/history"; readonly CHECK_CONTEST_TYPE: "/sdk/app/contest/check-type"; readonly COMPLETE_LEVEL: "/sdk/app/contest/level/complete"; readonly COMPLETE_LEVEL_IMAGE: "/sdk/app/contest/level/complete/image-type"; readonly COMPLETE_CLIENT_WEBHOOK: "/sdk/app/client-webhook"; readonly UPDATE_LEVEL_PROGRESS: "/sdk/app/contest/level/update-inprogress"; readonly GET_LEVEL_CONGRATULATION: "/sdk/app/level/congratulation"; readonly SCAN_QR: "/sdk/app/contest/scan-qr"; readonly START_QUIZ: "/sdk/app/quiz/start"; readonly SUBMIT_ANSWER: "/sdk/app/quiz/attempt/answer"; readonly SUBMIT_QUIZ: "/sdk/app/quiz/attempt/submit"; readonly GET_EARNINGS: "/sdk/app/contest/user-earnings"; readonly GET_USER_ACTIVITIES: "/sdk/app/contest/user-activites"; readonly GET_USER_PROGRESS: "/sdk/app/contest/user-progress"; readonly REDEEM_REWARD: "/sdk/app/contest/reward/redeem"; readonly GET_REWARD_HISTORY: "/sdk/app/contest/reward-history"; readonly GET_PRIZE_HISTORY: "/sdk/app/prize/history"; readonly UPDATE_PRIZE_STATUS: "/sdk/app/prize/status"; readonly GET_NOTIFICATIONS: "/sdk/app/contest/get-notification"; readonly MARK_NOTIFICATIONS_READ: "/sdk/app/contest/mark-notifications-read"; readonly UPDATE_NOTIFICATION_SETTINGS: "/sdk/contest/app/notification/update"; readonly GET_AVAILABLE_TASKS: "/sdk/app/contest/get-available-tasks"; readonly START_TASK: "/sdk/app/task/start"; readonly ON_CONTEST_CLICK: "/sdk/app/contest/on_contest_click"; readonly SEND_REFERRAL: "/sdk/app/contest/referral/send"; readonly SUBMIT_FEEDBACK: "/sdk/app/contest/app-feedback"; }; export type ApplicationEndpoint = typeof APPLICATION_ENDPOINTS[keyof typeof APPLICATION_ENDPOINTS]; export type UserEndpoint = typeof USER_ENDPOINTS[keyof typeof USER_ENDPOINTS];