[{"data":1,"prerenderedAt":902},["ShallowReactive",2],{"site":3,"docs-slug-site":15,"docs-product-en-x3d-mailbox":21,"docs-products-en":90,"docs-html-en-x3d-mailbox":868},{"site":4,"contact":10,"seo":13,"payment":14},{"name":5,"host":6,"default_locale":7,"locales":8},"X3D Developer","fivem.x3d-developer.com","th",[7,9],"en",{"discord_invite":11,"email":12,"line":12},"https:\u002F\u002Fdiscord.gg\u002FNA5kPVynFv","",{"google_site_verification":12,"bing_site_verification":12},{"bank_name":12,"account_name":12,"account_no":12,"promptpay_id":12},{"site":16,"contact":18,"seo":19,"payment":20},{"name":5,"host":6,"default_locale":7,"locales":17},[7,9],{"discord_invite":11,"email":12,"line":12},{"google_site_verification":12,"bing_site_verification":12},{"bank_name":12,"account_name":12,"account_no":12,"promptpay_id":12},{"id":22,"slug":23,"name":24,"summary":25,"price_thb":26,"license_mode":27,"cover_key":28,"cover_url":29,"category_slugs":30,"tags":32,"latest_version":51,"latest_released_at":52,"published_at":53,"has_docs":54,"config":55,"rent_price_satang":56,"description_md":57,"docs_md":58,"seo_title":59,"seo_description":60,"media":61,"versions":75},"83c7d7cb-bde4-45e3-a552-d7e377e4dc5d","x3d-mailbox","X3D Mailbox","Free offline mailbox with item and money attachments plus \u002Fredeem codes, no database required — Mail and Safe tabs, any framework through adapter files.",0,"none","public\u002Fproducts\u002Fx3d-mailbox\u002Fcover\u002F743a9e72c1ae8d6d.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-mailbox\u002Fcover\u002F743a9e72c1ae8d6d.jpg",[31],"gameplay",[33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50],"esx","free","mailbox","redeem code","standalone","กล่องจดหมาย","ของแนบ","ฟรี","รีดีมโค้ด","ส่งของออฟไลน์","โค้ดรับของ","กรอกโค้ดรับของ","จดหมายออฟไลน์","ส่งของให้คนออฟไลน์","โค้ดแจกของ","แจกของกิจกรรม","ของชดเชย","ไม่ต้องใช้ฐานข้อมูล","1.7.2","2026-10-12T17:22:30.892527Z","2026-09-19T19:05:39.140076Z",true,"public",null,"# An offline mailbox with attachments — free, no database required\n\nA player is offline but still owed an event prize, a compensation item, or a note from an admin — `x3d_mailbox` lets you send a mail with attachments and let them claim it whenever they log back in, through a ready-made Nuxt 4 panel. Works with any framework through editable adapter files.\n\n---\n\n## Features\n\n- [+] Easy setup: tune everything in config, or set it through the web builder\n- [+] Send mail with attachments to offline players, or to everyone\n- [+] Several items plus cash, black money or bank in a single mail\n- [+] Mail expiry with a red countdown warning and a default lifetime\n- [+] Separate Mail and Safe tabs, each with its own unread count\n- [+] \u002Fredeem codes with use caps, one per player and an expiry time\n- [+] A full bag never loses the reward: it waits in the mail\n- [+] Claim all in one click, with double-claim and spam protection\n- [+] Unread mail count shown when a player joins\n- [+] JSON file storage with no database, or switch to MySQL\n- [+] Easy move from other mailboxes: SendMail accepts their format\n- [+] Hook into other scripts through addons\u002F\n\n---\n\n## Attach items and money together\n\n`SendMail`\u002F`SendMailAll` can attach several items and several money accounts (`money`, `bank`, `black_money`, or your framework's own) in a single mail. Set an expiry, set a custom sender name.\n\nMoving from another mailbox? `SendMail` also accepts the format other mailboxes use (`subject`, `cash`\u002F`bank`, `items = {{ name, count }}`, `expiresInDays`), so switching is just a rename of the export.\n\n## Works with any framework\n\nFour files under `addons\u002F` — framework, notify, reward, storage — default to working with ESX out of the box, and fall back to standalone (ace only) with no framework installed. QBCore \u002F ox_lib examples are commented in, ready to swap in.\n\n## No database required\n\nData is stored as a JSON file inside the resource itself, loaded once and flushed every 30 seconds, on player drop, and on a graceful stop or restart. A hard crash mid-session doesn't lose attachments — the real risk runs the other way: a mail claimed inside that last unflushed window (≤30 seconds) has already paid out through the framework, but the on-disk `claimed` flag never caught up, so a restart can let the same mail be opened and paid out again. Need MySQL for a busier server? Set `Config.Storage.Driver = 'oxmysql'` and mail is kept in the `x3d_mailbox` table, created automatically (no `@oxmysql` include needed).\n\n## Can't be claimed twice, a broken reward can't lock a player out\n\nThe claimed flag is written to storage before anything is paid out, so a duplicate claim event can never pay twice. If a misspelled item key makes the reward throw, the mail still gets marked claimed instead of leaving the player stuck retrying forever. Attachment counts are always floored to whole numbers, and the mail cap never deletes a mail that hasn't been claimed yet.\n\n## Built-in redeem codes\n\nHand out welcome, event or compensation codes without another script. A player types `\u002Fredeem \u003Ccode>` or enters it in the mailbox panel, and the reward, items and money alike, is **delivered as mail**, so a full bag never loses it. You can deliver into the Safe tab instead.\n\n- Permanent codes in `Config.Codes`: a server-wide use cap (`maxUses`), one per player (`oncePerPlayer`) and an expiry time (`expires`)\n- Runtime codes from other scripts through exports (`AddCode`, `RemoveCode`, `GetCodeUsage`), for stream or event codes\n- Code usage survives restarts, and `\u002Fredeem` shares the claim throttle and lock, so spamming it still pays out once\n\n## Requirements\n\nNone. No database, no framework, no license. Drop it in and `ensure` it.\n\n**Free** · modify it as you like · just don't resell it or re-upload it under another name.\n","## Installation\n\n1. Unzip and **rename the folder to `x3d_mailbox`** (other scripts call the exports by this name)\n2. Drop it in `resources\u002F`\n3. Add to `server.cfg`:\n\n```\nensure x3d_mailbox\n```\n\nDone — data is stored in `data\u002Fmailbox.json` inside the resource. No SQL to run.\n\nPlayers open the mailbox with `\u002Fmailbox` or the **F7** key (`Config.Key`, empty = no keybind).\n\nIn the panel: two tabs, **Mail** (can expire) and **Safe** (a second channel with its own unread\u002FReceive All count — handy for redeem-code rewards), claim one at a time or **Receive All** in a single click (scoped to whichever tab is open), **delete** a mail once its reward is claimed, see a countdown to expiry, redeem a code from a field right in the panel, and get pinged immediately if a new mail arrives while online.\n\nNo database, no framework, no license required. Works with ESX out of the box, and standalone with no framework installed.\n\n## Framework adapters — 4 adapters under `addons\u002F`\n\n| Folder | Purpose |\n|---|---|\n| `addons\u002Fframework\u002F` | `Framework.IsBusy()` (client) — can the mailbox be opened right now (dead \u002F pause menu); `Framework.Identifier(src)` \u002F `Framework.IsAdmin(src)` (server) — the player's permanent key and admin check |\n| `addons\u002Fnotify\u002F` | `Notify(message, kind)` (client) — notifications |\n| `addons\u002Freward\u002F` | `Reward.CanCarry` \u002F `Reward.GiveItem` \u002F `Reward.GiveMoney` (server) — item\u002Fmoney system |\n| `addons\u002Fstorage\u002F` | `Storage.Get\u002FSet\u002FAll\u002FFlush` (server) — where the data lives (see next section) |\n\nEvery file defaults to working with ESX (it checks `GetResourceState('es_extended')` itself) and carries commented QBCore \u002F ox_lib examples at the bottom to copy over. With no framework at all the mailbox still opens — it just can't deliver attachments until `Reward.GiveItem`\u002F`GiveMoney` is wired up (a console print warns you if it isn't).\n\n## Storage — JSON by default, or switch to MySQL\n\nDefault: a single JSON file (`Config.Storage.File`, default `data\u002Fmailbox.json`), loaded once on resource start, written back every `Config.Storage.FlushSeconds` seconds (default 30) and on player drop \u002F resource stop. An unreadable file is moved to `data\u002Fmailbox.broken.json` and a fresh one is started — the old data is never overwritten.\n\nTo switch to MySQL:\n\n1. Set `Config.Storage.Driver = 'oxmysql'` — the `x3d_mailbox` table is created automatically and no `@oxmysql` include is needed\n2. Restart the resource — nothing else to edit. (Only replace the four `Storage.*` functions in `addons\u002Fstorage\u002Fserver.lua` if you want a custom storage backend.)\n\n## Exports\n\n```lua\n-- target can be a server id (number) or an identifier (string)\nexports['x3d_mailbox']:SendMail(target, {\n    title   = 'Event prize',\n    body    = 'Thanks for joining',\n    sender  = 'Staff',            -- omit = uses the mailbox title\n    box     = 'mail',             -- 'mail' (default, can expire) or 'safe' (the second channel)\n    expires = os.time() + 86400,  -- unix timestamp, omit = never expires\n    items   = { { item = 'bread', count = 5 } },\n    money   = { { account = 'money', amount = 500 } },\n})\n\nexports['x3d_mailbox']:SendMailAll({ title = 'Announcement', body = 'Server restarting tonight' })\n\nexports['x3d_mailbox']:GetMails(src)          --> { {id, title, body, sender, at, expires, read, claimed, box, items, money}, ... }\nexports['x3d_mailbox']:GetUnread(src)         --> number (every box)\nexports['x3d_mailbox']:GetUnread(src, 'safe') --> number (just one box — 'mail' or 'safe')\n```\n\n`GetMails` filters out expired mails automatically, and attaches a Thai `label` from `Config.ItemLabels`\u002F`Config.AccountLabels` to the copies it returns (the stored originals are never touched). `GetUnread` only counts unread, unexpired mails — it returns a plain number, no labels.\n\n`SendMail` also accepts the shape other mailboxes use — `subject`, `cash`\u002F`bank`, `items = {{ name, count }}`, `expiresInDays` — so moving off an old mailbox is a rename of the export.\n\n## Events — server-internal (not a net event)\n\n```lua\nAddEventHandler('x3d_mailbox:onSend', function(identifier, mail) end)\nAddEventHandler('x3d_mailbox:onClaim', function(src, mail, ok) end)\n```\n\n`x3d_mailbox:onSend` fires as soon as a mail is created (from an export or an admin command).\n\n`x3d_mailbox:onClaim` always fires after a claim is attempted — **`mail.claimed` is `true` either way** (the flag is set before payout on purpose, to block a duplicate claim; see Safety below). Check the 3rd argument for the real result — `ok` is `true` only when every attachment was delivered without throwing:\n\n```lua\nAddEventHandler('x3d_mailbox:onClaim', function(src, mail, ok)\n    if not ok then print(('mail %s claimed by %s but a reward failed'):format(mail.id, src)) end\nend)\n```\n\n## Admin commands\n\n`\u002Fmailsend \u003Cserver id or identifier> \u003Ctitle> \u003Cbody…>` and `\u002Fmailsendall \u003Ctitle> \u003Cbody…>` — always callable from the in-game server console; a player needs the `Config.AdminAce` ace (default `x3d_mailbox.admin`) to run them.\n\n## Safety properties, backed by tests\n\n- **Can't be claimed twice** — the `claimed` flag is written to storage before anything is paid out, with no yield between the check and the write; an `InFlight[identifier]` lock also blocks two simultaneous claim events.\n- **A broken reward can't lock a player out** — the payout is wrapped in `pcall`; the mail is still marked claimed even if it throws (a misspelled item key from `\u002Fmailsend` won't leave the player retrying forever). A partial delivery tells the player with its own message instead of staying silent, and never reverts what already landed (that would double-pay it).\n- **Counts are always floored to whole numbers** — fractional or negative attachments never reach the player's inventory.\n- **The player key is always the permanent identifier**, never the server id.\n- **The `Config.MaxMails` cap never deletes an unclaimed, unexpired mail** — it trims claimed or expired mails first, oldest first. A mail that's been read but not claimed (and hasn't expired) still has live attachments and is never deleted.\n- **Receive All is one action, not N** — it pays out through the exact same logic as a single claim, scoped to whichever box tab is open (Mail and Safe never claim each other's mail); a mail that doesn't fit is skipped and stays claimable, never paid twice.\n- **Delete only works on a mail with nothing left to claim** — claim it first (or it never had attachments) — the one exception is an expired mail, which is always deletable since it can no longer be claimed at all — and a client-supplied mail id is only ever looked up inside that player's own list.\n- **`\u002Fredeem` and the redeem net event share the same throttle and lock** — spamming the command can't outrun the rate limit, and the redeem function itself is single-flight per player so two calls can't race each other even if storage starts yielding (e.g. an oxmysql swap).\n- **`Config.Codes` keys are normalised at boot** — a key typed in the wrong case is fixed automatically instead of silently never matching what a player types (with a console warning naming what changed).\n- Rate-limited to 1 call per second per player per action (`open`\u002F`read`\u002F`claim`\u002F`claimAll`\u002F`delete`\u002F`redeem` use separate buckets).\n\n```bash\npip install lupa\npython tools\u002Flua-test\u002Fx3d_mailbox_check.py\n```\n\n## Config (`config.lua`)\n\n| Setting | Purpose |\n|---|---|\n| `Config.Command` \u002F `Config.Key` | Open command (`\u002Fmailbox`) and keybind (`F7`) |\n| `Config.MaxMails` | Mails kept per player |\n| `Config.AdminAce` | Ace required for `\u002Fmailsend` `\u002Fmailsendall` |\n| `Config.Storage.File` \u002F `.FlushSeconds` | JSON file location and flush interval |\n| `Config.ItemLabels` \u002F `Config.AccountLabels` | Thai display labels for the mailbox |\n| `Config.ItemImage` | Path to your inventory's item icons (`{item}` = item name), empty = no icon |\n| `Config.ExpiryWarnHours` | A mail with less than this many hours left shows a red countdown in the panel (default 24) |\n| `Config.CanCarryExport` | Your inventory's capacity-check export — empty = ESX `canCarryItem`. **Seeing \"bag full\" on an empty bag? Set this** — ESX's own weight numbers are stale when another inventory owns them. |\n\n- `Config.DefaultExpireDays` — mail sent without an expiry expires after this many days (the safe never expires)\n- `Config.CheckCarry` — `false` = claim even with a full bag\n- `Config.NotifyUnreadOnJoin` — tell the player their unread count when they load in\n- Item names fall back to the framework's item label when `Config.ItemLabels` has no entry\n\n## Redeem codes\n\nA player types `\u002Fredeem \u003Ccode>`, or types the code into the field right in the mailbox panel, and the reward is **delivered as mail** — a full bag can never lose it, it simply waits in the mailbox.\n\nPermanent codes live in `config.lua`:\n\n```lua\nConfig.Codes = {\n    WELCOME2026 = {\n        maxUses       = 0,        -- 0 = unlimited server-wide\n        oncePerPlayer = true,     -- one per player (default)\n        title         = 'Welcome',\n        items         = { { item = 'bread', count = 2 } },\n        money         = { { account = 'bank', amount = 1000 } },\n    },\n    EVENTONLY = {\n        maxUses = 100,            -- first 100 players only\n        expires = 1790000000,     -- unix time the code stops working\n        box     = 'safe',         -- deliver into the safe instead of mail (optional, default 'mail')\n        money   = { { account = 'money', amount = 5000 } },\n    },\n}\n```\n\nRuntime codes from another resource (gone on restart):\n\n```lua\nexports['x3d_mailbox']:AddCode('EVENT2026', { maxUses = 50, money = { { account = 'bank', amount = 2000 } } })\nexports['x3d_mailbox']:RemoveCode('EVENT2026')\nexports['x3d_mailbox']:GetCodeUsage('EVENT2026')   --> { uses = 12, by = { ['license:xxx'] = true } }\nexports['x3d_mailbox']:Redeem(src, 'EVENT2026')    --> ok, reason\n\nAddEventHandler('x3d_mailbox:onRedeem', function(src, code, def) end)\n```\n\nUsage is stored beside the mail under the system key `__redeem`: it survives a restart, and the broadcast command never writes into it.\n\n## Support\n\nDiscord: discord.gg\u002Fx3d-developer · Web: x3d-developer.com\n","Free FiveM Mailbox & Redeem Code Script","Free FiveM offline mailbox with \u002Fredeem codes: rewards arrive as mail so a full bag never loses them, per-player limits, no database, any framework.",[62,65,67,69,71,73],{"kind":63,"url":64},"image","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-mailbox\u002Fmedia\u002F5f0e2bffeb5847dd.png",{"kind":63,"url":66},"\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-mailbox\u002Fmedia\u002Fecae52ada3262923.png",{"kind":63,"url":68},"\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-mailbox\u002Fmedia\u002Fdfbe3182ca82566c.png",{"kind":63,"url":70},"\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-mailbox\u002Fmedia\u002F3b10675e2258a5ab.png",{"kind":63,"url":72},"\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-mailbox\u002Fmedia\u002Fa1d612aa5b9a172d.png",{"kind":63,"url":74},"\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-mailbox\u002Fmedia\u002F2f18c7395c42734f.png",[76,78,82,86],{"version":51,"released_at":52,"changelog_md":77},"### Changed\n\n- Store images now carry English captions for the English store page",{"version":79,"released_at":80,"changelog_md":81},"1.7.0","2026-10-12T03:25:54.186504Z","### Changed\n\n- UI font is now Kanit (one family for Thai and English), bundled inside the script; the Thai font now really loads in game (FiveM's browser dropped the old font declaration and fell back to a system font)\n### Added\n- `SendMail` also accepts the shape other mailboxes use (`subject`, `cash`\u002F`bank`, `items = {{ name, count }}`, `expiresInDays`) — moving off an old mailbox is a rename of the export\n- `Config.Storage.Driver = 'oxmysql'` keeps mail in table `x3d_mailbox` (created automatically; no `@oxmysql` include needed)\n- `Config.DefaultExpireDays` (mail without an expiry expires after N days; the safe never expires), `Config.CheckCarry` (false = claim even with a full bag), `Config.NotifyUnreadOnJoin` (unread count when a player loads in)\n### Fixed\n- Item names fall back to the framework's item label when `Config.ItemLabels` has no entry\n- Claims were refused on servers whose inventory replaces ESX's (ESX's stale weight vetoed every item); the carry check now asks `Config.CanCarryExport` first everywhere, including inside item delivery",{"version":83,"released_at":84,"changelog_md":85},"1.4.0","2026-09-20T10:38:20.840557Z","### Added\r\n- Safe box: a second mail channel (`box = 'safe'` on any mail, `SendMail`\u002Fredeem codes accept it, defaults to `'mail'`) with its own unread count, its own Receive All (never touches the other box), and its own tab + badge in the panel\r\n- `GetUnread(src, box)` accepts an optional box to scope the count; omitted, it still counts every box like before\r\n\r\n### Fixed\r\n- **Critical:** `\u002Fredeem` bypassed the rate limit entirely (only the net event was throttled) — same-tick command spam could drain a whole `maxUses` pool from one player; the command now shares `doRedeem`'s throttle with the net event, and `Mail.Redeem` itself is single-flight per identifier so a concurrent call (including a direct `exports.x3d_mailbox:Redeem` from another resource) can't race a still-in-flight redeem even once storage starts yielding\r\n- **Critical:** a `Config.Codes` key not already matching the case `\u002Fredeem` compares against (uppercase unless `caseSensitive = true`) was silently unredeemable — keys are now normalised once at boot, with a console warning naming any key that had to change\r\n- Delete now shares the same `InFlight` lock as claim\u002FclaimAll, closing a window where a delete and a claim on the same list could interleave under a storage adapter that doesn't cache in memory (e.g. the documented oxmysql swap)\r\n- A partial delivery (some attachments paid, some failed) now tells the player with its own message (`partial_delivery`) instead of staying silent — the mail is still never reverted, so what already landed is never paid twice\r\n- An expired mail with unclaimed attachments could never be deleted or trimmed by `Config.MaxMails` — its reward is already forfeit once it expires, so it's now deletable and gets reaped by the cap like a claimed mail\r\n- `x3d_mailbox:read` had no throttle bucket — it's rate-limited like every other action now\r\n- `Mail.Add` stored the caller's `items`\u002F`money` tables by reference — `SendMailAll` and a `Config.Codes` entry reused across redemptions could alias into storage; both are now copied on the way in",{"version":87,"released_at":88,"changelog_md":89},"1.0.0","2026-09-19T19:05:37.383308Z","### Added\n- Offline mailbox: mails with title, body, sender, optional expiry, item and money attachments\n- Exports `SendMail(target, mail)`, `SendMailAll(mail)`, `GetMails(src)`, `GetUnread(src)`\n- Server-internal events `x3d_mailbox:onSend(identifier, mail)` and `x3d_mailbox:onClaim(src, mail, ok)`\n- Nuxt 4 panel, `\u002Fmailbox` command and F7 keybind\n- Admin commands `\u002Fmailsend` and `\u002Fmailsendall`, gated by the `x3d_mailbox.admin` ace\n- Claim-once ordering: the claimed flag is written to storage before payout, with an `InFlight` per-identifier lock against simultaneous claims\n- Reward payout wrapped in `pcall` so a broken item\u002Faccount can't leave a player permanently unable to claim\n- Attachment counts floored to whole numbers before every capacity check and payout\n- JSON file storage by default, with a commented oxmysql swap and `install.sql`\n- Four `addons\u002F` adapter files (framework, notify, reward, storage) with ESX defaults and QBCore\u002Fox_lib examples\n- `Config.ItemLabels` \u002F `Config.AccountLabels` for Thai display names",{"items":91,"page":866,"size":867,"total":867},[92,128,149,178,200,229,262,287,314,344,369,395,423,450,478,506,530,550,573,600,630,655,679,703,724,752,777,798,821,824,845],{"id":93,"slug":94,"name":95,"summary":96,"price_thb":97,"license_mode":98,"cover_key":99,"cover_url":100,"category_slugs":101,"tags":104,"latest_version":123,"latest_released_at":124,"published_at":125,"has_docs":54,"config":126,"rent_price_satang":127},"6bdadea7-4316-4a4a-a38e-87c5e841077d","x3d-replay","X3D Replay","BETA pricing. Records every player, every session. Watch it back in game: 4 cameras, kill\u002Fdeath timeline, pressed keys, script usage, macro flags.",59900,"shop_license","public\u002Fproducts\u002Fx3d-replay\u002Fcover.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-replay\u002Fcover.jpg",[102,103],"anticheat","admin",[33,105,106,107,108,109,110,111,112,113,114,115,116,117,102,118,119,120,121,122],"ESX Legacy","replay","fivem replay script","replay system","รีเพลย์","ดูย้อนหลัง","ย้อนดูผู้เล่น","บันทึกผู้เล่น","เคสรีพอร์ต","จับโกง","จับมาโคร","macro detection","กันโปร","แอดมิน","admin tool","demo recorder","spectate","BETA","1.0.2","2026-10-14T06:14:23.677549Z","2026-10-14T06:14:23.700289Z","owners",12000,{"id":129,"slug":130,"name":131,"summary":132,"price_thb":97,"license_mode":98,"cover_key":133,"cover_url":134,"category_slugs":135,"tags":136,"latest_version":87,"latest_released_at":147,"published_at":148,"has_docs":54,"config":126,"rent_price_satang":127},"ff948fa9-6fc5-410e-b952-ee88b15f0c9d","x3d-anticheat","X3D Anti-Cheat","BETA pricing, join the testing. Evidence-first anti-cheat: Discord embeds with screenshots, HWID bans, Steam\u002FDiscord account lock, two-line event guard.","public\u002Fproducts\u002Fx3d-anticheat\u002Fcover\u002Fd90612eed4448164.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-anticheat\u002Fcover\u002Fd90612eed4448164.jpg",[102],[33,37,137,102,138,139,140,117,141,142,143,144,145,146],"แอนตี้โกง","ป้องกันแฮก","กันโกง","HWID ban","ภาพหลักฐาน","ล็อกบัญชี Steam Discord","แบนเครื่อง","คิวยศ Discord","กัน event สแปม","แอนตี้โกง ESX","2026-09-16T09:45:51.78533Z","2026-09-16T09:46:00.05928Z",{"id":150,"slug":151,"name":152,"summary":153,"price_thb":154,"license_mode":98,"cover_key":155,"cover_url":156,"category_slugs":157,"tags":161,"latest_version":174,"latest_released_at":175,"published_at":176,"has_docs":54,"config":126,"rent_price_satang":177},"47a33337-7dcf-4a78-b056-4b3e324a648d","x3d-slots","X3D Slots 1024 Ways","1,024-way cascading slot, Mahjong style, 97.5% RTP. Server-authoritative spins, anti-exploit, with free spins, multipliers and big-win scenes.",250000,"public\u002Fproducts\u002Fx3d-slots\u002Fcover\u002Fd09c2066a6ea2968.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-slots\u002Fcover\u002Fd09c2066a6ea2968.jpg",[158,159,160],"casino","economy","entertainment",[33,37,162,163,158,164,165,166,167,168,169,170,171,172,173],"คาสิโน","สล็อต","slot","มินิเกม","minigame","RTP 97.5%","มาห์จอง","คาสเคด","ฟรีสปิน","ตู้สล็อต","ซื้อฟีเจอร์","ปรับ RTP","1.1.4","2026-10-12T17:13:01.863556Z","2026-09-14T15:28:02.281478Z",50000,{"id":179,"slug":180,"name":181,"summary":182,"price_thb":26,"license_mode":27,"cover_key":183,"cover_url":184,"category_slugs":185,"tags":187,"latest_version":197,"latest_released_at":198,"published_at":199,"has_docs":54,"config":55,"rent_price_satang":56},"1fb91794-3e8b-4955-bc54-dc6b1491912e","x3d-mapevents","X3D Map Events","Free event panel on the pause-menu map: name + countdown, click to set a waypoint. Other scripts push events like notifications; admins can create their own.","public\u002Fproducts\u002Fx3d-mapevents\u002Fcover\u002F8e738f2dfcf0ea2f.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-mapevents\u002Fcover\u002F8e738f2dfcf0ea2f.jpg",[186,31],"hud",[188,189,190,191,192,193,194,195,196,40,34],"อีเวนต์","อีเวนต์บนแผนที่","แผนที่","จุดนำทาง","นับถอยหลัง","pause menu","map events","event","waypoint","1.0.3","2026-10-12T17:13:20.327337Z","2026-10-12T04:21:56.480796Z",{"id":201,"slug":202,"name":203,"summary":204,"price_thb":26,"license_mode":27,"cover_key":205,"cover_url":206,"category_slugs":207,"tags":209,"latest_version":226,"latest_released_at":227,"published_at":228,"has_docs":54,"config":55,"rent_price_satang":56},"58697b89-cbe5-4b1f-8a29-c5289727202e","x3d-weaponskins","X3D Weapon Skins","Free collectible ESX weapon skins: each skin is an add-on weapon tied to its base gun. Unlock with an item, same damage, tradable, held-weapon effects.","public\u002Fproducts\u002Fx3d-weaponskins\u002Fcover\u002F25e3c37b23545ec8.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-weaponskins\u002Fcover\u002F25e3c37b23545ec8.jpg",[31,208],"inventory",[210,211,212,213,214,215,216,217,218,219,33,40,34,220,221,222,223,224,225],"weapon skins","สกินอาวุธ","สกินอาวุธ fivem","สกินปืน","gun skin","weapon skin fivem","คลังสกิน","เทรดสกิน","skin collection","x3d_inventory","ปลดล็อกสกิน","สกินสะสม","เอฟเฟกต์อาวุธ","ความหายากสกิน","สกิน add-on","แปลงสกินเป็นไอเทม","1.1.2","2026-10-12T17:13:35.599698Z","2026-10-10T11:46:16.716284Z",{"id":230,"slug":231,"name":232,"summary":233,"price_thb":26,"license_mode":27,"cover_key":234,"cover_url":235,"category_slugs":236,"tags":238,"latest_version":123,"latest_released_at":260,"published_at":261,"has_docs":54,"config":55,"rent_price_satang":56},"d82d8eb1-ed6a-43e3-86ef-24e45ae2b39d","x3d-damage","X3D Damage","Set every weapon's damage yourself, with bleed, slow, stun, knockdown and lifesteal effects. Weapon skins supported. ESX or standalone.","public\u002Fproducts\u002Fx3d-damage\u002Fcover\u002F8ce8864c16843fe6.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-damage\u002Fcover\u002F8ce8864c16843fe6.jpg",[31,237],"gangs",[239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,33,37,40,34,254,255,256,257,258,259],"weapon damage","ดาเมจอาวุธ","ดาเมจปืน","fivem weapon damage","damage script","headshot","headshot kill","เลือดออก","bleed","สตัน","stun","lifesteal","ดูดเลือด","เมืองปืน","pvp","ทะลุเกราะ","ดาเมจเสริม","ปิดท่าต่อยหนัก","ปรับดาเมจ","ทำให้ช้า","กันกระโดดหลบ","2026-10-12T17:14:19.289254Z","2026-10-10T11:45:52.279629Z",{"id":263,"slug":264,"name":265,"summary":266,"price_thb":26,"license_mode":27,"cover_key":267,"cover_url":268,"category_slugs":269,"tags":271,"latest_version":123,"latest_released_at":285,"published_at":286,"has_docs":54,"config":55,"rent_price_satang":56},"93def22a-9501-4b66-bdf0-158cc6a0093c","x3d-vehiclestorage","X3D Vehicle Storage","Free ESX trunk storage on the x3d_inventory screen: capacity by vehicle class and model, owner-only access, job cars and an admin view.","public\u002Fproducts\u002Fx3d-vehiclestorage\u002Fcover\u002F2c2d97cb47678e1b.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-vehiclestorage\u002Fcover\u002F2c2d97cb47678e1b.jpg",[208,270],"garage",[272,273,274,275,276,277,278,219,33,40,34,279,280,281,282,283,284],"trunk","ท้ายรถ","ท้ายรถ fivem","vehicle storage","trunk inventory","esx trunk","เก็บของในรถ","ตู้ท้ายรถ","รถงาน","กล่องเก็บของหน้ารถ","น้ำหนักท้ายรถ","ล็อกรถ","เปิดท้ายรถ","2026-10-12T17:14:46.845123Z","2026-10-05T04:28:52.749188Z",{"id":288,"slug":289,"name":290,"summary":291,"price_thb":26,"license_mode":27,"cover_key":292,"cover_url":293,"category_slugs":294,"tags":296,"latest_version":123,"latest_released_at":312,"published_at":313,"has_docs":54,"config":55,"rent_price_satang":56},"b642bb91-9f6d-4c3c-8830-e594c2a92fcb","x3d-vault","X3D Vault","Free ESX vaults on the x3d_inventory screen: player vaults with levels and sharing, job vaults per society, Thai and English.","public\u002Fproducts\u002Fx3d-vault\u002Fcover\u002F72ea3a88a64e0034.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-vault\u002Fcover\u002F72ea3a88a64e0034.jpg",[208,295],"jobs",[297,298,299,300,301,302,303,304,219,33,40,34,305,306,307,308,309,310,311],"vault","stash","ตู้เซฟ","ตู้เก็บของ","ตู้เซฟ fivem","esx stash","job vault","ตู้หน่วยงาน","ตู้เซฟแก๊ง","ตู้ส่วนตัว","แชร์ตู้","อัปเกรดตู้","ตู้เซฟตำรวจ","ตู้เซฟอาชีพ","ลิมิตตู้","2026-10-12T17:15:03.928293Z","2026-10-05T04:28:43.828514Z",{"id":315,"slug":316,"name":317,"summary":318,"price_thb":26,"license_mode":27,"cover_key":319,"cover_url":320,"category_slugs":321,"tags":322,"latest_version":341,"latest_released_at":342,"published_at":343,"has_docs":54,"config":55,"rent_price_satang":56},"70fa1474-294a-49ad-91cb-1de0ab4dc8d8","x3d-adminpanel","X3D Admin Panel","A free all-in-one FiveM admin panel: players, bans and warnings, alt detection, bags, items, vehicles, weather, player logs and menus for X3D scripts.","public\u002Fproducts\u002Fx3d-adminpanel\u002Fcover\u002F5cb8420f481eee28.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-adminpanel\u002Fcover\u002F5cb8420f481eee28.jpg",[103],[323,324,325,326,327,328,143,329,330,331,332,333,121,334,33,37,40,34,335,336,337,338,339,340],"admin panel","admin menu","แผงแอดมิน","เมนูแอดมิน","เมนูแอดมิน fivem","fivem admin menu","token ban","จับบัญชีสำรอง","alt detection","txadmin","noclip","log","แอดมินไทย","ยึดไอเทม","ประวัติแบน","โน้ตแอดมิน","นำเข้า txAdmin","บทบาทแอดมิน","1.0.5","2026-10-12T17:15:53.66615Z","2026-10-05T04:11:47.352812Z",{"id":345,"slug":346,"name":347,"summary":348,"price_thb":26,"license_mode":27,"cover_key":349,"cover_url":350,"category_slugs":351,"tags":352,"latest_version":174,"latest_released_at":367,"published_at":368,"has_docs":54,"config":55,"rent_price_satang":56},"d76ff7ae-ded6-4f39-b63f-734181952698","x3d-inventory","X3D Inventory","Free ESX inventory with big readable text, hotkeys 1–9 saved per character, coupon-based capacity and a storage panel for any vault or trunk script.","public\u002Fproducts\u002Fx3d-inventory\u002Fcover\u002Ffc3857e556cf31f3.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-inventory\u002Fcover\u002Ffc3857e556cf31f3.jpg",[208,186],[208,353,354,355,356,357,358,359,360,361,33,40,34,362,363,364,365,366],"กระเป๋า","กระเป๋า fivem","ui กระเป๋า","esx inventory","inventory fivem","ช่องลัด","hotbar","ไอเทม","nui","คูปองขยายช่อง","คูปองน้ำหนัก","ความหายากไอเทม","ค้นกระเป๋า","จำกัดน้ำหนัก","2026-10-12T17:16:22.733967Z","2026-10-05T04:10:14.693356Z",{"id":370,"slug":371,"name":372,"summary":373,"price_thb":26,"license_mode":27,"cover_key":374,"cover_url":375,"category_slugs":376,"tags":377,"latest_version":174,"latest_released_at":393,"published_at":394,"has_docs":54,"config":55,"rent_price_satang":56},"f782bbab-0321-4d3f-832f-797a2aa198f5","x3d-fortune","X3D Fortune","Free ESX fortune teller: daily horoscope, zodiac from your birthday, 28 siamsi sticks, 22-card tarot on 9 topics and a 10-card monthly spread.","public\u002Fproducts\u002Fx3d-fortune\u002Fcover\u002Fab130eeac9fbc029.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-fortune\u002Fcover\u002Fab130eeac9fbc029.jpg",[160],[378,379,380,381,382,383,384,385,386,33,40,34,387,388,389,390,391,392],"หมอดู","ดูดวง","เซียมซี","ไพ่ยิปซี","tarot","ราศี","ดวงรายวัน","fortune teller","npc","ดวงรายเดือน","ไพ่ทาโร่","เลขมงคล","สีมงคล","ไพ่กลับหัว","จุดหมอดู","2026-10-12T17:16:40.12128Z","2026-09-26T14:59:27.315955Z",{"id":396,"slug":397,"name":398,"summary":399,"price_thb":26,"license_mode":27,"cover_key":400,"cover_url":401,"category_slugs":402,"tags":403,"latest_version":420,"latest_released_at":421,"published_at":422,"has_docs":54,"config":55,"rent_price_satang":56},"9cb293aa-8b2c-447d-b810-3a7e385f6e81","x3d-banking","X3D Banking","Free ESX bank and ATM: deposit, withdraw, transfer by player ID, transaction history, every ATM on the map, every action checked on the server.","public\u002Fproducts\u002Fx3d-banking\u002Fcover\u002Fe7e66ab29819a980.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-banking\u002Fcover\u002Fe7e66ab29819a980.jpg",[159],[404,405,406,407,408,409,410,411,412,413,33,40,34,414,415,416,417,418,419],"banking","ธนาคาร","ระบบธนาคาร","atm","ตู้ atm","โอนเงิน","โอนด้วยเบอร์โทร","esx banking","bank script","ประวัติรายการ","ถอนด่วน","วงเงินโอน","สาขาธนาคาร","ฝากเงิน","ถอนเงิน","เพิ่มตู้ ATM","1.1.8","2026-10-12T17:16:55.98941Z","2026-09-26T14:59:08.07128Z",{"id":424,"slug":425,"name":426,"summary":427,"price_thb":26,"license_mode":27,"cover_key":428,"cover_url":429,"category_slugs":430,"tags":431,"latest_version":174,"latest_released_at":448,"published_at":449,"has_docs":54,"config":55,"rent_price_satang":56},"c72d91e0-6bcd-4fae-bde9-0e140e02b0cb","x3d-music","X3D Music","Free ESX boombox: place it on the ground or mount it on a car, play YouTube with a shared queue and distance falloff; speakers survive restarts.","public\u002Fproducts\u002Fx3d-music\u002Fcover\u002Fce445e0d251f7540.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-music\u002Fcover\u002Fce445e0d251f7540.jpg",[160],[432,433,434,435,436,437,438,439,440,441,33,40,34,442,443,444,445,446,447],"boombox","ลำโพง","ลำโพงเปิดเพลง","เปิดเพลง youtube","music script","fivem music","xsound","youtube","คิวเพลง","ติดบนรถ","ลำโพงติดรถ","เปิดเพลงในรถ","ฟังเพลงด้วยกัน","เพลงร่วมกัน","ลำโพงวางพื้น","จำกัดลำโพง","2026-10-12T17:17:14.482272Z","2026-09-26T14:56:09.091062Z",{"id":451,"slug":452,"name":453,"summary":454,"price_thb":26,"license_mode":27,"cover_key":455,"cover_url":456,"category_slugs":457,"tags":458,"latest_version":475,"latest_released_at":476,"published_at":477,"has_docs":54,"config":55,"rent_price_satang":56},"6125d85f-eaff-45cb-90cd-9db4d66e7954","x3d-respawn","X3D Respawn","Free death screen: Call EMS button, wait for medics when they are online, respawn points, self-revive, a death summary and death kept across relogs.","public\u002Fproducts\u002Fx3d-respawn\u002Fcover\u002F1af99658aa5089b2.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-respawn\u002Fcover\u002F1af99658aa5089b2.jpg",[186],[459,460,461,462,463,464,465,466,467,468,469,33,40,34,470,471,472,473,474],"respawn","หน้าจอตาย","death screen","เรียกหมอ","call ems","ambulance","esx_ambulancejob","ชุบตัวเอง","จุดเกิดใหม่","dispatch","สรุปการตาย","รอหมอ","กันหนีตาย","ปุ่มเรียกหมอ","เกิดใหม่เมือง","ชุดปฐมพยาบาล","1.1.3","2026-10-12T17:17:26.33517Z","2026-09-25T16:14:21.42282Z",{"id":479,"slug":480,"name":481,"summary":482,"price_thb":26,"license_mode":27,"cover_key":483,"cover_url":484,"category_slugs":485,"tags":486,"latest_version":475,"latest_released_at":504,"published_at":505,"has_docs":54,"config":55,"rent_price_satang":56},"879a5a5d-5b22-4fb5-9274-6ac3ee631904","x3d-phone","X3D Phone","Free ESX smartphone: pma-voice calls, SMS with location sharing, mobile banking, a camera with self-hosted photos, Buzz and anonymous Dark Chat.","public\u002Fproducts\u002Fx3d-phone\u002Fcover\u002F9e0b9e2f9bc7352d.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-phone\u002Fcover\u002F9e0b9e2f9bc7352d.jpg",[186],[487,488,489,490,491,492,493,468,494,495,496,497,498,33,40,34,499,500,501,462,502,503],"phone","โทรศัพท์","โทรศัพท์ fivem","esx phone","phone script","sms","pma-voice","แจ้งเหตุ","ธนาคารมือถือ","buzz","dark chat","กล้อง","เบอร์หน่วยงาน","ออกบิล","แชร์ตำแหน่ง","กล้องโทรศัพท์","ไอเทมโทรศัพท์","2026-10-12T17:18:13.372348Z","2026-09-25T15:32:10.424119Z",{"id":507,"slug":508,"name":509,"summary":510,"price_thb":26,"license_mode":27,"cover_key":511,"cover_url":512,"category_slugs":513,"tags":514,"latest_version":475,"latest_released_at":527,"published_at":528,"has_docs":529,"config":27,"rent_price_satang":56},"6705aca9-39b7-48ad-a39b-0dc4a906dd70","x3d-safe","X3D Safe Cracking","A dial-cracking minigame: turn with A and D, press E on the notch. One export, no dependencies.","public\u002Fproducts\u002Fx3d-safe\u002Fcover\u002F410a110f32490438.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-safe\u002Fcover\u002F410a110f32490438.jpg",[237,31],[515,516,299,517,165,166,518,519,37,520,40,34,521,522,523,524,525,526],"safe cracking","เจาะตู้เซฟ","หมุนตู้เซฟ","มินิเกม fivem","export","crime","หมุนหน้าปัด","ตู้เซฟธนาคาร","ตู้เซฟร้าน","ตู้เซฟบ้าน","ไม่ต้องใช้ ESX","มินิเกม A\u002FD","2026-10-12T17:18:34.435941Z","2026-09-24T03:53:28.3285Z",false,{"id":531,"slug":532,"name":533,"summary":534,"price_thb":26,"license_mode":27,"cover_key":535,"cover_url":536,"category_slugs":537,"tags":538,"latest_version":547,"latest_released_at":548,"published_at":549,"has_docs":529,"config":27,"rent_price_satang":56},"d5bcab3a-9189-4813-9b17-6b34f3a16584","x3d-lockpick","X3D Lockpick","A lockpick minigame felt out with WASD, called with one export and usable from any script.","public\u002Fproducts\u002Fx3d-lockpick\u002Fcover\u002Fc36242cb20a32b3b.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-lockpick\u002Fcover\u002Fc36242cb20a32b3b.jpg",[237,31],[539,540,541,165,166,518,519,37,520,40,34,542,543,544,545,546],"lockpick","งัดล็อก","สะเดาะกุญแจ","งัดประตูบ้าน","งัดรถ","หมุดล็อก","มินิเกม WASD","ปรับความยาก","1.1.1","2026-10-12T17:18:46.115275Z","2026-09-24T03:53:14.231073Z",{"id":551,"slug":552,"name":553,"summary":554,"price_thb":26,"license_mode":27,"cover_key":555,"cover_url":556,"category_slugs":557,"tags":559,"latest_version":570,"latest_released_at":571,"published_at":572,"has_docs":54,"config":55,"rent_price_satang":56},"65d3b2da-6dba-4cd0-9907-06b8e6e54994","x3d-houserobbery","X3D House Robbery","Pick the door, search the floor, crack the safe, with a cooldown per house and both minigames in the same zip.","public\u002Fproducts\u002Fx3d-houserobbery\u002Fcover\u002F73f596dab6db196a.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-houserobbery\u002Fcover\u002F73f596dab6db196a.jpg",[558,237],"housing",[560,561,562,563,564,299,539,165,237,565,558,520,33,40,34,566,516,567,568,569],"งัดบ้าน","ปล้นบ้าน","house robbery","robbery","ปล้น","แก๊ง","คีย์การ์ด","เงินแดง","จุดค้นของ","ปล้นบ้านคูลดาวน์","1.2.4","2026-10-12T17:19:03.056031Z","2026-09-24T03:48:06.633278Z",{"id":574,"slug":575,"name":576,"summary":577,"price_thb":26,"license_mode":27,"cover_key":578,"cover_url":579,"category_slugs":580,"tags":581,"latest_version":597,"latest_released_at":598,"published_at":599,"has_docs":54,"config":55,"rent_price_satang":56},"5532c49c-d819-4dda-b8a0-71514a14df31","x3d-selldrug","X3D Sell Drug","Shady buyers appear around the map on a timer and pay in black money. Runs on ESX or standalone.","public\u002Fproducts\u002Fx3d-selldrug\u002Fcover\u002F38844a64037d78d6.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-selldrug\u002Fcover\u002F38844a64037d78d6.jpg",[237,159],[582,583,584,585,586,587,588,589,237,565,520,33,40,34,590,591,592,593,594,595,567,596],"ขายยา","งานขายยา","sell drug","drug selling","ของผิดกฎหมาย","เงินดำ","black money","ผู้รับซื้อ","จุด10","จุดสิบ","จุดขายยา","ขายของจุด10","ขายของลับ","ฟอกเงิน","ผู้รับซื้อรายใหญ่","1.2.6","2026-10-12T17:19:19.018788Z","2026-09-24T03:39:03.703963Z",{"id":601,"slug":602,"name":603,"summary":604,"price_thb":26,"license_mode":27,"cover_key":605,"cover_url":606,"category_slugs":607,"tags":608,"latest_version":226,"latest_released_at":628,"published_at":629,"has_docs":529,"config":55,"rent_price_satang":56},"8e4dcdf4-7c70-4185-a3c9-15bb5328c457","x3d-useitem","X3D Use Item","Painkillers, bandages, AED, armor, helmet, repair kits, ammo, loot boxes and buff food in one system that needs only ESX.","public\u002Fproducts\u002Fx3d-useitem\u002Fcover\u002Fe007251b171e6791.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-useitem\u002Fcover\u002Fe007251b171e6791.jpg",[208,31],[609,610,611,612,613,614,615,616,617,618,619,620,621,33,40,34,622,623,624,625,626,627],"use item","ไอเทมใช้ได้","usable items","ยา","ผ้าพันแผล","aed","ชุบคนล้ม","ซ่อมรถ","กระสุน","กล่องสุ่ม","อาหาร","เสื้อเกราะ","หมวกกันน็อค","บัฟอาหาร","ชุดซ่อมรถ","เติมกระสุน","ยืมเสื้อเกราะ","ใช้ไอเทม","ไอเทมเติมเลือด","2026-10-12T17:19:33.653792Z","2026-09-24T02:05:34.038449Z",{"id":631,"slug":632,"name":633,"summary":634,"price_thb":26,"license_mode":27,"cover_key":635,"cover_url":636,"category_slugs":637,"tags":638,"latest_version":475,"latest_released_at":653,"published_at":654,"has_docs":529,"config":27,"rent_price_satang":56},"8c823bc1-1de6-41b6-bf82-146d5a55eeb5","x3d-progressbar","X3D Progress Bar","A peach-themed progress bar with ESC to cancel, a countdown, an automatic hotkey lock, and a bundled Thai font.","public\u002Fproducts\u002Fx3d-progressbar\u002Fcover\u002Ff6830df60f656452.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-progressbar\u002Fcover\u002Ff6830df60f656452.jpg",[186],[639,640,641,642,643,644,645,186,646,33,40,34,647,648,649,650,651,652],"progressbar","progress bar","แถบโหลด","แถบความคืบหน้า","esx_progressbar","esx progressbar","ui","ยกเลิก esc","หลอดโหลด","ฟอนต์ไทย","นับเวลาถอยหลัง","ล็อกปุ่มลัด","โปรเกรสบาร์","แทน esx_progressbar","2026-10-12T17:19:45.934106Z","2026-09-24T01:22:17.768991Z",{"id":656,"slug":657,"name":658,"summary":659,"price_thb":26,"license_mode":27,"cover_key":660,"cover_url":661,"category_slugs":662,"tags":663,"latest_version":226,"latest_released_at":677,"published_at":678,"has_docs":54,"config":55,"rent_price_satang":56},"63ce5efe-2f18-499e-a52b-8155a6cebb84","x3d-slide","X3D Slide","A shooter-style forward slide on Shift plus one key, with a cooldown to stop spam. Fully configurable, nothing else needed.","public\u002Fproducts\u002Fx3d-slide\u002Fcover\u002F8c8383608791f58a.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-slide\u002Fcover\u002F8c8383608791f58a.jpg",[31],[664,665,666,667,668,669,670,671,37,33,40,34,672,673,674,675,676],"slide","สไลด์","slide fivem","ท่าสไลด์","หลบ","dodge","ท่าทาง","คูลดาวน์","สไลด์แบบเกมยิง","Shift สไลด์","ท่าหลบเกมยิง","ปุ่มสไลด์","ปรับแรงสไลด์","2026-10-12T17:20:03.227099Z","2026-09-24T01:21:56.84494Z",{"id":680,"slug":681,"name":682,"summary":683,"price_thb":26,"license_mode":27,"cover_key":684,"cover_url":685,"category_slugs":686,"tags":687,"latest_version":174,"latest_released_at":701,"published_at":702,"has_docs":54,"config":55,"rent_price_satang":56},"9b62b8ed-5911-47a8-b695-3320a6183758","x3d-notify","X3D Notify","Notification cards in nine positions, with item icons and rarity frames, and full Thai support.","public\u002Fproducts\u002Fx3d-notify\u002Fcover\u002F4a9cbdcedd86a149.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-notify\u002Fcover\u002F4a9cbdcedd86a149.jpg",[186],[688,689,690,691,692,693,645,186,648,694,33,40,34,695,696,697,698,699,700],"notify","notification","แจ้งเตือน","แจ้งเตือน fivem","esx_notify","esx notify","ไอคอนไอเทม","การ์ดแจ้งเตือน","กรอบความหายาก","แจ้งเตือน 9 ตำแหน่ง","สีในข้อความ","แทน esx_notify","แจ้งเตือนไอเทม","2026-10-12T17:20:21.047259Z","2026-09-24T01:21:40.547491Z",{"id":704,"slug":705,"name":706,"summary":707,"price_thb":26,"license_mode":27,"cover_key":708,"cover_url":709,"category_slugs":710,"tags":711,"latest_version":341,"latest_released_at":722,"published_at":723,"has_docs":54,"config":27,"rent_price_satang":56},"e6dc80f3-4f29-4d01-bffa-eba6829c6497","x3d-loadingscreen","X3D Loading Screen","A terminal-style loading screen with an ENTER WORLD button the player presses before spawning. One HTML file, no build step.","public\u002Fproducts\u002Fx3d-loadingscreen\u002Fcover\u002F32f1538b8e18f4db.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-loadingscreen\u002Fcover\u002F32f1538b8e18f4db.jpg",[186],[712,713,714,715,716,717,645,37,33,40,34,718,719,647,720,721],"loading screen","หน้าโหลด","หน้าโหลด fivem","loadingscreen","esx_loadingscreen","enter world","ปุ่มเข้าเมือง","หน้าโหลดเทอร์มินัล","พื้นหลังวิดีโอ","เพลงหน้าโหลด","2026-10-12T17:20:39.269405Z","2026-09-24T00:50:19.336351Z",{"id":725,"slug":726,"name":727,"summary":728,"price_thb":26,"license_mode":27,"cover_key":729,"cover_url":730,"category_slugs":731,"tags":733,"latest_version":749,"latest_released_at":750,"published_at":751,"has_docs":54,"config":27,"rent_price_satang":56},"37f7d9db-f90d-4eed-861b-922da1072932","es-extended","ESX Legacy Core — X3D Build","A faster es_extended that stops player saves going corrupt, autosaves every 10 minutes and freezes the economy before a restart. Drop-in, same resource name.","public\u002Fproducts\u002Fes-extended\u002Fcover\u002Fa0b783dc4bf383e9.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fes-extended\u002Fcover\u002Fa0b783dc4bf383e9.jpg",[732],"optimization",[33,734,735,736,737,738,739,740,741,742,40,34,743,744,745,746,747,748],"es_extended","esx legacy","esx core","esx_core","framework","core","esx ฟรี","ดาวน์โหลด esx","esx legacy 1.13","กันข้อมูลหาย","กันดูป","audit log","เซฟผู้เล่น","esx fork","กันตกทะลุแมพ","1.13.6","2026-10-12T17:20:52.726747Z","2026-09-23T13:28:50.819982Z",{"id":753,"slug":754,"name":755,"summary":756,"price_thb":26,"license_mode":27,"cover_key":757,"cover_url":758,"category_slugs":759,"tags":760,"latest_version":774,"latest_released_at":775,"published_at":776,"has_docs":54,"config":55,"rent_price_satang":56},"7c86bf83-0df0-4e59-ab59-461ac4a2bff8","x3d-skin","X3D Character Skin","A 77-slot character editor with an orbiting camera, poses and lighting. No skinchanger, no database, any framework.","public\u002Fproducts\u002Fx3d-skin\u002Fcover\u002Fdb520ac6e2e3d502.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-skin\u002Fcover\u002Fdb520ac6e2e3d502.jpg",[186],[33,37,761,762,763,764,765,766,767,40,34,768,769,770,771,772,773],"ตกแต่งตัวละคร","skin","character customization","skin creator","แต่งตัวละคร","ร้านเสื้อผ้า","ร้านตัดผม","ตู้เสื้อผ้า","ร้านเสริมสวย","ร้านหน้ากาก","ท่าโพส","แต่งหน้า","ไม่ต้องใช้ skinchanger","1.5.4","2026-10-12T17:21:14.159219Z","2026-09-22T04:02:41.988907Z",{"id":778,"slug":779,"name":780,"summary":781,"price_thb":26,"license_mode":27,"cover_key":782,"cover_url":783,"category_slugs":784,"tags":785,"latest_version":174,"latest_released_at":796,"published_at":797,"has_docs":54,"config":55,"rent_price_satang":56},"7337afbc-ca0d-4071-9de4-2cc04bd1b4e6","x3d-menu","X3D Main Menu","A server main menu: system cards, announcements, timed events, an in-game guidebook and per-player settings. No database, any framework.","public\u002Fproducts\u002Fx3d-menu\u002Fcover\u002F8a1dbb30861b0387.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-menu\u002Fcover\u002F8a1dbb30861b0387.jpg",[186],[33,37,786,787,788,789,188,790,40,34,791,792,793,794,795],"เมนูหลัก","main menu","menu","ประกาศ","คู่มือเมือง","เมนูเมือง","กฎเมือง","เมนู F4","ตั้งค่าผู้เล่น","แบนเนอร์อีเวนต์","2026-10-12T17:21:29.681926Z","2026-09-21T04:20:29.437521Z",{"id":799,"slug":800,"name":801,"summary":802,"price_thb":26,"license_mode":27,"cover_key":803,"cover_url":804,"category_slugs":805,"tags":806,"latest_version":818,"latest_released_at":819,"published_at":820,"has_docs":54,"config":55,"rent_price_satang":56},"7a9dd386-11c0-4f21-8c2e-cfa7dc24d15d","x3d-dailylogin","X3D Daily Login","Free daily check-in with streaks and a fully editable reward table, no database required, a full bag never costs the reward, works with any framework.","public\u002Fproducts\u002Fx3d-dailylogin\u002Fcover\u002Fffcad7901926aa67.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-dailylogin\u002Fcover\u002Fffcad7901926aa67.jpg",[31],[33,37,807,808,809,810,811,40,34,812,813,814,815,816,817,50],"เช็คอินรายวัน","daily login","daily reward","สตรีค","รางวัลรายวัน","ล็อคอินรายวัน","รางวัลค้างรับ","รับย้อนหลัง","โบนัสเวลาเล่น","รางวัลเข้าเกม","เช็คชื่อรายวัน","1.4.3","2026-10-12T17:21:47.885233Z","2026-09-20T10:37:48.155794Z",{"id":22,"slug":23,"name":24,"summary":25,"price_thb":26,"license_mode":27,"cover_key":28,"cover_url":29,"category_slugs":822,"tags":823,"latest_version":51,"latest_released_at":52,"published_at":53,"has_docs":54,"config":55,"rent_price_satang":56},[31],[33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50],{"id":825,"slug":826,"name":827,"summary":828,"price_thb":26,"license_mode":27,"cover_key":829,"cover_url":830,"category_slugs":831,"tags":832,"latest_version":475,"latest_released_at":843,"published_at":844,"has_docs":54,"config":55,"rent_price_satang":56},"fd28d581-12ee-43b8-9dfb-aa18defe53be","x3d-carry","X3D Carry","Free player carry script: carry and steal bodies, fireman carry and piggyback, consent before carrying the living, fully server authoritative, no dependencies.","public\u002Fproducts\u002Fx3d-carry\u002Fcover\u002F133f7c2c2d80c8a5.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-carry\u002Fcover\u002F133f7c2c2d80c8a5.jpg",[31],[33,37,833,834,835,40,34,836,837,838,839,840,841,842],"อุ้มศพ","carry","อุ้มผู้เล่น","แย่งศพ","แบกผู้เล่น","ขี่หลัง","อุ้มพาดบ่า","ลากศพ","เมืองแก๊ง","อุ้มเพื่อน","2026-10-12T17:22:50.777785Z","2026-09-16T13:52:19.956202Z",{"id":846,"slug":847,"name":848,"summary":849,"price_thb":26,"license_mode":27,"cover_key":850,"cover_url":851,"category_slugs":852,"tags":853,"latest_version":123,"latest_released_at":864,"published_at":865,"has_docs":54,"config":55,"rent_price_satang":56},"12cb8b4e-b8db-4ad1-a8a2-bd0679aabec5","x3d-environment","X3D Environment","Free one-file map cleaner: no NPCs, no AI traffic, no scenarios, no idle cam, and blood, tire marks and wounds wiped away.","public\u002Fproducts\u002Fx3d-environment\u002Fcover\u002F7aa9b73e2efb1416.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-environment\u002Fcover\u002F7aa9b73e2efb1416.jpg",[732],[33,37,854,732,855,856,857,40,34,858,859,860,861,862,863],"ล้างแมพ","ลดแลค","เพิ่ม FPS","ปิด NPC","ปิดรถ AI","ล้างคราบเลือด","ลบลอยยาง","ปิดกล้อง idle","ลบ NPC","แมพโล่ง","2026-10-12T17:23:03.418375Z","2026-09-16T09:49:13.991696Z",1,31,{"html":869,"headings":870},"\u003Ch2 id=\"installation\">Installation\u003C\u002Fh2>\n\u003Col>\n\u003Cli>Unzip and \u003Cstrong>rename the folder to \u003Ccode>x3d_mailbox\u003C\u002Fcode>\u003C\u002Fstrong> (other scripts call the exports by this name)\u003C\u002Fli>\n\u003Cli>Drop it in \u003Ccode>resources\u002F\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>Add to \u003Ccode>server.cfg\u003C\u002Fcode>:\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cpre>\u003Ccode>ensure x3d_mailbox\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Done — data is stored in \u003Ccode>data\u002Fmailbox.json\u003C\u002Fcode> inside the resource. No SQL to run.\u003C\u002Fp>\n\u003Cp>Players open the mailbox with \u003Ccode>\u002Fmailbox\u003C\u002Fcode> or the \u003Cstrong>F7\u003C\u002Fstrong> key (\u003Ccode>Config.Key\u003C\u002Fcode>, empty = no keybind).\u003C\u002Fp>\n\u003Cp>In the panel: two tabs, \u003Cstrong>Mail\u003C\u002Fstrong> (can expire) and \u003Cstrong>Safe\u003C\u002Fstrong> (a second channel with its own unread\u002FReceive All count — handy for redeem-code rewards), claim one at a time or \u003Cstrong>Receive All\u003C\u002Fstrong> in a single click (scoped to whichever tab is open), \u003Cstrong>delete\u003C\u002Fstrong> a mail once its reward is claimed, see a countdown to expiry, redeem a code from a field right in the panel, and get pinged immediately if a new mail arrives while online.\u003C\u002Fp>\n\u003Cp>No database, no framework, no license required. Works with ESX out of the box, and standalone with no framework installed.\u003C\u002Fp>\n\u003Ch2 id=\"framework-adapters-4-adapters-under-addons\">Framework adapters — 4 adapters under \u003Ccode>addons\u002F\u003C\u002Fcode>\u003C\u002Fh2>\n\u003Cdiv class=\"table-scroll\">\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Folder\u003C\u002Fth>\n\u003Cth>Purpose\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>addons\u002Fframework\u002F\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>Framework.IsBusy()\u003C\u002Fcode> (client) — can the mailbox be opened right now (dead \u002F pause menu); \u003Ccode>Framework.Identifier(src)\u003C\u002Fcode> \u002F \u003Ccode>Framework.IsAdmin(src)\u003C\u002Fcode> (server) — the player's permanent key and admin check\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>addons\u002Fnotify\u002F\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>Notify(message, kind)\u003C\u002Fcode> (client) — notifications\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>addons\u002Freward\u002F\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>Reward.CanCarry\u003C\u002Fcode> \u002F \u003Ccode>Reward.GiveItem\u003C\u002Fcode> \u002F \u003Ccode>Reward.GiveMoney\u003C\u002Fcode> (server) — item\u002Fmoney system\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>addons\u002Fstorage\u002F\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>Storage.Get\u002FSet\u002FAll\u002FFlush\u003C\u002Fcode> (server) — where the data lives (see next section)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003C\u002Fdiv>\n\u003Cp>Every file defaults to working with ESX (it checks \u003Ccode>GetResourceState('es_extended')\u003C\u002Fcode> itself) and carries commented QBCore \u002F ox_lib examples at the bottom to copy over. With no framework at all the mailbox still opens — it just can't deliver attachments until \u003Ccode>Reward.GiveItem\u003C\u002Fcode>\u002F\u003Ccode>GiveMoney\u003C\u002Fcode> is wired up (a console print warns you if it isn't).\u003C\u002Fp>\n\u003Ch2 id=\"storage-json-by-default-or-switch-to-mysql\">Storage — JSON by default, or switch to MySQL\u003C\u002Fh2>\n\u003Cp>Default: a single JSON file (\u003Ccode>Config.Storage.File\u003C\u002Fcode>, default \u003Ccode>data\u002Fmailbox.json\u003C\u002Fcode>), loaded once on resource start, written back every \u003Ccode>Config.Storage.FlushSeconds\u003C\u002Fcode> seconds (default 30) and on player drop \u002F resource stop. An unreadable file is moved to \u003Ccode>data\u002Fmailbox.broken.json\u003C\u002Fcode> and a fresh one is started — the old data is never overwritten.\u003C\u002Fp>\n\u003Cp>To switch to MySQL:\u003C\u002Fp>\n\u003Col>\n\u003Cli>Set \u003Ccode>Config.Storage.Driver = 'oxmysql'\u003C\u002Fcode> — the \u003Ccode>x3d_mailbox\u003C\u002Fcode> table is created automatically and no \u003Ccode>@oxmysql\u003C\u002Fcode> include is needed\u003C\u002Fli>\n\u003Cli>Restart the resource — nothing else to edit. (Only replace the four \u003Ccode>Storage.*\u003C\u002Fcode> functions in \u003Ccode>addons\u002Fstorage\u002Fserver.lua\u003C\u002Fcode> if you want a custom storage backend.)\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2 id=\"exports\">Exports\u003C\u002Fh2>\n\u003Cpre>\u003Ccode class=\"language-lua\">-- target can be a server id (number) or an identifier (string)\nexports['x3d_mailbox']:SendMail(target, {\n    title   = 'Event prize',\n    body    = 'Thanks for joining',\n    sender  = 'Staff',            -- omit = uses the mailbox title\n    box     = 'mail',             -- 'mail' (default, can expire) or 'safe' (the second channel)\n    expires = os.time() + 86400,  -- unix timestamp, omit = never expires\n    items   = { { item = 'bread', count = 5 } },\n    money   = { { account = 'money', amount = 500 } },\n})\n\nexports['x3d_mailbox']:SendMailAll({ title = 'Announcement', body = 'Server restarting tonight' })\n\nexports['x3d_mailbox']:GetMails(src)          --&gt; { {id, title, body, sender, at, expires, read, claimed, box, items, money}, ... }\nexports['x3d_mailbox']:GetUnread(src)         --&gt; number (every box)\nexports['x3d_mailbox']:GetUnread(src, 'safe') --&gt; number (just one box — 'mail' or 'safe')\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ccode>GetMails\u003C\u002Fcode> filters out expired mails automatically, and attaches a Thai \u003Ccode>label\u003C\u002Fcode> from \u003Ccode>Config.ItemLabels\u003C\u002Fcode>\u002F\u003Ccode>Config.AccountLabels\u003C\u002Fcode> to the copies it returns (the stored originals are never touched). \u003Ccode>GetUnread\u003C\u002Fcode> only counts unread, unexpired mails — it returns a plain number, no labels.\u003C\u002Fp>\n\u003Cp>\u003Ccode>SendMail\u003C\u002Fcode> also accepts the shape other mailboxes use — \u003Ccode>subject\u003C\u002Fcode>, \u003Ccode>cash\u003C\u002Fcode>\u002F\u003Ccode>bank\u003C\u002Fcode>, \u003Ccode>items = {{ name, count }}\u003C\u002Fcode>, \u003Ccode>expiresInDays\u003C\u002Fcode> — so moving off an old mailbox is a rename of the export.\u003C\u002Fp>\n\u003Ch2 id=\"events-server-internal-not-a-net-event\">Events — server-internal (not a net event)\u003C\u002Fh2>\n\u003Cpre>\u003Ccode class=\"language-lua\">AddEventHandler('x3d_mailbox:onSend', function(identifier, mail) end)\nAddEventHandler('x3d_mailbox:onClaim', function(src, mail, ok) end)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ccode>x3d_mailbox:onSend\u003C\u002Fcode> fires as soon as a mail is created (from an export or an admin command).\u003C\u002Fp>\n\u003Cp>\u003Ccode>x3d_mailbox:onClaim\u003C\u002Fcode> always fires after a claim is attempted — \u003Cstrong>\u003Ccode>mail.claimed\u003C\u002Fcode> is \u003Ccode>true\u003C\u002Fcode> either way\u003C\u002Fstrong> (the flag is set before payout on purpose, to block a duplicate claim; see Safety below). Check the 3rd argument for the real result — \u003Ccode>ok\u003C\u002Fcode> is \u003Ccode>true\u003C\u002Fcode> only when every attachment was delivered without throwing:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-lua\">AddEventHandler('x3d_mailbox:onClaim', function(src, mail, ok)\n    if not ok then print(('mail %s claimed by %s but a reward failed'):format(mail.id, src)) end\nend)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"admin-commands\">Admin commands\u003C\u002Fh2>\n\u003Cp>\u003Ccode>\u002Fmailsend &lt;server id or identifier&gt; &lt;title&gt; &lt;body…&gt;\u003C\u002Fcode> and \u003Ccode>\u002Fmailsendall &lt;title&gt; &lt;body…&gt;\u003C\u002Fcode> — always callable from the in-game server console; a player needs the \u003Ccode>Config.AdminAce\u003C\u002Fcode> ace (default \u003Ccode>x3d_mailbox.admin\u003C\u002Fcode>) to run them.\u003C\u002Fp>\n\u003Ch2 id=\"safety-properties-backed-by-tests\">Safety properties, backed by tests\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Cstrong>Can't be claimed twice\u003C\u002Fstrong> — the \u003Ccode>claimed\u003C\u002Fcode> flag is written to storage before anything is paid out, with no yield between the check and the write; an \u003Ccode>InFlight[identifier]\u003C\u002Fcode> lock also blocks two simultaneous claim events.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>A broken reward can't lock a player out\u003C\u002Fstrong> — the payout is wrapped in \u003Ccode>pcall\u003C\u002Fcode>; the mail is still marked claimed even if it throws (a misspelled item key from \u003Ccode>\u002Fmailsend\u003C\u002Fcode> won't leave the player retrying forever). A partial delivery tells the player with its own message instead of staying silent, and never reverts what already landed (that would double-pay it).\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Counts are always floored to whole numbers\u003C\u002Fstrong> — fractional or negative attachments never reach the player's inventory.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>The player key is always the permanent identifier\u003C\u002Fstrong>, never the server id.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>The \u003Ccode>Config.MaxMails\u003C\u002Fcode> cap never deletes an unclaimed, unexpired mail\u003C\u002Fstrong> — it trims claimed or expired mails first, oldest first. A mail that's been read but not claimed (and hasn't expired) still has live attachments and is never deleted.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Receive All is one action, not N\u003C\u002Fstrong> — it pays out through the exact same logic as a single claim, scoped to whichever box tab is open (Mail and Safe never claim each other's mail); a mail that doesn't fit is skipped and stays claimable, never paid twice.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Delete only works on a mail with nothing left to claim\u003C\u002Fstrong> — claim it first (or it never had attachments) — the one exception is an expired mail, which is always deletable since it can no longer be claimed at all — and a client-supplied mail id is only ever looked up inside that player's own list.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>\u003Ccode>\u002Fredeem\u003C\u002Fcode> and the redeem net event share the same throttle and lock\u003C\u002Fstrong> — spamming the command can't outrun the rate limit, and the redeem function itself is single-flight per player so two calls can't race each other even if storage starts yielding (e.g. an oxmysql swap).\u003C\u002Fli>\n\u003Cli>\u003Cstrong>\u003Ccode>Config.Codes\u003C\u002Fcode> keys are normalised at boot\u003C\u002Fstrong> — a key typed in the wrong case is fixed automatically instead of silently never matching what a player types (with a console warning naming what changed).\u003C\u002Fli>\n\u003Cli>Rate-limited to 1 call per second per player per action (\u003Ccode>open\u003C\u002Fcode>\u002F\u003Ccode>read\u003C\u002Fcode>\u002F\u003Ccode>claim\u003C\u002Fcode>\u002F\u003Ccode>claimAll\u003C\u002Fcode>\u002F\u003Ccode>delete\u003C\u002Fcode>\u002F\u003Ccode>redeem\u003C\u002Fcode> use separate buckets).\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cpre>\u003Ccode class=\"language-bash\">pip install lupa\npython tools\u002Flua-test\u002Fx3d_mailbox_check.py\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"config-config-lua\">Config (\u003Ccode>config.lua\u003C\u002Fcode>)\u003C\u002Fh2>\n\u003Cdiv class=\"table-scroll\">\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Setting\u003C\u002Fth>\n\u003Cth>Purpose\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>Config.Command\u003C\u002Fcode> \u002F \u003Ccode>Config.Key\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Open command (\u003Ccode>\u002Fmailbox\u003C\u002Fcode>) and keybind (\u003Ccode>F7\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>Config.MaxMails\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Mails kept per player\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>Config.AdminAce\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Ace required for \u003Ccode>\u002Fmailsend\u003C\u002Fcode> \u003Ccode>\u002Fmailsendall\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>Config.Storage.File\u003C\u002Fcode> \u002F \u003Ccode>.FlushSeconds\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>JSON file location and flush interval\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>Config.ItemLabels\u003C\u002Fcode> \u002F \u003Ccode>Config.AccountLabels\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Thai display labels for the mailbox\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>Config.ItemImage\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Path to your inventory's item icons (\u003Ccode>{item}\u003C\u002Fcode> = item name), empty = no icon\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>Config.ExpiryWarnHours\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>A mail with less than this many hours left shows a red countdown in the panel (default 24)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>Config.CanCarryExport\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Your inventory's capacity-check export — empty = ESX \u003Ccode>canCarryItem\u003C\u002Fcode>. \u003Cstrong>Seeing &quot;bag full&quot; on an empty bag? Set this\u003C\u002Fstrong> — ESX's own weight numbers are stale when another inventory owns them.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003C\u002Fdiv>\n\u003Cul>\n\u003Cli>\u003Ccode>Config.DefaultExpireDays\u003C\u002Fcode> — mail sent without an expiry expires after this many days (the safe never expires)\u003C\u002Fli>\n\u003Cli>\u003Ccode>Config.CheckCarry\u003C\u002Fcode> — \u003Ccode>false\u003C\u002Fcode> = claim even with a full bag\u003C\u002Fli>\n\u003Cli>\u003Ccode>Config.NotifyUnreadOnJoin\u003C\u002Fcode> — tell the player their unread count when they load in\u003C\u002Fli>\n\u003Cli>Item names fall back to the framework's item label when \u003Ccode>Config.ItemLabels\u003C\u002Fcode> has no entry\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"redeem-codes\">Redeem codes\u003C\u002Fh2>\n\u003Cp>A player types \u003Ccode>\u002Fredeem &lt;code&gt;\u003C\u002Fcode>, or types the code into the field right in the mailbox panel, and the reward is \u003Cstrong>delivered as mail\u003C\u002Fstrong> — a full bag can never lose it, it simply waits in the mailbox.\u003C\u002Fp>\n\u003Cp>Permanent codes live in \u003Ccode>config.lua\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-lua\">Config.Codes = {\n    WELCOME2026 = {\n        maxUses       = 0,        -- 0 = unlimited server-wide\n        oncePerPlayer = true,     -- one per player (default)\n        title         = 'Welcome',\n        items         = { { item = 'bread', count = 2 } },\n        money         = { { account = 'bank', amount = 1000 } },\n    },\n    EVENTONLY = {\n        maxUses = 100,            -- first 100 players only\n        expires = 1790000000,     -- unix time the code stops working\n        box     = 'safe',         -- deliver into the safe instead of mail (optional, default 'mail')\n        money   = { { account = 'money', amount = 5000 } },\n    },\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Runtime codes from another resource (gone on restart):\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-lua\">exports['x3d_mailbox']:AddCode('EVENT2026', { maxUses = 50, money = { { account = 'bank', amount = 2000 } } })\nexports['x3d_mailbox']:RemoveCode('EVENT2026')\nexports['x3d_mailbox']:GetCodeUsage('EVENT2026')   --&gt; { uses = 12, by = { ['license:xxx'] = true } }\nexports['x3d_mailbox']:Redeem(src, 'EVENT2026')    --&gt; ok, reason\n\nAddEventHandler('x3d_mailbox:onRedeem', function(src, code, def) end)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Usage is stored beside the mail under the system key \u003Ccode>__redeem\u003C\u002Fcode>: it survives a restart, and the broadcast command never writes into it.\u003C\u002Fp>\n\u003Ch2 id=\"support\">Support\u003C\u002Fh2>\n\u003Cp>Discord: discord.gg\u002Fx3d-developer · Web: x3d-developer.com\u003C\u002Fp>\n",[871,875,878,881,884,887,890,893,896,899],{"id":872,"text":873,"level":874},"installation","Installation",2,{"id":876,"text":877,"level":874},"framework-adapters-4-adapters-under-addons","Framework adapters — 4 adapters under addons\u002F",{"id":879,"text":880,"level":874},"storage-json-by-default-or-switch-to-mysql","Storage — JSON by default, or switch to MySQL",{"id":882,"text":883,"level":874},"exports","Exports",{"id":885,"text":886,"level":874},"events-server-internal-not-a-net-event","Events — server-internal (not a net event)",{"id":888,"text":889,"level":874},"admin-commands","Admin commands",{"id":891,"text":892,"level":874},"safety-properties-backed-by-tests","Safety properties, backed by tests",{"id":894,"text":895,"level":874},"config-config-lua","Config (config.lua)",{"id":897,"text":898,"level":874},"redeem-codes","Redeem codes",{"id":900,"text":901,"level":874},"support","Support",1792316314620]