Download the purchased resource from CFX Portal, the official FiveM site for purchased resources.Put the aps_cityhall folder into your resources directory. Keep the folder name: other scripts call its exports as exports['aps_cityhall'].
Nothing to import. Every table is created automatically on the first start and upgraded on later versions. The database user needs the CREATE and ALTER rights.
If you prefer to create the tables yourself, run sql/aps_cityhall.sql (it works for ESX, QBCore and Qbox).
Open your database in HeidiSQL, phpMyAdmin or the txAdmin database tab, open a new query window, paste the SQL below and run it.
Database (optional, ESX / QBCore / Qbox)
-- APS City Hall — Database Schema-- Optional: every table is also created automatically on start.-- Run it if you prefer to create the tables yourself.-- NOTE: If upgrading from nt_licensecenter, run:-- RENAME TABLE nt_licenses TO aps_licenses;-- RENAME TABLE nt_license_cooldowns TO aps_license_cooldowns;CREATE TABLE IF NOT EXISTS `aps_licenses` ( `id` INT NOT NULL AUTO_INCREMENT, `identifier` VARCHAR(60) NOT NULL, `license_id` VARCHAR(50) NOT NULL, `issued_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_license` (`identifier`, `license_id`), KEY `idx_identifier` (`identifier`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;CREATE TABLE IF NOT EXISTS `aps_license_cooldowns` ( `identifier` VARCHAR(60) NOT NULL, `license_id` VARCHAR(50) NOT NULL, `last_attempt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`identifier`, `license_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;CREATE TABLE IF NOT EXISTS `aps_documents` ( `id` INT NOT NULL AUTO_INCREMENT, `identifier` VARCHAR(60) NOT NULL, `doc_type` VARCHAR(50) NOT NULL, `serial` VARCHAR(30) NULL DEFAULT NULL, `issued_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `expires_at` TIMESTAMP NOT NULL, `price_paid` INT NOT NULL DEFAULT 0, `revoked` TINYINT NOT NULL DEFAULT 0, `data` LONGTEXT NULL, PRIMARY KEY (`id`), UNIQUE KEY `uk_serial` (`serial`), KEY `idx_ident` (`identifier`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;CREATE TABLE IF NOT EXISTS `aps_vehicle_insurance` ( `id` INT NOT NULL AUTO_INCREMENT, `identifier` VARCHAR(60) NOT NULL, `plate` VARCHAR(20) NOT NULL, `model` VARCHAR(50) NOT NULL, `expires_at` TIMESTAMP NOT NULL, `price_paid` INT NOT NULL DEFAULT 0, `issued_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_ident` (`identifier`), KEY `idx_plate` (`plate`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;CREATE TABLE IF NOT EXISTS `aps_bills` ( `id` INT NOT NULL AUTO_INCREMENT, `identifier` VARCHAR(60) NOT NULL, `type` VARCHAR(30) NOT NULL, `status` VARCHAR(20) NOT NULL DEFAULT 'unpaid', `issuer` VARCHAR(100) NOT NULL, `issuer_job` VARCHAR(50) NOT NULL DEFAULT '', `amount` INT NOT NULL, `due_at` TIMESTAMP NULL DEFAULT NULL, `paid_at` TIMESTAMP NULL DEFAULT NULL, `issued_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `data` LONGTEXT NOT NULL, PRIMARY KEY (`id`), KEY `idx_ident` (`identifier`), KEY `idx_status` (`status`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;-- Mini-games: best score per player and game-- (the resource also creates / upgrades this table on start)CREATE TABLE IF NOT EXISTS `aps_game_scores` ( `identifier` VARCHAR(60) NOT NULL, `game` VARCHAR(20) NOT NULL DEFAULT 'tower', `name` VARCHAR(100) NOT NULL, `best_score` INT NOT NULL DEFAULT 0, `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`identifier`, `game`), KEY `idx_game_score` (`game`, `best_score`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;-- Business Register (also created automatically on start)CREATE TABLE IF NOT EXISTS `aps_businesses` ( `id` INT NOT NULL AUTO_INCREMENT, `owner` VARCHAR(60) NOT NULL, `owner_name` VARCHAR(100) NOT NULL, `name` VARCHAR(60) NOT NULL, `category` VARCHAR(30) NOT NULL, `description` VARCHAR(400) NOT NULL DEFAULT '', `phone` VARCHAR(20) NOT NULL DEFAULT '', `status` VARCHAR(10) NOT NULL DEFAULT 'active', `fee_paid` INT NOT NULL DEFAULT 0, `review_note` VARCHAR(300) NOT NULL DEFAULT '', `reviewed_by` VARCHAR(100) NOT NULL DEFAULT '', `reviewed_at` TIMESTAMP NULL DEFAULT NULL, `job` VARCHAR(50) NOT NULL DEFAULT '', `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_owner` (`owner`), KEY `idx_status` (`status`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;-- Business permits, vehicles, employees, inspections (also created automatically on start)CREATE TABLE IF NOT EXISTS `aps_business_permits` ( `id` INT NOT NULL AUTO_INCREMENT, `business_id` INT NOT NULL, `permit` VARCHAR(40) NOT NULL, `status` VARCHAR(10) NOT NULL DEFAULT 'pending', `days` INT NOT NULL DEFAULT 0, `price_paid` INT NOT NULL DEFAULT 0, `expires_at` TIMESTAMP NULL DEFAULT NULL, `review_note` VARCHAR(300) NOT NULL DEFAULT '', `reviewed_by` VARCHAR(100) NOT NULL DEFAULT '', `reviewed_at` TIMESTAMP NULL DEFAULT NULL, `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_business` (`business_id`, `permit`, `status`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;CREATE TABLE IF NOT EXISTS `aps_business_vehicles` ( `plate` VARCHAR(20) NOT NULL, `business_id` INT NOT NULL, `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`plate`), KEY `idx_business` (`business_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;CREATE TABLE IF NOT EXISTS `aps_business_employees` ( `business_id` INT NOT NULL, `identifier` VARCHAR(60) NOT NULL, `name` VARCHAR(100) NOT NULL, `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`business_id`, `identifier`), KEY `idx_identifier` (`identifier`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;CREATE TABLE IF NOT EXISTS `aps_business_inspections` ( `id` INT NOT NULL AUTO_INCREMENT, `business_id` INT NOT NULL, `inspector` VARCHAR(100) NOT NULL, `result` VARCHAR(50) NOT NULL, `notes` VARCHAR(500) NOT NULL DEFAULT '', `fine` INT NOT NULL DEFAULT 0, `bill_id` INT NULL DEFAULT NULL, `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_business` (`business_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;-- Government Portal activity log (also created automatically on start)CREATE TABLE IF NOT EXISTS `aps_gov_log` ( `id` INT NOT NULL AUTO_INCREMENT, `actor` VARCHAR(60) NOT NULL, `actor_name` VARCHAR(100) NOT NULL, `action` VARCHAR(40) NOT NULL, `target` VARCHAR(100) NOT NULL DEFAULT '', `details` VARCHAR(300) NOT NULL DEFAULT '', `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_created` (`created_at`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;-- License card photos (also created automatically on start)CREATE TABLE IF NOT EXISTS `aps_mugshots` ( `identifier` VARCHAR(60) NOT NULL, `image` MEDIUMTEXT NOT NULL, `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`identifier`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;-- ═════════════════════════════════════════════-- 3.7.0 — taxes, treasury, license suspension, penalty points,-- paychecks, Job Center (all also created automatically on start)-- ═════════════════════════════════════════════-- Scheduler: last period each job ranCREATE TABLE IF NOT EXISTS `aps_scheduler` ( `name` VARCHAR(60) NOT NULL, `last_key` VARCHAR(20) NOT NULL, PRIMARY KEY (`name`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;-- Personal taxesCREATE TABLE IF NOT EXISTS `aps_taxes` ( `id` INT NOT NULL AUTO_INCREMENT, `identifier` VARCHAR(60) NOT NULL, `title` VARCHAR(100) NOT NULL, `category` VARCHAR(30) NOT NULL DEFAULT 'other', `base_amount` INT NOT NULL DEFAULT 0, `percent` DECIMAL(6,2) NOT NULL DEFAULT 0, `amount` INT NOT NULL, `status` VARCHAR(20) NOT NULL DEFAULT 'unpaid', `ref` VARCHAR(80) NULL DEFAULT NULL, `issued_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `due_at` TIMESTAMP NULL DEFAULT NULL, `paid_at` TIMESTAMP NULL DEFAULT NULL, `paid_amount` INT NOT NULL DEFAULT 0, `auto` TINYINT(1) NOT NULL DEFAULT 0, PRIMARY KEY (`id`), UNIQUE KEY `uniq_ref` (`identifier`, `ref`), KEY `idx_identifier` (`identifier`, `status`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;-- Business taxes per account and monthCREATE TABLE IF NOT EXISTS `aps_business_taxes` ( `id` INT NOT NULL AUTO_INCREMENT, `account` VARCHAR(60) NOT NULL, `period` CHAR(7) NOT NULL, `earned` BIGINT NOT NULL DEFAULT 0, `tax_amount` INT NOT NULL DEFAULT 0, `status` VARCHAR(20) NOT NULL DEFAULT 'open', `paid_amount` INT NOT NULL DEFAULT 0, `paid_by` VARCHAR(100) NULL DEFAULT NULL, `paid_at` TIMESTAMP NULL DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `uniq_period` (`account`, `period`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;-- City treasury (one row)CREATE TABLE IF NOT EXISTS `aps_treasury` ( `id` TINYINT NOT NULL, `balance` BIGINT NOT NULL DEFAULT 0, `total_earned` BIGINT NOT NULL DEFAULT 0, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;-- Treasury ledgerCREATE TABLE IF NOT EXISTS `aps_treasury_log` ( `id` INT NOT NULL AUTO_INCREMENT, `amount` BIGINT NOT NULL, `reason` VARCHAR(120) NOT NULL, `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_created` (`created_at`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;-- License suspensionsCREATE TABLE IF NOT EXISTS `aps_license_suspensions` ( `id` INT NOT NULL AUTO_INCREMENT, `identifier` VARCHAR(60) NOT NULL, `license_id` VARCHAR(50) NOT NULL, `until` TIMESTAMP NULL DEFAULT NULL, `reason` VARCHAR(200) NOT NULL DEFAULT '', `by_name` VARCHAR(100) NOT NULL DEFAULT '', `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `lifted_at` TIMESTAMP NULL DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_active` (`identifier`, `license_id`, `lifted_at`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;-- Penalty pointsCREATE TABLE IF NOT EXISTS `aps_penalty_points` ( `id` INT NOT NULL AUTO_INCREMENT, `identifier` VARCHAR(60) NOT NULL, `points` INT NOT NULL, `reason` VARCHAR(200) NOT NULL DEFAULT '', `bill_id` INT NULL DEFAULT NULL, `issued_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `expires_at` TIMESTAMP NULL DEFAULT NULL, `removed` TINYINT(1) NOT NULL DEFAULT 0, PRIMARY KEY (`id`), KEY `idx_identifier` (`identifier`, `removed`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;-- Paychecks waiting at City HallCREATE TABLE IF NOT EXISTS `aps_paychecks` ( `identifier` VARCHAR(60) NOT NULL, `balance` BIGINT NOT NULL DEFAULT 0, `total` BIGINT NOT NULL DEFAULT 0, `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`identifier`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;-- Paycheck historyCREATE TABLE IF NOT EXISTS `aps_paycheck_log` ( `id` INT NOT NULL AUTO_INCREMENT, `identifier` VARCHAR(60) NOT NULL, `amount` INT NOT NULL, `label` VARCHAR(100) NOT NULL DEFAULT '', `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_identifier` (`identifier`, `created_at`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;-- Job applicationsCREATE TABLE IF NOT EXISTS `aps_resumes` ( `id` INT NOT NULL AUTO_INCREMENT, `identifier` VARCHAR(60) NOT NULL, `name` VARCHAR(100) NOT NULL, `job` VARCHAR(60) NOT NULL, `answers` TEXT NOT NULL, `status` VARCHAR(20) NOT NULL DEFAULT 'pending', `reviewed_by` VARCHAR(100) NULL DEFAULT NULL, `reviewed_at` TIMESTAMP NULL DEFAULT NULL, `note` VARCHAR(300) NOT NULL DEFAULT '', `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_job` (`job`, `status`), KEY `idx_identifier` (`identifier`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;-- Job Center: applications open / closed per jobCREATE TABLE IF NOT EXISTS `aps_resume_settings` ( `job` VARCHAR(60) NOT NULL, `allowed` TINYINT(1) NOT NULL DEFAULT 1, PRIMARY KEY (`job`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;INSERT IGNORE INTO `aps_treasury` (id, balance, total_earned) VALUES (1, 0, 0);
On start City Hall also adds the vin and vin_hidden columns to your owned vehicles table (Config.VIN.autoMigrate). See Database for the full table list.
The Government Portal can be opened by job, by login or both (Config.Government.access). If you want job access, add a government job. The grades match the default roles in goverment.lua: grade 0 = Clerk, grade 2 = Manager, grade 4 = Mayor. Salaries are examples.
Login accounts are set in config/config.server.lua → Config.GovernmentAccounts. Accounts with the password change-me are disabled. Change the example passwords before going live.
Start aps_cityhall in your server.cfgafter your framework, target, inventory and banking resources so they are detected:
ensure oxmysqlensure es_extended # or qb-core / qbx_core# Here you run your other resources like ox_target, ox_lib, ox_inventory, phone etc.# APS Resourcesensure MugShotBase64 # optional, document photosensure aps_cityhall
Then restart the server, go to the City Hall blip on the map and talk to the clerk.
On first start the console prints nothing unless something is wrong. Table upgrades are logged as [aps_cityhall] Upgraded ….