Skip to content

Server Events

The phone announces its lifecycle moments as plain server-local events. Listen with a standard handler:

lua
AddEventHandler('sd-phone:server:messages:sent', function(message)
    -- react to the send
end)

All events fire via TriggerEvent, which is synchronous: handlers run inline inside the phone's own action, so keep them cheap and never let them error. Payloads carry citizenids where noted; they are for trusted server resources and must not be forwarded to clients unfiltered.

Phone Numbers

sd-phone:server:number:assigned

Fires exactly once per character, when their phone number is first minted.

lua
AddEventHandler('sd-phone:server:number:assigned', function(citizenid, number)
    print(citizenid .. ' was assigned ' .. number)
end)
ParameterTypeDescription
citizenidstringThe character the number was minted for
numberstringThe raw-digit number

INFO

No source argument: minting can happen with the owner offline (the getPhoneNumberByIdentifier export with ensure = true). Resolve a server id yourself when you need one, and expect nil.


Messages

sd-phone:server:messages:sent

Fires once per logical SMS send, on all three delivery paths: a player's 1:1 send, a player's group send, and a system text.

lua
AddEventHandler('sd-phone:server:messages:sent', function(m)
    if not m.system and not m.group then
        print(m.senderNumber .. ' texted ' .. m.targetNumber)
    end
end)
ParameterTypeDescription
systembooleantrue for sendSystemMessage-style service texts
groupbooleantrue for group-thread sends
sourcenumber|nilSending player's server id (absent on system texts)
citizenidstring|nilSending character (absent on system texts)
senderNumberstringSending number
senderNamestring|nilDisplay name (system texts only)
targetNumberstring|nilRecipient number (1:1 and system)
targetCitizenidstring|nilRecipient character, nil when the number is not in service
targetSourcenumber|nilRecipient's server id when online and delivered live
groupIdnumber|nilGroup thread id (group sends)
memberstable|nilGroup roster of { citizenid, number, name } (group sends); treat as read-only
kindstringMessage kind (text, image, gif, location, ...)
bodystringMessage text
metatable|nilSanitized kind metadata
midstringShared logical id correlating the per-mailbox copies
messageIdnumberStored row id (sender copy for player sends, recipient copy for system texts)
recipientIdnumber|nilRecipient copy row id, nil when no copy was stored
withheldboolean|niltrue when airplane mode is holding the delivery
timestampnumberUnix seconds

INFO

On a 1:1 send, targetCitizenid can be set while recipientId and targetSource are nil: the number is in service but the sender is blocked, and the block is deliberately indistinguishable from offline.


Mail

sd-phone:server:mail:sent

Fires once per mail send, both player composes and system mail.

