Browse docs

Server Exports

Create DOJ template documents, query court conditions and connect hearings or courtroom evidence from server resources.

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

ExportPurpose
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
OptionMeaning
publishedOnlyUse true when selecting a template for document creation. Managers can otherwise see their latest unpublished revisions.
summaryOnlyUse true for a picker. Omit or use false to include body, field schema and page settings.
templateIdOptional template UUID returned by an earlier lookup.
registryKeyDefaults 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
FieldMeaning
templateIdRequired published template UUID. The current published version is captured by the server.
caseFileIdOptional existing case UUID. The player must be allowed to edit that case.
caseTitleRequired only when creating a new case, maximum 160 characters.
subjectOptional new-case subject, maximum 240 characters. Existing cases retain their subject.
authorCodeRequired 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.
fieldValuesTable keyed by the chosen template's field keys. Values are validated against its schema.
referenceInputRequired when the template's reference format uses {REFERENCE}. Otherwise may be omitted.
folderIdOptional destination folder UUID for a newly created case. Must be writable by the actor.
workspaceOwnerOptional 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

ErrorAction
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_foundThe document is missing or outside the actor's accessible scope.
invalid_template_id, invalid_document_reference, invalid_fields, invalid_author_code, invalid_reference_inputCorrect the payload using current IDs and schema.
version_conflictReopen/read the current state before continuing.
rate_limited, busy, network_unstableStop repeated requests; let the current operation finish or resolve the connection issue.
database_error, invalid_stored_template, invalid_stored_documentInspect 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.