Skip to main content

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 in lua-code/config.lua.

Licenses

config.lua

Custom cards

Every entry needs exactly one condition: item, job (optionally with minGrade) or license.
config.lua
Custom cards are evaluated every time the wallet loads — take the item away, revoke the license or demote the player and the card is gone on the next open.

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 m so a player who is one step too far still appears; the show itself is refused with Too far away beyond ShowRadius.
  • 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 showWalletCard with 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 name boss 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.
A membership card issued to the wrong person is fixed by revoking it — there is no edit. Issue a new one instead.

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.
The photo URL captured in the app is validated against the upload host allow-list (fivemanage.com or the hosts named for a custom upload endpoint). A URL from any other host is refused with bad_url, so a modified client cannot put an arbitrary image on an ID card.

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 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.
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.
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.
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.
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.
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.
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.

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