> For the complete documentation index, see [llms.txt](https://sbscripts.gitbook.io/sb-scripts/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sbscripts.gitbook.io/sb-scripts/sb-speedtraps/tickets-and-licences.md).

# Tickets and Licences

### How a ticket is issued

1. The client checks the line the car drove since the last check, not just its current position, so a fast car can't skip the zone. If that line passes within the radius of the blip above `limit + Config.Detection.Tolerance`, the trap fires once per pass, with a per-trap cooldown.
2. The server checks that the trap exists and is active, that the player is the driver, that they're within the radius plus a small allowance, that the job or plate isn't exempt, and that they're not on cooldown. It then caps the reported speed against the vehicle's server-side velocity.
3. The server writes the ticket, gives the item, and sends the flash, sound and notification.

Whose ticket it is depends on the plate (`Config.Owner`):

* **Your own car, or a car nobody owns** (NPC, rental or stolen): you get the ticket and the item.
* **Someone else's car:** the registered owner gets the ticket by phone email only, with no item. The driver still sees the flash and a notice that the owner was ticketed. The ticket counts towards the owner's fines and licence, and the police panel shows who was driving. If the speed is at least `Dispatch.MinOver` over the limit, a dispatch alert is sent too.

**Fine** = `price + perUnit x (speed - limit)`, capped at `maxFine`. Overdue tickets add `LateFeePercent` when paid.

### The ticket item

Each ticket stores its details as metadata on the item. Using the item opens the full citation. The database is only read for the live status (paid, unpaid, overdue or removed). Fields include the citation number, plate, vehicle, driver, speed and limit, fine, location, and issued and due dates.

Copy `install/speeding_ticket.png` into your inventory's image folder, then add the item.

**qb-core, ps, lj or codem** (`qb-core/shared/items.lua`):

```lua
speeding_ticket = {
    name        = 'speeding_ticket',
    label       = 'Speeding Ticket',
    weight      = 0,
    type        = 'item',
    image       = 'speeding_ticket.png',
    unique      = true,
    useable     = true,
    shouldClose = true,
    description = 'A citation from a speed camera.',
},
```

**ox\_inventory** (`ox_inventory/data/items.lua`):

```lua
['speeding_ticket'] = {
    label = 'Speeding Ticket',
    weight = 0,
    stack = false,
    close = true,
    consume = 0,
    description = 'A citation from a speed camera.',
},
```

The README includes an optional inventory tooltip snippet for qb-inventory and ps-inventory, in `FormatItemInfo` in `app.js`.

### Licence revocation

Licence revocation needs QBCore or Qbox. On other frameworks, tickets and fines still work and licence revocation is skipped.

* Every `Tickets.CheckInterval` minutes, and when a player loads in, unpaid tickets past their due date become **overdue**.
* At `License.OverdueToRevoke` overdue tickets, the driver licence is revoked. With `License.RemoveItem` on, the licence card is taken away too.
* When nothing is overdue any more, the licence is reinstated. This only happens if this script revoked it.
