Wallet
The Wallet app collects everything a character carries as a card: an ID with photo, licenses, the job and gang card, custom passes you configure, membership cards issued by businesses and tickets bought in the Events app. Nothing is stored twice — every card is built live from the framework and the phone’s own tables when the app opens, so a revoked license or a job change shows up immediately.Built from your framework
Identity, licenses, job and gang come straight from ESX, QBCore or Qbox. There is nothing to sync and nothing to migrate.
Show, don't hand over
A card is shown to one player within
Config.Wallet.ShowRadius for ShowDuration seconds. The receiver sees the card — never a copy they could keep.Tickets with check-in
Organizers check a ticket in from the card shown to them. The ticket flips to Checked in on the holder’s phone at the same moment.
Membership cards
Job bosses issue expiring cards — gym member, VIP, staff — from the Events app; your own scripts do the same through an export. Holders are notified and see the card right away.
Wallet is a default app and present on every phone. Tickets and membership cards come from the Events app, which players install through the App Shop; configure it under Events and Wallet.
What ends up in the wallet
The app has three sections: IDs & Licenses, Cards & Passes and Tickets.Framework coverage
The ID number on the card is a stable hash of the player identifier, so on ESX the card never shows
license:….
Setup
1
Nothing to enable
The Wallet is part of every RoadPhone Pro install.
roadshop_wallet_profiles, roadshop_wallet_cards and the Events tables are created on boot. Servers that cannot run the automatic setup use lua-code/sql/wallet_events.sql.2
Check the upload method
The ID photo is a headshot of the player’s ped, uploaded through the phone’s regular upload path. It needs a working
Config.uploadMethod (fivemanage or a custom endpoint). Without it the card works, but stays without photo and the app keeps offering Renew photo.3
Map your licenses and add passes
Review
Config.Wallet (below). The default maps drive / driver and weapon; add every license type your server uses.4
Restart
ensure roadphone. Open the Wallet on a character with a job and a license to verify the cards.Configuration
Everything lives inlua-code/config.lua.
Licenses
config.lua
Custom cards
Every entry needs exactly one condition:item, job (optionally with minGrade) or license.
config.lua
Player flow
1
First open: the ID photo
The app asks for a photo before it shows any card. Take photo renders a headshot of the ped as it looks right now (the text tells players to remove masks first), uploads it and stores the URL on the character. Later skips the step for this session; the ID card then reads Photo pending until a photo exists. Renew photo on the ID card repeats the capture at any time.
2
Browse
IDs & Licenses, Cards & Passes and Tickets are separate sections. Tapping a card opens it large, with every field the server sent — issue and expiry dates, holder, ticket code.
3
Show a card
Show lists the players standing within
ShowRadius by name and distance. Picking one sends the card to that player only. The sender sees Card shown, Too far away or Could not show the card.4
Receiving a card
The receiver’s phone shows the card as an overlay with a countdown of
ShowDuration seconds and who is showing it. With the phone closed, a notification and a lockscreen card announce it; opening the Wallet from there shows the card as long as time is left.5
Tickets
A ticket card carries the event location. Route sets a waypoint on the map. At the door, the holder shows the ticket to the organizer — see below.
How showing is verified
- The server measures the distance between both players; the client only proposes candidates. Players in a different routing bucket are never offered.
- The nearby list scans
ShowRadius + 2 mso a player who is one step too far still appears; the show itself is refused with Too far away beyondShowRadius. - The receiver gets a snapshot of the card, built at that moment for the sender. It disappears after
ShowDuration(clamped to 1–120 seconds on the phone) and is never stored. - A player can show one card every two seconds. Scripts use
showWalletCardwith the same checks and no rate limit.
Tickets and check-in
1
Buy
Tickets are bought in the Events app (bank money, up to
Config.Events.MaxTicketsPerBuyer per event). Each ticket has a unique code in the form EV-XXXXXX and appears in the Wallet’s Tickets section right away.2
Show at the door
The holder opens the ticket and shows it to the organizer. On the organizer’s phone the shown ticket carries a Check in button — only when they own the event, the event is still active and the ticket has not been checked in yet.
3
Check in
Check in stamps the ticket server-side. The holder receives a notification (Your ticket for … has been checked in), the card flips to Checked in with the time on both phones, and a second attempt shows Already checked in at ….
4
After the event
Tickets read Expired once the event is over or cancelled and leave the wallet one day after the event ended. Refunds for cancelled events and organizer payouts are pending money: they are credited to the bank account the next time the Wallet opens, or through Collect in the Events app.
Check-in is bound to the code of the ticket that was shown, to the organizer’s identifier and to the distance between organizer and holder — a ticket cannot be checked in from a screenshot or from across the map.
Membership cards (businesses)
A job boss — grade nameboss on ESX, isboss on QBCore / Qbox — finds a Business tab in the Events app. From there they issue and revoke membership cards of their job:
The holder gets a notification (New membership card) and the wallet refreshes without reopening. The card shows business, holder, who issued it and the issue and expiry dates; after expiry it stays for seven days marked Expired, then drops out. Bosses see up to 300 active cards of their job in the Business tab.
Your own resources issue the same cards through
issueWalletCard — any label, any business name, online or offline players, no boss required.
Data model
Every card the phone receives has the same shape. Labels are locale keys where the phone has a translation and plain text otherwise;fields are rendered in order with their kind deciding the formatting.
meta.valid and meta.status drive the status badge: Checked in, Expired, Invalid or Valid.
Two tables belong to the Wallet itself; tickets and events are documented with the Events configuration.
Events
The server exports (
getWalletCards, hasWalletCard, issueWalletCard, showWalletCard, …), the callbacks behind the app and the card schema are on the Wallet API page.
Troubleshooting
The ID card has no photo / the photo could not be saved
The ID card has no photo / the photo could not be saved
The capture renders a headshot, uploads it and stores the URL. Check
Config.uploadMethod and the upload credentials — the same path the camera app uses. A URL from a host outside the allow-list is refused as bad_url; a custom endpoint must name its hosts in uploader/upload-server.lua.A license the player owns is not in the wallet
A license the player owns is not in the wallet
The entry’s
keys must match the license name as the framework stores it: user_licenses.type on ESX (drive, weapon, …), the keys of PlayerData.metadata.licences on QBCore / Qbox (driver, weapon, …). Add every spelling your server uses to keys.Show says Too far away although the players stand next to each other
Show says Too far away although the players stand next to each other
The server measures the distance between the two peds itself and requires the same routing bucket. Instanced interiors with per-player buckets block the show — as intended, since the players are not in the same world.
No Business tab in the Events app
No Business tab in the Events app
The player is not detected as boss. ESX needs the grade name
boss; QBCore / Qbox needs isboss = true on the job grade. Check Bridge.Job.IsBoss for your framework.A ticket disappeared from the wallet
A ticket disappeared from the wallet
Tickets are kept until one day after the event ended; cancelled events are shown as Expired until then. Refunds are credited when the Wallet opens next, or through Collect in the Events app.
Cards show raw keys like WALLET_LICENSE_DRIVE
Cards show raw keys like WALLET_LICENSE_DRIVE
The key is missing in the language file of the phone’s current language (
public/static/locales/<lang>.json). Add it there, or use plain text as label in Config.Wallet.Wallet shows Could not load Wallet
Wallet shows Could not load Wallet
The server answered
db_error: the console shows a [Wallet] traceback with the failing query. Usually a missing table on a server that skipped the automatic setup — run lua-code/sql/wallet_events.sql.Related Resources
Wallet API
Exports for reading, showing and issuing cards, plus callbacks, events and the card schema
Events configuration
Event creation, ticket limits and the Business tab
Custom upload
The upload endpoint the ID photo goes through
Fold
On the Fold the Wallet uses the full width of the inner display