Browse docs
Server Exports
Call these exports from your resource's server Lua. To open a tablet application from a player's menu, use Client Exports.
Declare DOJ as a dependency in your resource's fxmanifest.lua:
dependency "sky_dojjob"
Let DOJ finish its normal database startup before requesting records. Database-backed calls can yield; use a normal FiveM event, callback or thread, keep results local to the request and handle failure before using data. These exports do not expose a public HTTP API.
The document and condition APIs take an online player server ID. DOJ resolves that player's current job, duty and permissions on the server. Passing 0, a character identifier or an actor table does not create a service-account bypass. If your script accepts a client request, capture the event's actual source; never accept a player ID or author identity from the request body.
SetHearingStatus has a different contract: it is a trusted server automation API, and its optional actor is only an audit identity. An evidence provider must authorize its own records. Read those sections before connecting a player-facing action.
API overview
| Export | Purpose |
|---|---|
GetDocumentTemplates(source, options?) | List templates available to the acting player. |
CreateCaseDocument(source, payload) | Create a draft from a published template, optionally in an existing case file. |
GetCaseDocument(source, reference) | Read an accessible document and its saved draft. |
GetConditionOrders(source, filters?) | List court-condition orders with bounded filters. |
GetConditionOrder(source, reference) | Read an order, conditions, evidence, violations and event history. |
GetPublicHearingPayload() | Read the public courthouse timetable. |
SetHearingStatus(reference, status, actor?, options?) | Change hearing status from trusted server automation. |
RegisterCourtroomEvidenceProvider(name, resolver) | Register a source of courtroom evidence. |
GetCourtroomPresentationForPlayer(source, reference?) | Read the presentation that the player is allowed to see. |
Documents
GetDocumentTemplates(source, options?)
local result = exports["sky_dojjob"]:GetDocumentTemplates(player_source, {
publishedOnly = true,
summaryOnly = true,
})
if not result.success then
print(("Template lookup failed: %s"):format(result.error))
return
end
for _, template in ipairs(result.data.templates) do
print(template.id, template.key, template.displayName)
end
| Option | Meaning |
|---|---|
publishedOnly | Use true when selecting a template for document creation. Managers can otherwise see their latest unpublished revisions. |
summaryOnly | Use true for a picker. Omit or use false to include body, field schema and page settings. |
templateId | Optional template UUID returned by an earlier lookup. |
registryKey | Defaults to criminal_justice. Leave this default for the normal File Explorer. |
Success returns { success = true, data = { templates, registryKey, permissions, unavailableTemplates } }. Each template includes id, key, code, displayName, revision, status, publishedVersionId and version. A full version includes id, version, fieldSchema, bodyTemplate, pageMaster, pageSettings, referenceFormat and signaturePolicy.
IDs belong to the current database. Use the returned UUID, not a UUID copied from demo data. The shipped arrest-warrant key is doj-hb; servers can customize templates, so inspect the returned schema before supplying fields. The template UUID and template-version UUID are different IDs.
CreateCaseDocument(source, payload)
Call this after the user chooses a published template and your integration has collected its fields. player_source, selected_template_id and prepared_fields below come from that existing server workflow.
local result = exports["sky_dojjob"]:CreateCaseDocument(player_source, {
templateId = selected_template_id,
caseTitle = "Hearing preparation",
subject = "Example Subject",
authorCode = "AM",
fieldValues = prepared_fields,
})
if not result.success then
print(("Document creation failed: %s"):format(result.error))
return
end
local document = result.data.document
print(document.id, document.caseFileId, document.documentNumber)
if not document.draft.valid then
-- Keep the created draft and let the author complete the listed fields.
for _, failure in ipairs(document.draft.validationErrors) do
print(json.encode(failure))
end
end
| Field | Meaning |
|---|---|
templateId | Required published template UUID. The current published version is captured by the server. |
caseFileId | Optional existing case UUID. The player must be allowed to edit that case. |
caseTitle | Required only when creating a new case, maximum 160 characters. |
subject | Optional new-case subject, maximum 240 characters. Existing cases retain their subject. |
authorCode | Required code, 1–8 characters, beginning with a letter; letters, digits and hyphens. Normalized to uppercase. It is a reference component, not the author's authenticated identity. |
fieldValues | Table keyed by the chosen template's field keys. Values are validated against its schema. |
referenceInput | Required when the template's reference format uses {REFERENCE}. Otherwise may be omitted. |
folderId | Optional destination folder UUID for a newly created case. Must be writable by the actor. |
workspaceOwner | Optional existing shared workspace owner. Existing workspace permissions apply. Omit for the actor's workspace. |
Success returns { success = true, data = { caseFile, link, document, draft } }. link is present for a newly created case. A successful creation can contain an incomplete draft: inspect draft.valid and draft.validationErrors. Signing remains an explicit authorized action in the document editor.
The server generates case/document identifiers, renders the published template, writes the audit event and captures header, footer, watermark and page settings. Supplying renderedContent, a template code or another author's identity does not replace those server-owned values. Editing a template later does not rewrite this document's captured version.
Persist the returned document/case IDs in your integration record. This is a create operation, not an upsert: do not blindly repeat it after an uncertain response. Check the File Explorer before retrying an operation that may already have committed.
GetCaseDocument(source, reference)
local result = exports["sky_dojjob"]:GetCaseDocument(player_source, {
documentId = stored_document_id,
})
if not result.success then
print(("Document lookup failed: %s"):format(result.error))
return
end
local document = result.data.document
print(document.documentNumber, document.title, document.draft.revision)
Supply either documentId or caseFileId, never both. Prefer the exact document UUID when a case contains several documents. The case-only form selects the case's first document using the service's existing ordering.
data.document includes document and case IDs, display references, title, status, document revision, template snapshot, draft, signing summary and resolved case references. draft includes its separate revision, fields, renderedContent, renderedPageMaster, valid and validationErrors.
The returned content is structured editor data; it is not a PDF URL or a license to reveal the file to another player. Forward content only to the same authorized actor. Use the established Share and Print workflow for other recipients and physical copies.
Document failures
| Error | Action |
|---|---|
not_authorized, edit_not_authorized, AUTH_* | Check job, duty, role mapping, clearance and case/workspace access. Keep the returned correlationId for diagnostics when present. |
document_not_found | The document is missing or outside the actor's accessible scope. |
invalid_template_id, invalid_document_reference, invalid_fields, invalid_author_code, invalid_reference_input | Correct the payload using current IDs and schema. |
version_conflict | Reopen/read the current state before continuing. |
rate_limited, busy, network_unstable | Stop repeated requests; let the current operation finish or resolve the connection issue. |
database_error, invalid_stored_template, invalid_stored_document | Inspect server diagnostics and migrations; do not treat failure as an empty list. |
Document exports share the tablet's per-player throttles: template reads 250 ms, creation 1,000 ms and document reads 150 ms. They do not bypass the current ACL, mutation lock or audit path.
Court conditions
GetConditionOrders(source, filters?)
local result = exports["sky_dojjob"]:GetConditionOrders(player_source, {
subjectIdentifier = subject_identifier,
status = "active",
limit = 25,
offset = 0,
})
if not result.success then
print(("Condition lookup failed: %s"):format(result.error))
return
end
for _, order in ipairs(result.data.items) do
print(order.orderKey, order.status, order.conditionCount)
end
Filters are optional: subjectIdentifier, status, search, limit and offset. search matches order key, case reference, source reference and subject name. Default limit is 50; the configured maximum defaults to 100. Offsets must be integers from 0 to 1,000,000. Order statuses are active, completed, review_required, continuation_requested and cancelled.
Success returns { success = true, data = { items, total, limit, offset } }. An empty items list is a valid result. Each item includes orderKey, subject, source/case references, status and condition/violation counts.
GetConditionOrder(source, reference)
local result = exports["sky_dojjob"]:GetConditionOrder(player_source, {
orderKey = selected_order_key,
})
if result.success then
local order = result.data
print(order.orderKey, #order.conditions)
else
print(("Order detail failed: %s"):format(result.error))
end
The detail response includes the order plus conditions, violations and events. Each condition contains its own evidence and violations lists. orderKey is the stable string key, not the numeric database ID. Missing orders return not_found; malformed references return invalid_order_key.
These calls require the configured DOJ job, enabled Tablet/Conditions modules, required duty state and application access. They do not grant civilians access to orders about themselves. They reuse normal condition refresh: provider progress is reconciled and overdue conditions are checked before results are returned. Use them when opening or updating the relevant screen, not in a per-frame loop. Execution and compliance updates continue through the configured adapters and authorized DOJ workflow.
Hearings
GetPublicHearingPayload()
local timetable = exports["sky_dojjob"]:GetPublicHearingPayload()
for _, hearing in ipairs(timetable.hearings) do
print(hearing.publicReference, hearing.courtroom, hearing.startsAt, hearing.statusLabel)
end
This export returns the payload directly, without a { success, data } envelope. Fields include generatedAt, locale, heading, subheading, maxRows, compact, rooms, hearings and syncSequence. It queries the configured public display time window and returns only enabled public hearing entries. Subject and judge names obey each hearing's disclosure flags. Private notes, full case content and participant assignments are not in this payload.
SetHearingStatus(reference, status, actor?, options?)
local result = exports["sky_dojjob"]:SetHearingStatus(hearing_key, "in_progress", {
identifier = "system:court_scheduler",
name = "Court scheduler",
})
if not result.success then
print(("Hearing transition failed: %s"):format(result.error))
end
reference accepts the hearing key or numeric hearing ID. This existing export is for trusted server automation: actor is an audit identity and does not authenticate a player. Do not forward a client-supplied reference/status/actor directly to it. Player actions should use the existing permission-checked hearing interface.
Allowed changes follow the hearing lifecycle: reserved/delayed can start; in_progress, paused and deliberation can transition between their supported phases and finish/close; finished can close; closed and cancelled cannot reopen. Cancellation is available before the hearing starts. A repeated current status is accepted for synchronization.
Returns { success = true, data = hearing } or { success = false, error }. Status and active courtroom state are synchronized through the normal transaction/lock path. Common failures include not_found, invalid_status_transition, courtroom_occupied, courtroom_unavailable and database_error. Leave options unset unless working with the maintained courtroom integration; internal options are not a player-facing configuration API.
Courtroom evidence
RegisterCourtroomEvidenceProvider(name, resolver)
-- server.lua; Archive is your resource's own server-side data/permission service.
local registered = exports["sky_dojjob"]:RegisterCourtroomEvidenceProvider("archive", function(player_source, reference, context)
local record = Archive.FindReadable(player_source, reference.reference)
if not record then
return nil, "evidence_not_found"
end
return {
sourceType = "archive",
sourceReference = reference.canonical,
sourceVersion = record.immutableVersion,
label = record.title,
mediaType = "document",
assetUrl = record.httpsUrl,
pageCount = record.pageCount,
}
end)
assert(registered, "DOJ evidence provider registration failed")
Users enter archive:<your-record-id> in the evidence reference field. Provider names are 1–40 lowercase letters/digits/underscores/hyphens; police_case and doj_file are reserved. Registration returns a boolean. The resolver receives the acting player, normalized reference (provider, reference, canonical) and courtroom context (sessionKey, hearingKey, job). It must verify the actor's read access itself and return nil, errorCode when inaccessible.
Return a stable sourceVersion, label, media type, HTTPS assetUrl and pageCount (1–5,000). The exact media host must be in Config.Courtroom.allowedMediaHosts, configured through Job Configurator. A provider cannot skip evidence approval or the audience's room/bucket checks. The remote asset must remain available and unchanged; the stored reference hash does not freeze bytes hosted by an external website.
Providers are removed when their resource stops. Re-register after the provider or DOJ restarts. Never keep a cached export function or resolver from an earlier resource instance.
GetCourtroomPresentationForPlayer(source, reference?)
local result = exports["sky_dojjob"]:GetCourtroomPresentationForPlayer(player_source, {
courtroomKey = configured_room_key,
})
if result.success and result.data.active then
-- Send only this authorized presentation to player_source's own display.
end
The reference can specify courtroomKey, sessionKey/sessionId or hearingKey/hearingId. With no reference, DOJ resolves the player's nearby active room; ambiguous rooms fail explicitly. The current room, routing bucket, participant/audience entitlement and evidence approval govern the response. An accessible session with no active evidence returns success = true and data.active = false. This is not a global broadcast API.
Internal compatibility exports
ImportPoliceDocumentEvent accepts only the sky_policejob server resource and its validated JSON event contract. It is not a generic third-party import endpoint. Use CreateCaseDocument for an authorized actor's new documents.
GetDojRecordsGradeOptions, GetDojTaxSocietyJobOptions, GetDojTaxCurrencyOptions and GetDojTaxPaymentModeOptions supply Job Configurator choices. They are configuration providers, not record access APIs. Client-side shared-preview and radial compatibility exports are listed in Client Exports.