lua
AddEventHandler('sd-phone:server:mail:sent', function(mail)
    print(('%s mailed %d recipient(s): %s'):format(mail.from.email, #mail.to, mail.subject))
end)
ParameterTypeDescription
systembooleantrue for sendMail-style system senders
idstring|nilStored message id (absent on a system send that reached nobody)
citizenidstring|nilSending character (player composes only)
fromtable{ name, email }
tostring[]Normalized recipient addresses
subjectstringSubject line
bodystringBody text
sentAtnumberUnix seconds
deliverednumber|nilRecipient accounts that existed (system sends only)

Calls

All call events share one call table:

FieldTypeDescription
channelnumberThe pma-voice call channel, doubling as the call id
companystring|nilDisplay name for company/group rings, nil for 1:1 calls
callertable{ source, citizenid, name, number }
calleetable|nilSame shape; nil on group rings before an answer
targetstable|nilGroup rings only: everyone rung, same party shape

sd-phone:server:call:started

Fires when a 1:1 call starts ringing, and once per company/group ring (with targets populated and callee nil).

lua
AddEventHandler('sd-phone:server:call:started', function(call)
    print(call.caller.number .. ' is calling ' .. (call.callee and call.callee.number or call.company))
end)

sd-phone:server:call:answered

Fires when a call is answered, including a group ring being promoted to a live call (the answering employee becomes callee; company keeps the display name). The payload adds startedAt (unix seconds at answer).

sd-phone:server:call:ended

Fires on every teardown, answered or not, with endedBy as a second argument.

lua
AddEventHandler('sd-phone:server:call:ended', function(call, endedBy)
    if call.answered then
        print(('call on channel %d lasted %ds'):format(call.channel, call.duration))
    end
end)

Extra payload fields on this event:

FieldTypeDescription
answeredbooleanWhether the call was ever active
durationnumberSeconds, 0 when never answered
reasonstring'declined', 'hangup', 'disconnected', or 'unavailable'
ParameterTypeDescription
calltableThe call table above
endedBynumber|nilServer id that caused the teardown, nil on disconnects

INFO

Cancelled group rings that nobody answered also fire this event (answered = false, callee = nil), so a dispatch script can observe missed company calls. Payloads are built from stored session state, so a disconnecting player still appears with the data they rang with.


Services

sd-phone:server:services:message

Fires when a citizen messages a company through the Services app (or the messageCompany export).

lua
AddEventHandler('sd-phone:server:services:message', function(e)
    if e.job == 'police' then
        print(('911 text from %s (%s): %s'):format(e.name, e.number, e.body))
    end
end)
ParameterTypeDescription
sourcenumberSending player's server id
citizenidstringSending character
jobstringCompany job name
labelstringCompany display label
numberstringSender's phone number
namestringSender's display name
kindstringComposer kind
bodystringMessage text
metatable|nilKind metadata

Banking

sd-phone:server:banking:transaction

Fires when an externally-logged Wallet row is appended (the addBankTransaction export or the internal event that backs it).

ParameterTypeDescription
citizenidstringRow owner
sourcenumber|nilOwner's server id when online
amountnumberSigned amount, positive = money in
labelstringRow label
categorystring|nilCategory tag
counterpartystring|nilWho the money moved to or from
timestampnumberUnix seconds

sd-phone:server:banking:transfer

Fires once per player-to-player Wallet transfer made in the phone.

ParameterTypeDescription
fromCitizenidstringSender
fromNumberstringSender's number
fromSourcenumberSender's server id
toCitizenidstringRecipient
toNumberstringRecipient's number
toSourcenumber|nilRecipient's server id when online
amountnumberAmount moved
notestring|nilTransfer note
timestampnumberUnix seconds

Photos

sd-phone:server:photos:added

Fires when a photo lands in a gallery, on every add path: camera captures, saved URLs, and the addPhoto export.

ParameterTypeDescription
sourcenumberOwner's server id
citizenidstringOwner
idnumberGallery row id
urlstringHosted media URL

sd-phone:server:photos:deleted

Fires when a player deletes media from their own gallery. Retention pruning and admin wipes bypass it deliberately.

ParameterTypeDescription
sourcenumberOwner's server id
citizenidstringOwner
idnumberDeleted row id
urlstringThe deleted media URL

Social

sd-phone:server:birdy:post

Fires when a new Birdy post is created.

ParameterTypeDescription
idnumberPost id
sourcenumberAuthor's server id
citizenidstringAuthor
usernamestringAuthor's handle
displayNamestringAuthor's display name
bodystringPost text
imagesstring[]|nilAttached image URLs, nil for text-only posts

sd-phone:server:photogram:post

Fires when a new Photogram post is created.

ParameterTypeDescription
idnumberPost id
sourcenumberAuthor's server id
citizenidstringAuthor
usernamestringAuthor's handle
imagesstring[]Post media URLs
captionstringCaption (may be empty)
locationstring|nilLocation tag
privatebooleanWhether the author's account is private

INFO

Private authors' posts are scoped to approved followers inside the app. This payload is server-local and trusted; never forward it to clients unfiltered.


Classifieds

sd-phone:server:pages:post

Fires when a new Pages listing is posted. Payload fields come from the stored row: { id, source, citizenid, number, title, body, price, image, images } (images is the stored JSON string).

sd-phone:server:marketplace:post

Fires when a new Marketplace listing is posted. Same shape as the Pages event.


Contacts

sd-phone:server:contacts:added

Fires when a contact lands in a player's phone book, from the app, the addContact export, or an accepted AirShare.

ParameterTypeDescription
sourcenumberOwner's server id
citizenidstringOwner
idnumberContact row id
namestringContact name
phonestringContact number, digit-normalized
sharedbooleantrue when it arrived via AirShare

sd-phone:server:contacts:removed

Fires when contacts are removed, from the app delete or the removeContactByNumber export.

ParameterTypeDescription
sourcenumberOwner's server id
citizenidstringOwner
idnumber|nilRow id (app deletes)
phonestringRemoved number, digit-normalized
removednumberRows removed

Settings

sd-phone:server✈️released

Fires when a player switches airplane mode off, releasing withheld messages.

ParameterTypeDescription
sourcenumberThe player's server id

TIP

Client-local events (phone opened, camera mode, flashlight) live on the Client Events page. Third-party scripts written against lb-phone's events keep working through the lb-phone compatibility layer.