Every QR carries a HMAC the gate can verify in one trip.
The QR on a voteMe ticket is a base64url-encoded payload containing the ticket ID, event ID, signing version, a hash of the holder email, and the issue timestamp β concatenated with an HMAC-SHA256 signature. The scanner verifies the signature locally before it ever hits the server.
The signing key lives in a single environment variable paired with a version counter. To rotate β for example, because a staff device was compromised β bump the version on the event's ticketing settings. Newly-issued tickets sign with the new key. Existing tickets remain valid because the validator checks every known version until a match or rejection.
Because signature verification is cryptographic, a QR that someone photographed off your phone cannot be used to walk through the gate a second time. The same ticket flips to used on the first successful scan, and every subsequent scan returns already_used with the scanner ID, gate number, and timestamp. You know exactly who walked in when.