API Contracts¶
Purpose¶
This file defines active, framework-independent endpoint contracts and
envelopes. Historical TYPE/ACTION module notes are retained only where a
legacy module shell still exists.
Endpoint Inventory¶
| Endpoint | Path | Method | Purpose |
|---|---|---|---|
| module read | app/systems/<SYSTEM>/<module>/query.php |
GET/POST | legacy module-owned reads where still present |
| module write | app/systems/<SYSTEM>/<module>/post.php |
POST | legacy module-owned writes where still present |
| sync | app/controllers/sync.php |
GET | temporary compatibility checksum polling from temp/<TABLE>; active app callers use /api/platform/sync/checksums |
| excel | app/controllers/excel.php |
GET | authenticated TMS packing-list XLSX and BMS QuickBooks CSV export |
| media | app/controllers/media.php |
POST | temporary compatibility adapter for upload/download/datestamp; active app callers use /api/files/media/* |
| gmail | app/controllers/gmail.php |
POST | temporary legacy/server-token email/PDF compatibility surface; active browser booking inquiry, packing list, and BOL dispatch callers use API v2 |
| Gmail Add-on | public/gmail/addon.php |
GET/POST | token-protected Gmail Workspace Add-on gateway for appointment email summary, explicit item apply, and reply draft creation |
| AI extraction | app/controllers/chatgpt.php |
POST | legacy Gemini-backed document/OCR extraction and prompt compatibility surface; active browser extraction and prompt tasks use owner API v2 routes |
| API v2 | api/index.php |
GET/POST/PATCH/PUT/DELETE | framework-independent successor routes without TYPE/ACTION |
| Telegram webhook | public/telegram/webhook.php |
POST | Telegram Bot API message/callback handler; validates TELEGRAM_WEBHOOK_SECRET for every request, falling back to TELEGRAM_TOKEN when a separate webhook secret is not configured |
| Telegram cron | public/telegram/cron.php or cron.php telegram_breaks |
GET/POST or CLI | protected maintenance endpoint/CLI job for closing expired loader break queue rows and sending the next queued job Telegram when available |
| Gmail Add-on gateway | public/gmail/addon.php |
GET/POST | token-protected Workspace Add-on gateway for current-message appointment analysis, apply, reply draft creation, and status |
Legacy Controller Status¶
app/controllers/query.phpandapp/controllers/post.phpwere removed in #454.app/controllers/master.phpandapp/controllers/autocomplete.phpwere removed in #1088 after committed source scan and lookup route validation showed active callers use owner API v2 routes.- Active application list callers use explicit API v2 table-list routes; the shared jTable compatibility endpoint was removed after the staged cutover.
- Active application callers must use API v2 or specialized controllers listed above, not shared
TYPE/ACTIONread/write dispatch. - Direct module endpoint shells that still exist are legacy implementation surfaces and must not be used by new API v2 clients.
app/controllers/media.phpremains a temporary compatibility surface only; active upload, download, and datestamp callers use/api/files/media/*.app/controllers/sync.phpremains a temporary compatibility surface only; active checksum polling callers use/api/platform/sync/checksums.app/controllers/gmail.phpremains a temporary compatibility surface for server-token or legacy email/PDF callers. Active browser booking inquiry, packing-list email, and BOL email dispatch use owner API v2 routes.app/controllers/chatgpt.phpremains a temporary compatibility surface for direct legacy/external AI callers. The shared browser fallback surface was removed in #1087, so browser code must use owner API v2 routes or fail visibly for unsupported AI task/prompt names.app/controllers/excel.phpremains a specialized authenticated download surface for TMS packing-list XLSX and BMS QuickBooks CSV exports. The QuickBooks CSV branch also updatesT_TRANSACTION.CHECK_NUMBER, so it is not a read-only API v2 download candidate without an explicit owner command contract.- Write handlers that reuse legacy helpers still flush
sync_tasks[]throughapp/shared/sync/task_registry.php.
API v2 Successor Contract¶
API v2 is the current framework-independent successor contract. It is not a
compatibility layer over legacy TYPE/ACTION.
API v2 contract rules:
- API v2 HTTP routes enter through
/api/...and are dispatched byapi/index.php. - API v2 shared helpers live under
app/shared/api/; route definitions live inapp/platform/api_routes.php,app/shared/*/api_routes.php,app/addons/*/api_routes.php, orapp/systems/*/*/api_routes.php. - Request bodies must not use
TYPE,ACTION, orUSERNAMEas contract fields. - Route definitions carry explicit module ownership and must not depend on
moduleGuardEndpointModuleKey(). - API v2 success responses use
{ "data": ..., "requestId": "..." }. - API v2 errors use
{ "error": { "code": "...", "message": "..." }, "requestId": "..." }. - API v2 list routes may support
LIMIT,OFFSET,PAGE, andCOUNT_TOTAL=1for server-side pagination;ITEMS_ONLY=1omits the legacy duplicatevaluearray and returnsitemsplus metadata such astotal,page,pageSize,startIndex, andhasMore. - API v2 response helpers must preserve binary-safe JSON behavior equivalent to
JSON_INVALID_UTF8_SUBSTITUTE. - File/media API v2 work must preserve hybrid EFS/S3
T_FILEbehavior from #460. - API v2 route matching currently supports exact paths and regex patterns; unsupported methods return HTTP 405 with
Allow. - API v2 auth uses the existing session (
login_username) and module gating uses explicit routemoduleKeywithgetClientId(). - Staff time event creation may perform a silent outbound QuickBooks Time sync after the CTC staff-time write has committed when
QUICKBOOKS_TIME_ACCESS_TOKENis configured. Local staff-time writes remain the source of truth; QuickBooks Time failures, skipped states, and manual-review states are logged underintegrations/quickbooks-timeand must not remove the local event or add integration fields to the UI/API response. - QuickBooks Time staff-time sync maps
CLOCK_INto an active regular timesheet,CLOCK_OUTto ending the active staff-time timesheet,BREAK_INto ending the active regular timesheet and opening an active break timesheet, andBREAK_OUTto ending the active break timesheet and opening a new active regular timesheet. Existing QuickBooks Time behavior is preserved by allowingQUICKBOOKS_TIME_REGULAR_JOBCODE_ID=0for no-jobcode regular work and by using existing QuickBooks Time break jobcodes for break/lunch. Staff-time currentDAYandWEEKtotals count10MIN BREAKas paid time and excludeLUNCH BREAKas unpaid time. External active timesheets outside the configured staff-time model are left unchanged and logged asmanual_review_required.
QuickBooks Time staff-time sync config:
QUICKBOOKS_TIME_ACCESS_TOKEN: QuickBooks Time OAuth bearer token or API Add-On access token. If this is empty, sync is skipped silently.QUICKBOOKS_TIME_CLIENT_ID,QUICKBOOKS_TIME_CLIENT_SECRET,QUICKBOOKS_TIME_REDIRECT_URI,QUICKBOOKS_TIME_PUBLIC_BASE_URL,QUICKBOOKS_TIME_CTC_CLIENT_ID: optional OAuth setup values for the public production app URLs.QUICKBOOKS_TIME_SETUP_TOKENis recommended for initial production setup authorization only while no QuickBooks Time access token is configured for the tenant; reconnect after a tenant token exists requires an authenticated CTC tenant administrator or super admin session. When OAuth succeeds, the access token is stored inT_TENANT_CONFIG.QUICKBOOKS_TIME_ACCESS_TOKENfor the configured CTC client. Staff-time sync still readsQUICKBOOKS_TIME_ACCESS_TOKENthrough tenant config first and env fallback second. IfQUICKBOOKS_TIME_REFRESH_TOKENis present and expiry metadata is missing or expiring, sync refreshes OAuth tokens before calling QuickBooks Time.- QuickBooks Time user identity is stored on the staff user record as
T_USER.QUICKBOOKS_TIME_USER_ID; if the value is missing, sync is skipped/logged for that staff event. QUICKBOOKS_TIME_REGULAR_JOBCODE_ID: QuickBooks Time jobcode for regular loader work. Use0to preserve the existing no-jobcode regular clock-in/out behavior.QUICKBOOKS_TIME_BREAK_10_JOBCODE_ID,QUICKBOOKS_TIME_LUNCH_JOBCODE_ID: existing QuickBooks Time break jobcodes for 10-minute and lunch breaks.QUICKBOOKS_TIME_BASE_URL: defaults tohttps://rest.tsheets.com/api/v1.QUICKBOOKS_TIME_TIMEOUT_SECONDS: defaults to2and is capped at10; sync runs after the local response is scheduled and must not block the local write path.QUICKBOOKS_TIME_WEEK_START_DAY: day name used by staff-time current state to compute the Time ClockWEEKtotal; defaults toSUNDAYand acceptsSUNDAYthroughSATURDAY.
QuickBooks Time production app URLs:
/quickbooks-time/connect: public connect/reconnect page that starts OAuth authorization when app credentials are configured and the request has a tenant administrator session, super admin session, or setup token before any tenant QuickBooks Time access token is configured./quickbooks-time/callback: public OAuth redirect page that validates state and exchanges the authorization code./quickbooks-time/disconnect: public disconnect page for Intuit app configuration; GET renders a landing page only, and POST clears tenant-stored QuickBooks Time token metadata only after setup-token authorization or tenant administrator/super admin authorization with a valid session CSRF token./api/quickbooks-time/connect,/api/quickbooks-time/callback, and POST/api/quickbooks-time/disconnect: API counterparts for setup checks./privacy-policyand/terms-of-use: public legal URLs for production app review.
Gmail Workspace Add-on gateway:
public/gmail/addon.phpis a public integration endpoint for Apps Script and is not an API v2 session route.- Requests must send
Authorization: Bearer <GMAIL_ADDON_TOKEN>orX-CTC-Gmail-Addon-Token; query-string tokens are not accepted. - The Apps Script project must set
GMAIL_ADDON_TOKENand may setGMAIL_ADDON_API_URL; the latter points athttps://ctclogistic.com/public/gmail/addon.phpin production. - Success responses use
{ "data": ..., "requestId": "..." }; errors use{ "error": { "code": "...", "message": "..." }, "requestId": "..." }. - Supported actions are
status,analyze,apply, andreply-draft;reply_draftanddraftare accepted aliases forreply-draft. GET action=statusreturns mailbox/watch setup state and supported actions.POST action=analyzerequiresgmailMessageIdand returns the parsed appointment request summary, item list, safe item ids, reply-draft-ready item ids, safe/review counts, andreviewUrlfor the CTC system review page. If the message has not been ingested yet, the gateway may ingest the Gmail message through the configured mailbox OAuth token before returning the summary; an already-ingested message with no actionable rows must not be re-ingested unlessforceRefreshis true. The optionalpreferFastflag is intended for interactive Gmail add-on selection/refresh flows and may use deterministic table extraction before falling back to Gemini.POST action=applyacceptsitemIds,outcome, optionaledits, andreplyMode(NONEorDRAFT) for explicit item-level handling by the add-on.POST action=reply-draftacceptsgmailMessageIdoritemIdsand creates same-thread Gmail drafts only for selected resolved items that have no existing reply message.POST action=process-safeis not an active gateway action. Apps Script safe-processing UI must callapplywith backend-selected item ids, or a separate alias must be implemented before it is documented as supported.GMAIL_ADDON_CLIENT_IDoptionally pins the tenant context and defaults toConfig::CLIENT_ID.GMAIL_ADDON_SYSTEM_BASE_URLandGMAIL_ADDON_REVIEW_PATHmay override the system link used forReview in System; defaults are the CTC app base URL and/transload-email-approval.
The active legacy-to-v2 route inventory and deletion conditions live in .agents/rules/API_V2_CONTRACT_INVENTORY.md.
The conditional React-specific proposal is retained in
.agents/rules/REACT_API_CLIENT.md; it has no current adoption authority.
The final cutover validation runbook lives in docs/runbooks/API_V2_CUTOVER_VALIDATION_RUNBOOK.md.
KJTable API v2 list contract¶
- Active KJTable schemas set
dataSource.adaptertoapi-v2and provide an explicit endpoint beginning with/api/; active callers must not sendtype,TYPE, orACTION. - List requests use
GETwithoffset,limit, optionalsort/direction, optionalfrom/to, and column filters encoded asfilter[<column>]. - Successful responses use
{ "data": { "items": [...], "total": <number>, "checksums": {...}, "query": <string|null> }, "requestId": "..." }. Bothitemsand a non-negative numerictotalare required; malformed 2xx payloads are visible adapter errors, not empty lists. - Each route definition pins its internal legacy query type and its
moduleKeyserver-side. Neither value is accepted from the browser, preserving the existing query, effective-tenant, permission, filter, sort, paging, checksum, and refresh behavior during the staged cutover. - Active route families are
/api/platform/table-lists/*,/api/yms/table-lists/*,/api/tms/table-lists/*,/api/oms/table-lists/*, and/api/bms/table-lists/*.
Active API v2 routes:
| Route | Method | Module key | Purpose |
|---|---|---|---|
/api/platform/ping |
GET, POST | none | authenticated platform/session and JSON parsing smoke |
/api/platform/account/password |
PATCH | none | current-session password change without legacy ACCOUNT contract |
/api/platform/sync/checksums |
GET | none | authenticated checksum polling over temp/<TABLE> tokens without using the legacy sync.php controller |
/api/platform/menu/tree |
GET, PATCH | platform.menu |
visible menu tree read and reorder/update; permission-only route rows are excluded; write clears KJ_MENU_CACHE |
/api/platform/menu/favorites |
GET, POST | none | current-user sidebar favorite menu list/add; permission-only rows are excluded; available to admin/office-style roles and stores favorites by user/menu UUID mapping |
/api/platform/menu/favorites/{id} |
DELETE | none | soft-delete a current-user sidebar favorite by numeric menu id |
/api/platform/menu/items |
POST | platform.menu |
create menu item |
/api/platform/menu/items/{id} |
PATCH, DELETE | platform.menu |
update/delete menu item |
/api/platform/menu/roles |
GET | platform.menu |
role list for menu permissions |
/api/platform/menu/roles/{id}/default-menu |
PATCH | platform.menu |
update role default menu |
/api/platform/module-pages |
GET | none | page registry list for menu/admin tools |
/api/platform/table-lists/{chassis,users,commodities,companies,drivers,master-data,carriers} |
GET | route-specific | explicit platform/master list reads for the KJTable API v2 adapter |
/api/yms/table-lists/* |
GET | route-specific | explicit YMS import/export/container/equipment list reads for the KJTable API v2 adapter |
/api/tms/table-lists/{transloads,deliveries,loading-planner,driver-logs} |
GET | route-specific | explicit TMS list reads for the KJTable API v2 adapter |
/api/oms/table-lists/{bookings,customer-pos} |
GET | oms.inbound-order |
explicit OMS list reads for the KJTable API v2 adapter |
/api/bms/table-lists/* |
GET | route-specific | explicit BMS transaction/rate/scale-ticket/fuel list reads for the KJTable API v2 adapter |
/api/platform/users |
POST | none | create tenant user without generic T_USER write |
/api/platform/users/{id} |
GET, PATCH | none | tenant user detail/update without exposing password hash |
/api/platform/users/roles |
GET | none | user role options |
/api/platform/users/check-username |
GET | none | username availability check |
/api/platform/companies |
GET, POST | none | tenant company list/create for company popup flows |
/api/platform/companies/options |
GET | none | tenant company option list for master-data replacement flows; supports bounded search, company type filter, and optional blank value |
/api/platform/companies/search |
GET | none | tenant company autocomplete search without legacy TYPE; returns suggestions plus raw items |
/api/platform/companies/form |
POST, PATCH | none | company popup form update/delete for company and company-email rows |
/api/platform/companies/{id} |
GET | none | tenant company detail with email rows |
/api/platform/master-data/form |
POST, PATCH | table-specific menu role | generic popup form create/update/delete for allowlisted master-data tables; each requested table requires access to its owning menu (chassis-list, commodity-list, or master-list) |
/api/platform/master-data/options |
GET | none | bounded T_MASTER category option list replacing deleted legacy master-data lookup flows |
/api/platform/master-data/row |
GET | table-specific menu role | allowlisted master-data row detail for popup edit fallback; the requested table requires access to its owning menu (chassis-list, commodity-list, or master-list) |
/api/platform/commodities/options |
GET | none | tenant commodity option list for master-data replacement flows, including name-only compatibility mode |
/api/platform/commodities/search |
GET | none | tenant commodity autocomplete search without legacy TYPE; returns suggestions plus raw items |
/api/platform/operation-events |
GET, POST | none | bounded persisted operation notification feed/create; GET defaults to recent screen-facing candidates, applies current role policy, and returns only public display fields; POST is super-admin test tooling only |
/api/platform/operation-events/count |
GET | none | server-backed unread persisted operation notification count and latest visible event ID cursor for current role policy within the bounded notification window |
/api/platform/operation-events/preferences |
GET, PATCH | none | current user's enabled/disabled choices for role-visible notification types; a preference can only suppress a type and never grants visibility outside the role policy |
/api/platform/operation-events/ack |
PATCH | none | acknowledge/read multiple persisted operation notifications by UUID for the current role policy; this is not workflow confirmation |
/api/platform/operation-events/{uuid}/ack |
PATCH | none | acknowledge/read a persisted operation notification; this is not workflow confirmation |
/api/platform/operation-events/{uuid}/unack |
PATCH | none | undo acknowledgement for a persisted operation notification when the current role can acknowledge it; used only for immediate UI undo |
/api/addons/telegram/messages |
POST | addon.telegram |
canonical authenticated Telegram notification send |
/api/addons/ai-verifications/ingate-ticket/ai-extract |
POST | addon.reports |
Gemini-backed INGATE_TICKET extraction for AI verification rows |
/api/platform/telegram/send |
POST | none | compatibility Telegram send route; do not add new callers |
/api/platform/codex/overview |
GET | none | admin/superadmin Codex Portal overview backed by configured Codex file roots; returns accessible projects, recent active sessions, and a bounded archive slice without full transcript scans |
/api/platform/codex/projects/{projectKey}/sessions |
GET | none | admin/superadmin Codex Portal session list for source=active, archive, or all; reads Codex JSONL metadata from configured file roots and does not use DB session tables |
/api/platform/codex/projects/{projectKey}/sessions/{sessionId} |
GET | none | admin/superadmin Codex Portal lazy session detail; reads one matching JSONL transcript and returns display-safe terminal lines while skipping developer/system messages |
/api/platform/codex/projects/{projectKey}/sessions/{sessionId}/restore |
POST | none | admin/superadmin Codex Portal archive restore reference; writes a portal-local JSON pointer under storage/codex-portal/restored and does not mutate Codex archive files |
/api/platform/codex/projects/{projectKey}/sessions/{sessionId}/messages |
POST | none | admin/superadmin Codex Portal runner entrypoint for active sessions only; starts a background codex exec resume --json process for the selected session and records runner state under storage/codex-portal/runs |
/api/platform/codex/projects/{projectKey}/sessions/{sessionId}/archive |
POST | none | admin/superadmin Codex Portal archive action; blocks working sessions, moves active JSONL files into the configured archive directory, and removes restored pointers without mutating archive JSONL contents |
/api/platform/admin/* |
GET, POST, PATCH | none | super-admin console tenants/users/logs/monitor/integrity/db/mass-action/onboarding routes |
/api/platform/admin/control-tower |
GET | none | super-admin Control Tower deployment, tenant UUID, and runtime mapping registry; registry data comes from CONTROL_TOWER_DB_*, while current-server metadata comes from the active runtime |
/api/platform/admin/control-tower/deployments |
POST | none | create a Control Tower deployment/server registry row in the CONTROL_TOWER_DB_* database |
/api/platform/admin/control-tower/deployments/{id} |
PATCH | none | update a Control Tower deployment/server registry row in the CONTROL_TOWER_DB_* database |
/api/platform/admin/control-tower/tenants |
POST | none | create a Control Tower global tenant identity row in the CONTROL_TOWER_DB_* database |
/api/platform/admin/control-tower/tenants/{id} |
PATCH | none | update a Control Tower global tenant identity row in the CONTROL_TOWER_DB_* database |
/api/platform/admin/control-tower/mappings |
POST | none | create a tenant-to-deployment runtime mapping row in the CONTROL_TOWER_DB_* database |
/api/platform/admin/control-tower/mappings/{id} |
PATCH | none | update a tenant-to-deployment runtime mapping row in the CONTROL_TOWER_DB_* database |
/api/platform/admin/logs/codex |
GET | none | super-admin session or Authorization: Bearer <CTC_CODEX_LOG_API_TOKEN> / X-CTC-Codex-Log-Token; Codex-friendly bounded JSONL log diagnostics; supports channel, date, sinceMinutes, limit, scanLines, requestId, path, module, username, status, method, contains, errorOnly, and includeRaw filters without arbitrary file reads |
/api/yms/yard-map/ping |
GET | yms.yard-map |
authenticated module guard smoke |
/api/yms/yard-map/sections |
GET | yms.yard-map |
yard-map section geometry read model |
/api/yms/yard-map/state |
GET | yms.yard-map |
yard-map occupancy and read-only map state |
/api/yms/yard-moves/dispatch-queue |
GET | yms.yard-move |
yard dispatch queue read model, including role-policy-filtered autoAssign* alert fields for unacknowledged operation events sourced from auto-marked queue assignments |
/api/yms/yard-moves/returning-empty |
GET | yms.yard-move |
returning empty queue read model |
/api/yms/yard-moves/assignable-users |
GET | yms.yard-move |
assignable yard dispatch user list |
/api/yms/yard-truck-drivers/staff-state |
GET | yms.yard-move |
yard truck driver staff-time status roster with current/day totals, open break state, and claimed dispatch counts for the yard dispatch board; Armando/Ezekiel remain yard-truck-dedicated, while shared forklift/yard staff only appear when in YARD_TRUCK context or holding claimed yard dispatch work |
/api/yms/yard-truck-drivers/break |
POST | yms.yard-move |
manager yard dispatch break start/end command for Yard Truck Driver users using T_STAFF_TIME_EVENT.WORK_CONTEXT='YARD_TRUCK' |
/api/yms/yard-moves/unmapped-entities |
GET | yms.yard-move |
unmapped yard entity search/read model |
/api/yms/yard-locations/occupied-items |
GET | yms.yard-move |
occupied yard location item picker; optional blockingForLocation returns CY stack blockers above the target location |
/api/yms/yard-locations/available |
GET | yms.yard-move |
available yard locations by area type; CY L2/L3 spots blocked only by AUTO:CY_L1_TRL:<lane> are included when the L1 trailer has an active clearing queue |
/api/yms/yard-locations/stack-groups |
GET | yms.yard-move |
available stack group options |
/api/yms/yard-locations/available-by-stack-group |
GET | yms.yard-move |
available yard locations by stack group; CY L2/L3 spots blocked only by a clearing L1 trailer are eligible |
/api/yms/yard-moves/preview |
POST | yms.yard-move |
yard dispatch move preview for complex request bodies |
/api/yms/yard-locations/reset |
POST | yms.yard-move |
reset yard location occupancy for selected equipment |
/api/yms/yard-locations/move |
POST | yms.yard-move |
move/register an occupied yard entity |
/api/yms/yard-locations/vacate |
POST | yms.yard-move |
vacate a yard location |
/api/yms/yard-moves/queue |
POST, PATCH | yms.yard-move |
create or update yard dispatch queue items |
/api/yms/yard-moves/queue/relocate-before-pull-out |
POST | yms.yard-move |
create a relocate queue item immediately before a queued/scheduled pull-out parent and preserve the parent link through the system remark tag |
/api/yms/yard-moves/queue-after-clear |
POST | yms.yard-move |
queue a CTN/TRL/CHS move behind an active clearing move for the occupied target location |
/api/yms/yard-moves/queue/reorder |
POST | yms.yard-move |
reorder yard dispatch queue items |
/api/yms/yard-moves/queue/cancel |
POST | yms.yard-move |
cancel a queue item |
/api/yms/yard-moves/queue/claim |
POST | yms.yard-move |
claim a queue item |
/api/yms/yard-moves/queue/unclaim |
POST | yms.yard-move |
unclaim a queue item |
/api/yms/yard-moves/queue/confirm |
POST | yms.yard-move |
confirm a queue item |
/api/yms/yard-moves/dispatch/complete |
POST | yms.yard-move |
complete an active yard dispatch |
/api/yms/yard-moves/* write commands |
POST | yms.yard-move |
reserve, confirm, cancel, claim, and dispatch command routes backed by explicit transactions |
Yard move queue destinations support exact spot codes, DROP, stack-group instructions, single-area instructions such as A AREA, and the DIP pull-out A/C AREA instruction. A/C AREA is CTN-only and must be confirmed into an available A or C spot.
| /api/yms/containers/mobile | GET | yms.container-tracking | mobile container tracking list |
| /api/yms/containers/empty | GET | yms.container-tracking | available empty container list for appointment/transload flows |
| /api/yms/yard-containers | GET | yms.container-tracking | yard container lookup for closing/selection flows |
| /api/yms/equipment-loads/search | GET | yms.container-tracking | bounded active equipment-load autocomplete search by container number; replaces deleted legacy EQUIPMENT_LOAD autocomplete flow |
| /api/yms/equipment-loads/{id}/container-detail | GET | yms.container-tracking | container edit detail payload |
| /api/yms/equipment-loads/container-details | GET | yms.container-tracking | multi-container edit detail payload |
| /api/yms/containers/by-delivery | GET | yms.container-tracking | container detail by delivery id |
| /api/yms/containers/by-equipment-load | GET | yms.container-tracking | container detail by equipment load id |
| /api/yms/containers/by-deliveries | GET | yms.container-tracking | container list by delivery ids |
| /api/yms/equipment/by-delivery | GET | yms.container-tracking | equipment detail by delivery id |
| /api/yms/equipment-information/{id} | GET | yms.container-tracking | equipment information row detail for popup edit fallback |
| /api/yms/equipment-information/form | POST, PATCH | yms.container-tracking | equipment information popup form create/update/delete |
| /api/yms/equipment/{id}/repair-logs | GET | yms.container-tracking | equipment repair log list |
| /api/yms/fleet-management/dashboard | GET | yms.container-tracking | fleet dashboard read model by asset type/search, including selected assets, recent activities, due/work-order/document signals, summary, and typeCounts active/inactive/total counts by asset type for sidebar filter badges |
| /api/yms/fleet-management/assets | POST, PATCH | yms.container-tracking | create/update fleet asset profiles backed by T_EQUIPMENT_INFORMATION |
| /api/yms/fleet-management/assets/{id} | GET | yms.container-tracking | fleet asset detail with shaped asset, activities, and missing document signals |
| /api/yms/fleet-management/activities | POST, PATCH | yms.container-tracking | create/update fleet service, inspection, odometer/meter, work-order, and status activities backed by T_EQUIPMENT_ACTIVITY |
| /api/yms/containers/validate-numbers | POST | yms.container-tracking | pasted container-number validation |
| /api/yms/containers/validate-full-ready | POST | yms.container-tracking | full-ready validation by equipment load ids |
| /api/yms/containers/form | POST, PATCH | yms.container-tracking | container popup form create/update/delete for allowed equipment tables |
| /api/yms/containers/seal-photo/ai-extract | POST | yms.container-tracking | Gemini-backed CONTAINER_SEAL_PHOTO OCR for seal number extraction |
| /api/yms/containers/street-turn | POST | yms.container-tracking | street-turn an import container into an empty export-ready load |
| /api/yms/containers/return-bookings | PATCH | yms.container-tracking | update selected equipment return-booking links |
| /api/yms/containers/mobile/{id}/empty-weight | PATCH | yms.container-tracking | mobile container empty-weight update |
| /api/yms/equipment-repair-logs/{id} | GET | yms.container-tracking | equipment repair log detail for popup edit |
| /api/yms/dock-scheduling/available-docks | GET | yms.dock-scheduling | available dock option list |
| /api/yms/dock-scheduling/available-yard-locations | GET | yms.dock-scheduling | available yard-location option list; includes CY L2/L3 mobile-lane targets when the L1 trailer blocker has an active clearing queue |
| /api/yms/dock-scheduling/planning-yard-locations | GET | yms.dock-scheduling | planning yard-location option list; includes CY L2/L3 mobile-lane targets when the L1 trailer blocker has an active clearing queue |
| /api/yms/dock-scheduling/appointments | GET | yms.dock-scheduling | dock appointment list |
| /api/yms/scale/schedule | GET | yms.scale | scale schedule read model |
| /api/yms/scale/tickets | GET | yms.scale | scale ticket list read model |
| /api/yms/scale/tickets/{id} | GET, DELETE | yms.scale | scale ticket detail read model and scale portal delete |
| /api/yms/scale/check-in | POST, PATCH | yms.scale | scale check-in create/update |
| /api/yms/scale/check-out | POST | yms.scale | scale check-out write |
| /api/yms/scale/purchase-inbound/walk-in | POST | yms.scale | create server-normalized ad-hoc walk-in purchase inbound shell without a commercial PO |
| /api/yms/scale/purchase-inbound/finalize | POST | yms.scale | purchase inbound finalization from scale |
| /api/tms/transloads/planning-board | GET | tms.transload | transload planning board read model, including planner loader display, PLANNER_LAST_SENT_TIME, and role-policy-filtered autoAssign* alert fields for unacknowledged AUTO_PLANNED/AUTO_ASSIGNED operation events |
| /api/tms/transloads/assignment-auto-mode | GET, PATCH | tms.transload | tenant-wide Assignment Board auto-assignment mode stored as TMS_TRANSLOAD_ASSIGNMENT_AUTO_MODE; accepts/returns manual or auto-send so one open browser cannot keep running auto assignments after another operator turns Auto off |
| /api/tms/transloads/instruction-rules | GET, PATCH | tms.transload | tenant-wide appointment/reload instruction rules stored as TMS_TRANSLOAD_INSTRUCTION_RULES; TMS_TRANSLOAD_INSTRUCTION_ENABLED=0 returns { enabled: false, rules: [] } and rejects PATCH, otherwise GET falls back to built-in defaults when no rules config exists and PATCH requires at least one valid rule |
| /api/tms/transloads | GET | tms.transload | transload rows by comma-separated ids for popup edit flows |
| /api/tms/transloads/form | POST, PATCH | tms.transload | transload popup form create/update/delete for allowed transload table fields |
| /api/tms/transloads/load-to-load-reconcile | POST | tms.transload | copy selected transload inbound final bale quantity/weight to outbound final quantity/weight |
| /api/tms/transloads/{id} | GET | tms.transload | transload row detail for popup edit flows |
| /api/tms/transloads/{id}/scale-ticket | PATCH | tms.transload | link a created BMS scale ticket to a transload row |
| /api/tms/transloads/{id}/bol-email | POST | tms.transload | send BOL and weight email with BOL company-email recipients, scale-ticket PDF, and transload file attachments |
| /api/tms/transloads/load-schedule/ai-extract | POST | tms.transload | Gemini-backed LOAD_SCHEDULE extraction through the transload owner route |
| /api/tms/transloads/export-schedule/ai-extract | POST | tms.transload | Gemini-backed export-transload scheduling target extraction; availability remains client timeblock logic |
| /api/tms/transloads/load-schedule/ai-prompt | GET, PATCH | tms.transload | read/save the tenant prompt for LOAD_SCHEDULE extraction |
| /api/tms/loading-planner/{id} | GET, PATCH, DELETE | tms.transload | loading-planner row detail/update/delete for planner UI and loader assignment; delete cancels related planner yard queues and returns active planning statuses to ARRIVED |
| /api/tms/loading-planner/form | POST, PATCH | tms.transload | loading-planner popup form create/update/delete |
| /api/tms/equipment-loads/{id}/transloads | GET | tms.transload | transload rows attached to an equipment load |
| /api/tms/transloads/plan-preview | POST | tms.transload | transload planner preview command |
| /api/tms/transloads/plan-apply | POST | tms.transload | apply generated transload plan |
| /api/tms/transloads/assign-submit | POST | tms.transload | submit loader/warehouse assignment |
| /api/tms/transloads/loader-assignment | POST, PATCH | tms.transload | loader board assignment command that keeps active planner and docked transload loader in sync |
| /api/tms/transloads/loader-telegram | POST | tms.transload | loader board Telegram send command that records planner LAST_SENT_TIME after successful send |
| /api/tms/transloads/stuck-dip-cleanup | POST | tms.transload | force-clear a stuck started dock-in-plan planner by REL/load number when the unloaded/docked load has no active yard trailer location |
| /api/tms/transloads/confirm-plan | POST | tms.transload | confirm planned transload dispatch |
| /api/tms/transloads/plan | PATCH | tms.transload | edit planning fields |
| /api/tms/transloads/domestic-dock-plan | PATCH | tms.transload | create/update only the active domestic pickup planner dock (T_LOADING_PLANNER.AREA_NUMBER_TO) without writing T_TRANSLOAD.WAREHOUSE_LOCATION or yard-map occupancy |
| /api/tms/transloads/check-in | POST | tms.transload | planning-board check-in command |
| /api/tms/transloads/mobile-check-in | POST | tms.transload | appointment-board check-in command preserving mobile carrier-master behavior |
| /api/tms/transloads/dock-in | POST | tms.transload | dock trailer and sync yard occupancy |
| /api/tms/transloads/dock-in-after-clear | POST | tms.transload | queue trailer dock-in behind an active clearing yard move when the selected dock is still occupied |
| /api/tms/transloads/stage | PATCH | tms.transload | update staging/loading instruction |
| /api/tms/transloads/start-transloading | POST | tms.transload | start outbound container loading execution |
| /api/tms/transloads/start-unloading | POST | tms.transload | start inbound unloading execution |
| /api/tms/transloads/complete-transloading | POST | tms.transload | complete outbound transload; Added results require no source-lot selection or inventory reservation |
| /api/tms/transloads/complete-unloading | POST | tms.transload | complete inbound unloading into warehouse and return optional telegram completion-report send status |
| /api/tms/transloads/request-stack-footprint-review | POST | tms.transload | loader signals that a completed unload needs Office physical stack-space review |
| /api/tms/transloads/complete-unloading-spare | POST | tms.transload | disabled direct unload-to-Spare action; complete unloading first, then use the separate Spare transition |
| /api/tms/transloads/complete-spare | POST | tms.transload | CTC Office UNLOADED → SPARE; preserves the existing lot, warehouse location, and placement |
| /api/tms/transloads/create-domestic-pickup-unit | POST | tms.transload | create or link a missing domestic pickup equipment unit/load from a checked-in planning card |
| /api/tms/transloads/undo | POST | tms.transload | undo docked/in-progress transload execution |
| /api/tms/transloads/doc-submitted | PATCH | tms.transload | update document submitted flag |
| /api/tms/drivers/identity | GET | tms.delivery | resolve current WordPress-linked driver identity through T_USER.USERNAME |
| /api/tms/drivers/search | GET | tms.delivery | truck/forklift operator autocomplete search with optional carrier company filter; replaces deleted legacy DRIVER autocomplete flow |
| /api/tms/driver-logs/current | GET | tms.delivery | current non-finished driver log by username or userId/USER_ID |
| /api/tms/driver-logs/{id} | GET | tms.delivery | driver log detail row for native Driver Log editor |
| /api/tms/deliveries/driver-list | GET | tms.delivery | driver-operation delivery work list; supports userId/USER_ID |
| /api/tms/deliveries | GET | tms.delivery | delivery rows by comma-separated ids for popup edit flows |
| /api/tms/deliveries/form | POST, PATCH | tms.delivery | delivery and driver-log popup form create/update/delete |
| /api/tms/deliveries/{id} | GET | tms.delivery | delivery row detail for popup edit flows |
| /api/tms/bookings | GET, POST | tms.booking | booking list/create flows |
| /api/tms/bookings/search | GET | tms.booking | bounded booking autocomplete search; replaces deleted legacy BOOKING autocomplete flow |
| /api/tms/bookings/drayage-empty-options | GET | tms.booking | current Export Dashboard export -trucking booking option list with terminal/company ids for Export Dispatch Drayage Queue empty creation |
| /api/tms/bookings/booking-instruction/ai-extract | POST | tms.booking | Gemini-backed BOOKING_INSTRUCTION extraction through the booking owner route |
| /api/tms/bookings/booking-instruction/ai-prompt | GET, PATCH | tms.booking | read/save the tenant prompt for BOOKING_INSTRUCTION extraction |
| /api/tms/bookings/form | POST, PATCH | tms.booking | booking popup form create/update/delete |
| /api/tms/bookings/{id} | GET, PATCH | tms.booking | booking detail/update flows |
| /api/tms/bookings/{id}/packing-list/email | POST | tms.booking | send packing list email to customer, inspector, or both with PACKING_LIST company-email recipients and split ZIP attachments |
| /api/tms/empty-plan/summary | GET | tms.booking | empty container booking planning read model |
| /api/tms/empty-plan/create | POST | tms.booking | create empty-container booking allocations from the empty-plan page |
| /api/tms/empty-plan/booking-inquiry-email | POST | tms.booking | send empty-plan booking-needed inquiry emails grouped by billing company after revalidating selected summary keys against the current empty-plan read model |
| /api/tms/carriers/{id} | GET | tms.carrier | carrier master row detail for popup edit flows |
| /api/tms/carriers/form | POST, PATCH | tms.carrier | carrier popup form create/update/delete |
| /api/tms/driver-logs/{id}/deliveries | GET | tms.delivery | delivery rows attached to a driver log |
| /api/tms/equipment-loads/{id}/deliveries | GET | tms.delivery | delivery rows attached to an equipment load |
| /api/tms/equipment-loads/{id}/status | PATCH, POST | tms.delivery | office-only equipment-load status update for Export Dispatch Drayage Queue Mark Empty / Mark Full actions; STATUS=FULL requires a current-booking-list RETURN_BOOKING_ID for the same customer and updates the equipment return-booking link in the same command |
| /api/tms/equipment-loads/{id}/return-booking-options | GET | tms.delivery | office-only return booking picker options for Export Dispatch Drayage Queue Mark Full, scoped to the current Export Dashboard booking list for the current container customer and promoting the current pickup booking when it is in that list |
| /api/tms/delivery-orders | GET | tms.delivery | delivery-order rows by booking id |
| /api/tms/companies/{id}/terminal-status | GET | tms.delivery | terminal flag check for delivery flows |
| /api/tms/deliveries/{id}/status | POST | tms.delivery | update delivery runtime status |
| /api/tms/deliveries/{id}/arrival-signal | POST | tms.delivery | driver near-yard / yard-entrance signal for pending arrival notification |
| /api/tms/deliveries/{id}/arrival-action | PATCH | tms.delivery | office/operation action that clears pending arrival notification |
| /api/tms/deliveries/{id}/location-ping | POST | tms.delivery | driver one-time current-location ping; creates DRIVER_LOCATION_PING operation event without background tracking |
| /api/tms/deliveries/{id}/parking-request | POST | tms.delivery | assigned-driver export-empty parking request, with office override allowed; sets T_DELIVERY.PARKING_STATUS='PARKING_REQUESTED' and request timestamp |
| /api/tms/deliveries/{id}/parking-assignment | POST, PATCH | tms.delivery | office-only parking assignment; accepts exact spots plus YMS area/stack-group/drop destinations, creates/updates the existing YMS yard queue for the delivery equipment, and stores assignment status/timestamp on T_DELIVERY |
| /api/tms/deliveries/{id}/parking-confirm | POST, PATCH | tms.delivery | assigned-driver parking confirmation, with office override allowed; accepts optional ACTUAL_TO for area/stack-group parking assignments, confirms the active claimed YMS queue when present, and stores confirmation status/timestamp on T_DELIVERY |
| /api/tms/deliveries/{id}/field | PATCH | tms.delivery | update allowed delivery operation fields without generic table input |
| /api/tms/equipment/{id}/field | PATCH | tms.delivery | update allowed equipment fields from driver operation |
| /api/tms/deliveries/{id}/driver-assignment | PATCH | tms.delivery | assign or cancel driver on a delivery |
| /api/tms/dispatch/export-pickup | POST | tms.delivery | create export pickup dispatch |
| /api/tms/dispatch/import-return | POST | tms.delivery | create import return dispatch |
| /api/tms/dispatch/delivery | POST | tms.delivery | create delivery dispatch |
| /api/tms/transloads/driver-contacted | PATCH | tms.transload | update driver contacted flag |
| /api/tms/transloads/dispatch | POST | tms.transload | dispatch staged plan to docked execution |
| /api/tms/transloads/cancel | POST | tms.transload | cancel active transload appointment/execution |
| /api/tms/transloads/no-show | POST | tms.transload | mark scheduled/pre-planned/arrived transload as no-show |
| /api/tms/transloads/scheduled-inquiry-email | POST | tms.transload | send scheduled-load inquiry emails grouped by customer for selected scheduled transload rows |
| /api/tms/transload-emails/reschedule-decision | GET | tms.transload | validate requested transload reschedule slot against active rules |
| /api/tms/transload-emails/approval-queue | GET | tms.transload | transload appointment email approval queue, including reviewed Shipper/Carrier/Equipment/Remark draft values; LIMIT is applied by email and all rows for included emails are returned; supports exact-link filters GMAIL_MESSAGE_ID, MAIL_MESSAGE_ID, and ITEM_ID |
| /api/tms/transload-emails/outbound-queue | GET | tms.transload | transload email follow-up/outbound queue |
| /api/tms/transload-emails/reschedule-apply | POST | tms.transload | apply approved reschedule email decision |
| /api/tms/transload-emails/approval-submit | POST | tms.transload | approve/reject/delete appointment email queue item; unmatched CREATE preserves reviewed Carrier/Shipper/Equipment Type+Number/Remark when present and keeps legacy fallback when absent; legacy manual outcome remains available for integrations |
| /api/tms/transload-emails/create-confirmation-reply | POST | tms.transload | send one same-thread create confirmation summary for multiple approved rows from one email |
| /api/tms/transload-emails/reject-request | POST | tms.transload | reject open rows from one appointment email as one request, then send one same-thread rejection reply after commit |
| /api/tms/transload-emails/rejection-reply | POST | tms.transload | send or retry one same-thread rejection reply for already rejected rows from one email |
| /api/tms/transload-emails/item-process | POST | tms.transload | process parsed appointment email item |
For POST /api/tms/transload-emails/approval-submit, reviewed-field parity applies only to unmatched CREATE
(ACTION_TYPE=CREATE, MATCHED_TRANSLOAD_ID=0). DRAFT.INITIAL_EQUIPMENT_TYPE accepts CONTAINER or TRAILER;
a positive DRAFT.SHIPPER_COMPANY_ID must resolve inside the active tenant. Invalid values return 400 before
appointment/order writes. Missing reviewed keys retain the legacy Carrier/Shipper/equipment/remark fallback, so this
change does not add required fields. RESCHEDULE, CANCEL, matched CREATE, provider reply behavior, MK and schema are
unchanged. Implementation status: COMPLETE / NOT_DEPLOYED.
| /api/tms/transloads/{id}/load-label | GET | tms.transload | load-label print data |
| /api/tms/transloads/{id}/load-label/warehouse-location | PATCH | tms.transload | update warehouse location from load-label print page |
| /api/tms/transload-planner/events | GET | tms.transload | transload calendar/planner events |
| /api/tms/transload-planner/events/{id} | PATCH | tms.transload | update transload planner appointment time |
| /api/tms/loading-planner | POST | tms.transload | create dock/loading planner row without generic table write |
| /api/tms/loading-planner/{id} | GET, PATCH, DELETE | tms.transload | read/update/delete dock/loading planner row with tenant ownership check; delete cancels related planner yard queues and returns active planning statuses to ARRIVED |
| /api/tms/transload-loaders/options | GET | tms.transload | forklift loader option list for planning and assignment boards; replaces deleted legacy forklift-driver master lookup |
| /api/tms/transloads/unloading-equipment/options | GET | tms.transload | bounded unloading-equipment autocomplete options; replaces deleted legacy unloading-equipment autocomplete flow |
| /api/tms/staff-time/current | GET | tms.transload | current staff clock state for inbound-loader and staff time controls, including the current open break/lunch state when a BREAK_IN has no paired BREAK_OUT; DAY_SECONDS and WEEK_SECONDS include paid 10MIN BREAK time and exclude LUNCH BREAK time |
| /api/tms/staff-time/event | POST | tms.transload | create self-service staff time event; active self-service events are clock in/out only |
| /api/tms/staff-time/timeline | GET | tms.transload | staff-time event timeline read model for /loader-timeline; returns an empty list if staff-time storage has not been deployed yet |
| /api/tms/staff-time/current-context | PATCH | tms.transload | update the current open clock-in WORK_CONTEXT for a staff member so planning auto-assignment can exclude clocked-in staff doing non-forklift work; managers may update other staff and users may update their own context |
| /api/tms/staff-time/manager-events | POST | tms.transload | manager-only clock or break/lunch correction create with required reason; break/lunch creates BREAK_IN and auto-creates BREAK_OUT after its duration elapses |
| /api/tms/staff-time/manager-events/{id} | PATCH, DELETE | tms.transload | manager-only clock or break/lunch correction update/delete with required reason |
| /api/tms/transload-appointment-blocks | GET, POST, DELETE | tms.transload | list/create/remove appointment time blocks |
| /api/tms/transload-timeblocks/status | GET | tms.transload | appointment timeblock occupied/reserved/blocked status with scheduled load display context |
| /api/tms/transload-timeblocks/options | GET | tms.transload | transload appointment timeblock options; replaces generic master-data lookup for TRANSLOAD_TIMEBLOCK |
| /api/oms/commercial-orders/options | GET | oms.commercial-order | commercial order editor options including company templates |
| /api/oms/commercial-orders | GET, POST | oms.commercial-order | commercial order list/create |
| /api/oms/commercial-orders/{id} | GET, PATCH, DELETE | oms.commercial-order | commercial order detail/update/delete |
| /api/oms/inbound-orders/options | GET | oms.inbound-order | inbound purchase order editor options |
| /api/oms/inbound-orders/commodity-rate-options | GET | oms.inbound-order | commodity/rate editor options with companies, commodities, and UOMs |
| /api/oms/inbound-orders/doortrade-packing-list/ai-extract | POST | oms.inbound-order | Gemini-backed DOORTRADE_PACKING_LIST extraction for inbound order line import |
| /api/oms/inbound-orders | GET, POST | oms.inbound-order | inbound purchase order list/create |
| /api/oms/inbound-orders/schedule | GET | oms.inbound-order | inbound purchase order schedule events |
| /api/oms/inbound-orders/calendar-events | GET | oms.inbound-order | inbound purchase order calendar events |
| /api/oms/inbound-orders/{id} | GET, PATCH, DELETE | oms.inbound-order | inbound purchase order detail/update/delete |
| /api/oms/inbound-orders/{id}/atomic-save | POST | oms.inbound-order | editor-only atomic header/item/delete Save |
| /api/oms/inbound-orders/{id}/complete-without-scale | POST | oms.inbound-order | complete inbound purchase without scale execution |
| /api/oms/inbound-orders/{id}/items | POST | oms.inbound-order | add inbound purchase order item |
| /api/oms/inbound-orders/{id}/items/{itemId} | PATCH, DELETE | oms.inbound-order | update/delete inbound purchase order item |
| /api/oms/customer-pos/by-load-numbers | POST | oms.inbound-order | customer PO lookup by load numbers |
| /api/oms/customer-pos | POST | oms.inbound-order | customer PO create with item rows |
| /api/oms/customer-pos/form | POST, PATCH | oms.inbound-order | customer PO popup form create/update/delete |
| /api/oms/customer-pos/{id} | GET | oms.inbound-order | customer PO row detail for popup edit flows |
| /api/oms/customer-pos/{id}/items | GET | oms.inbound-order | customer PO item rows with linked transload status |
| /api/oms/outbound-orders/options | GET | oms.outbound-order | outbound sales order editor options |
| /api/oms/outbound-orders | GET, POST | oms.outbound-order | outbound sales order list/create |
| /api/oms/outbound-orders/schedule | GET | oms.outbound-order | outbound sales order schedule events |
| /api/oms/outbound-orders/{id} | GET, PATCH, DELETE | oms.outbound-order | outbound sales order detail/update/delete |
| /api/oms/outbound-orders/{id}/items | POST | oms.outbound-order | add outbound sales order item |
| /api/oms/outbound-orders/{id}/items/{itemId} | PATCH, DELETE | oms.outbound-order | update/delete outbound sales order item |
| /api/oms/outbound-orders/{id}/costs | GET, POST | oms.outbound-order | outbound order cost detail/upsert |
| /api/oms/outbound-orders/{id}/costs/{transactionId} | DELETE | oms.outbound-order | delete outbound order cost transaction |
| /api/oms/export-brokerage/bookings/search | GET | oms.outbound-order + oms.inbound-order | bounded booking autocomplete for export brokerage workflow-selected bookings |
| /api/oms/export-brokerage/documents/ai-extract | POST | oms.outbound-order + oms.inbound-order | Gemini-backed EXPORT_BROKERAGE_DOCUMENT extraction for export brokerage job setup |
| /api/oms/export-brokerage/jobs | POST | oms.outbound-order + oms.inbound-order | one-step export brokerage job create; creates inbound purchase, inventory lots/transload context, outbound sales order, and outbound allocation without scale execution |
| /api/oms/export-brokerage/jobs/cancel | POST | oms.outbound-order + oms.inbound-order | cancel a one-step export brokerage job by INBOUND_ORDER_ID and OUTBOUND_ORDER_IDS; deletes the created inbound/outbound orders when no downstream scale, delivery, transload, ledger, or outside allocation activity exists |
| /api/oms/allocations/workbench | GET | oms.allocation | allocation workbench read model |
| /api/oms/allocations/target-shipments | GET | oms.allocation | target outbound shipment autocomplete |
| /api/oms/allocations/allocatable-lots/search | GET | oms.allocation | bounded allocatable inventory lot autocomplete for outbound allocation source selection |
| /api/oms/allocations/apply | POST | oms.allocation | apply staged inventory lots to outbound demand |
| /api/oms/trade-summary | GET | oms.trade-summary | trade summary list/read model |
| /api/oms/trade-summary/{equipmentId} | GET | oms.trade-summary | trade summary detail read model |
| /api/oms/deal-ledger | GET | oms.trade-summary | deal ledger alias for trade summary list |
| /api/oms/deal-ledger/{equipmentId} | GET | oms.trade-summary | deal ledger alias for trade summary detail |
| /api/wms/inbound/transloads/check-in-list | GET | wms.inbound | WMS-owned inbound check-in list |
| /api/wms/inbound/transloads/completed | GET | wms.inbound | WMS-owned completed inbound transload list |
| /api/wms/inbound/imports/transload | POST | wms.inbound | create transload from import equipment |
| /api/wms/inbound/imports/delivery-orders | POST | wms.inbound | create import delivery order group |
| /api/wms/inbound/import-delivery-orders/ai-extract | POST | wms.inbound | Gemini-backed IMPORT_DELIVERY_ORDER extraction through the WMS inbound owner route |
| /api/wms/inbound/import-delivery-orders/ai-prompt | GET, PATCH | wms.inbound | read/save the tenant prompt for IMPORT_DELIVERY_ORDER extraction |
| /api/wms/inventory/lots | GET | wms.inventory | inventory lot list |
| /api/wms/inventory/lots/{id} | GET, PATCH | wms.inventory | inventory lot detail/update |
| /api/wms/inventory/lots/{id}/adjust | POST | wms.inventory | manual inventory lot remaining-balance adjustment |
| /api/wms/inventory/warehouse-map/state | GET | wms.inventory | canonical read-only Warehouse Map grid, grid-owned cellType, and storage-cell inventory-lot occupancy model |
| /api/wms/inventory/warehouse-map/locations | GET | wms.inventory | active warehouse location master rows for shared callers |
| /api/wms/inventory/warehouse-map/location-options | GET | wms.inventory | active, unblocked warehouse location options for Loader/Inbound callers, including Firelane exceptions |
| /api/wms/inventory/report | GET | wms.inventory | inventory report read model |
| /api/wms/inventory/physical-report | GET | wms.inventory | Inventory Report Physical tab read model; returns previous finalized inventory lot snapshot and current saved or generated draft |
| /api/wms/inventory/physical-report/draft | POST | wms.inventory | save editable inventory lot snapshot rows for the Physical tab by company + period |
| /api/wms/inventory/physical-report/finalize | POST | wms.inventory | finalize the inventory lot snapshot as customer-reported for future previous/email reuse |
| /api/wms/storage/by-company | GET | wms.inventory | storage by company report |
| /api/wms/inventory/bale-adjustments | GET | wms.inventory | computed bale adjustment queue from completed transloads and inventory lot ledger state |
| /api/wms/inventory/bale-adjustments/apply | POST | wms.inventory | apply exact extra sources, atomically create-and-apply a manual extra source, apply source lots to created leftover loads, create leftover, or create/mark spare source lots with ledger rows |
| /api/wms/inventory/bale-reviews | GET | wms.inventory | Final Loading Review queue with server-derived Expected/Final/Difference, readiness and BAL TRK summary |
| /api/wms/inventory/bale-reviews/confirm | POST | wms.inventory | final confirm after source, leftover, and weight-review checks are satisfied |
| /api/wms/inventory/bale-reviews/apply-weight | POST | wms.inventory | ACTION=USE_INBOUND_WEIGHT; applies inbound final weight to the final weight using a stale-value guard |
| /api/wms/inventory/bale-reviews/reopen | POST | wms.inventory | reopens review status only; inventory ledger and lot balances remain unchanged |
| /api/wms/inventory/bale-sources/options | GET | wms.inventory | exact Spare-source autocomplete for an Extra adjustment target; returns load/reference, customer, commodity, location, and remaining balance |
| /api/wms/inventory/bale-sources | GET | wms.inventory | bale source pool read model from T_INVENTORY_LOT |
| /api/wms/inventory/bale-sources/manual | POST | wms.inventory | create manual source lot and LOT_CREATED ledger row |
| /api/wms/inventory/bale-sources/{lotUuid}/ledger | GET | wms.inventory | source ledger drawer data for a lot UUID |
| /api/wms/inventory/bale-sources/{lotUuid}/count-check | POST | wms.inventory | update remaining count/weight and insert COUNT_CHECK; CTC use requires Office, an active placed Spare lot, a reason, and a quantity not below reservation |
| /api/wms/inventory/bale-sources/{lotUuid}/void | POST | wms.inventory | insert REVERSAL ledger row and restore lot balance |
| /api/files | GET, POST, PATCH | none | shared file metadata lookup, registration, and bulk type/delete updates |
| /api/files/{id} | PATCH, DELETE | none | shared file metadata type/sequence update and delete with CLIENT_ID ownership check |
| /api/files/transaction-documents | POST | none | register uploaded AP transaction documents against multiple transactions |
| /api/files/media/upload | POST | none | physical media upload with hybrid EFS/S3 storage behavior |
| /api/files/media/download | POST | none | zip/download response for selected stored files |
| /api/files/media/datestamp | POST | none | add equipment-load photo datestamp image and register T_FILE metadata |
| /api/bms/scale-tickets | POST | bms.scale-ticket | create scale ticket with tenant ticket-number generation |
| /api/bms/scale-tickets/{id} | GET, PATCH, DELETE | bms.scale-ticket | scale ticket detail/update/delete |
| /api/bms/scale-tickets/closing | POST | bms.scale-ticket | create/update a closing scale ticket after validating the equipment-load/transload/commodity/ticket relation; axle values, times, and tractor number are client-authored, while load/customer/driver/commodity metadata is derived from the validated equipment/transload relation |
| /api/bms/scale-tickets/outbound-weight-apply | POST | bms.scale-ticket | apply outbound weight from scale ticket |
| /api/bms/transactions/{id} | GET | bms.transaction | transaction popup detail with transaction list rows |
| /api/bms/transactions/form | POST, PATCH | bms.transaction | transaction popup form create/update/delete |
| /api/bms/transactions/{source} | POST, DELETE | bms.transaction | create/delete source-owned trucking, transload, chassis, or scale-ticket transactions |
| /api/bms/transactions | DELETE | bms.transaction | delete selected transaction rows by transaction id |
| /api/bms/transactions/close | PATCH | bms.transaction | close selected transactions |
| /api/bms/transactions/chassis/bulk-input | POST | bms.transaction | create chassis transactions from bulk pasted container/rate input |
| /api/bms/transactions/apply-final-transload | POST | bms.transaction | apply final transload weight/quantity to equipment commodity rows |
| /api/bms/companies/{id}/billing-address | GET | bms.transaction | transaction popup billing address lookup |
| /api/bms/ar-billing/options | GET | bms.transaction | AR Billing companies, transaction types, presets, and QBO readiness |
| /api/bms/ar-billing/presets | GET, POST | bms.transaction | list/create AR Billing preview presets |
| /api/bms/ar-billing/presets/{uuid} | PATCH, DELETE | bms.transaction | update/delete AR Billing preview preset by UUID |
| /api/bms/ar-billing/rates | GET | bms.transaction | customer registered trucking/transload/chassis rate structures and prices for Billing Presets actual-rate review |
| /api/bms/ar-billing/rates/form | PATCH | bms.transaction | update the final trucking/transload/chassis price row surfaced in the Rate customer modal |
| /api/bms/ar-billing/workbench | GET | bms.transaction | paged booking/container AR Billing workbench rows |
| /api/bms/ar-billing/preview | POST | bms.transaction | generate editable charge-line preview without writing transactions |
| /api/bms/ar-billing/confirm | POST | bms.transaction | create/update container-scoped AR transactions from confirmed preview lines |
| /api/bms/ar-billing/qbo-sync | POST | bms.transaction | create QuickBooks Online invoices for confirmed container AR transactions |
| /api/bms/fuel/{id} | GET | bms.transaction | fuel row detail for popup edit fallback |
| /api/bms/fuel/form | POST, PATCH | bms.transaction | fuel popup form create/update/delete |
| /api/reports/inventory/monthly | GET | addon.reports | monthly inventory report read model |
| /api/reports/inventory/accumulative | GET | addon.reports | accumulative inventory report read model |
| /api/reports/mk/daily-commodity | GET | addon.reports | MK daily commodity report read model |
| /api/bms/reports/account-trucking | GET | addon.reports | account trucking report read model used by BMS table flows |
| /api/reports/fbol | GET | addon.reports | FBOL report read model |
| /api/addons/ai-verifications/{id} | GET | addon.reports | AI verification report lookup by delivery id |
Request Shapes¶
Conditional React API client¶
If P12 selects React, its client proposal must be re-reviewed against the current framework-independent API contract before implementation.
Example calls:
api.yms.yardMap.getState();
api.yms.yardMoves.preview(input);
api.tms.transloads.checkIn(id, input);
api.wms.inventory.listLots(query);
api.oms.outboundOrders.update(id, input);
The client contract does not accept TYPE, ACTION, or USERNAME.
Shared read/write¶
The shared query.php / post.php request shape was removed in #454. Do not add new callers or compatibility routes for this shape.
Direct module read¶
Legacy module-owned shell only; do not use for new React/API v2 callers.
GET /app/systems/<SYSTEM>/<module>/query.php
TYPE=<domain_type>
ACTION=<action_name>
DATA=<payload>
USERNAME=<optional>
Direct module write¶
Legacy module-owned shell only; do not use for new React/API v2 callers.
POST /app/systems/<SYSTEM>/<module>/post.php
TYPE=<domain_type>
ACTION=<action_name>
DATA=<payload>
USERNAME=<optional>
Response Envelope¶
Success¶
{
"Result": "SUCCESS",
"Value": {},
"Time": "YYYY-MM-DD HH:mm:ss",
"Debug": "",
"Query": "",
"ReqId": "..."
}
Error¶
{
"Result": "ERROR",
"Message": "visible error message",
"Value": "",
"Time": "YYYY-MM-DD HH:mm:ss",
"Debug": "",
"ReqId": "..."
}
Auth And Module Gate¶
- Auth helper:
endpointAssertAuthenticated(). - API v2 auth helper:
apiAssertAuthenticated(). - Page/module guard:
app/platform/tenant/module_guard.php. TYPE/ACTIONmodule key resolver:moduleGuardEndpointModuleKey().- API v2 module key source: route
moduleKey, notTYPE/ACTION. - Disabled module endpoint response: HTTP 403 + JSON error envelope.
- Super-admin impersonation checks the target tenant, not raw source session
CLIENT_ID.
Active Direct Endpoint Shells¶
| Module | Read | Write |
|---|---|---|
oms.commercial-order |
OMS/commercial-order/query.php |
OMS/commercial-order/post.php |
oms.outbound-order |
OMS/outbound-order/query.php |
OMS/outbound-order/post.php |
oms.allocation |
OMS/allocation/query.php |
OMS/allocation/post.php |
wms.inbound |
WMS/inbound/query.php |
WMS/inbound/post.php |
wms.inventory |
WMS/inventory/query.php |
WMS/inventory/post.php |
tms.transload |
TMS/transload/query.php |
none |
yms.yard-map |
YMS/yard-map/query.php |
none |
yms.yard-move |
YMS/yard-move/query.php |
YMS/yard-move/post.php |
yms.container-tracking |
YMS/container-tracking/query.php |
none |
yms.dock-scheduling |
YMS/dock-scheduling/query.php |
none |
yms.scale |
YMS/scale/query.php |
YMS/scale/post.php |
bms.rate |
BMS/rate/query.php |
BMS/rate/post.php |
bms.scale-ticket |
none | BMS/scale-ticket/post.php |
bms.invoice |
BMS/invoice/query.php |
none |
Key TYPE Families¶
| Family | Owner |
|---|---|
MENU |
platform.menu; active menu/admin callers use /api/platform/menu/* |
ACCOUNT |
platform.auth; active password caller uses /api/platform/account/password |
SUPER_ADMIN |
platform.audit; active admin-console callers use /api/platform/admin/*; tenant onboarding uses POST /api/platform/admin/clients with ONBOARDING_ENABLED=1 or POST /api/platform/admin/tenants/{clientId}/onboarding |
TRANSLOAD, TRANSLOAD_PLANNER, TRANSLOAD_TIMEBLOCK_STATUS |
tms.transload |
TRANSLOAD_APPOINTMENT_BLOCK |
tms.transload |
TRANSLOAD_EMAIL_* |
tms.transload, email add-on bridge |
MOBILE_DRIVER, MOBILE_CONTAINER, delivery lists |
tms.delivery; driver-operation callers now use API v2 delivery routes |
YARD_LOCATION, YARD_DISPATCH_QUEUE, RESET_YARD |
yms.yard-move |
YARD_MAP, YARD_OCCUPANCY |
yms.yard-map |
YMS_SCALE |
yms.scale |
SCALE_TICKET, CLOSING_SCALE_TICKET, OUTBOUND_WEIGHT_APPLY |
bms.scale-ticket |
MK_COMMODITY_RATE, MK_TRUCKING_RATE, MK_FREIGHT_RATE |
bms.rate |
MK_PURCHASE_ORDER |
oms.inbound-order |
MK_SALES_ORDER |
oms.outbound-order |
MK_ALLOCATION_* |
oms.allocation |
MK_INVENTORY, MK_INVENTORY_LOT |
wms.inventory |
MK_BOOKING, BOOKING_* |
tms.booking |
COMMERCIAL_ORDER |
oms.commercial-order |
TRADE_SUMMARY, DEAL_LEDGER |
oms.trade-summary |
FILE |
shared file helper; active metadata callers use /api/files* |
| report add-ons | addon.reports; active inventory/MK/account-trucking/FBOL/AI-verification report callers use /api/reports*, /api/bms/reports/account-trucking, or /api/addons/ai-verifications/*; INGATE_TICKET extraction uses /api/addons/ai-verifications/ingate-ticket/ai-extract |
TELEGRAM |
addon.telegram; active shared send callers use POST /api/addons/telegram/messages |
Tenant Onboarding¶
- Super-admin tenant create can run onboarding in the same transaction by posting
ONBOARDING_ENABLED=1toPOST /api/platform/admin/clients. - Super-admin can also apply onboarding defaults to an explicitly selected tenant with
POST /api/platform/admin/tenants/{clientId}/onboarding. - Onboarding seeds default
T_ROLErows, an initial adminT_USER, enabledT_TENANT_MODULErows by package tier, requiredT_TENANT_CONFIGdefaults, and a baselineT_MENUtree. - Valid package tiers are
starter,professional, andenterprise. - Current schema names are
T_MODULE.MODULE_KEY,T_TENANT_MODULE.IS_ENABLED, andT_TENANT_CONFIG.CONFIG_KEY/CONFIG_VALUE. - Production tenant onboarding writes require explicit user confirmation. Local write verification must follow the DB target confirmation in
.agents/rules/DEV_ENV.md.
Important Contracts¶
File metadata¶
- Physical uploads use
POST /api/files/media/upload; the legacyapp/controllers/media.php ACTION=UPLOADcontroller remains compatibility-only. - Zip downloads use
POST /api/files/media/download. - Equipment-load photo datestamps use
POST /api/files/media/datestamp. - File metadata registration uses
POST /api/files; request bodies useFILE_TYPE, not legacyTYPE. - File URL lookup uses
GET /api/files?TABLE_NAME=...&TABLE_ID=.... - Multi-transaction AP document registration uses
POST /api/files/transaction-documentswithTABLE_NAME=T_TRANSACTION,TABLE_IDS=[...],FILE_TYPE=AP_INVOICE|AP_PAYMENT, andFILES=[...]. - Transaction document registration stores one
T_FILEmetadata row per transaction and file so a shared Pierpass/CTF payment document can be found from every paid transaction. - File metadata update/delete routes verify
T_FILE.CLIENT_IDownership before changing or deleting rows.
Commercial order¶
- Active API v2 routes are
GET/POST /api/oms/commercial-orders,GET/PATCH/DELETE /api/oms/commercial-orders/{id}, andGET /api/oms/commercial-orders/options. - Legacy read options remain available during cutover as
TYPE=COMMERCIAL_ORDER ACTION=OPTIONS. OPTIONSreturnsCOMPANY_TEMPLATESkeyed byT_COMPANY.IDwhen tenant configCOMMERCIAL_ORDER_COMPANY_TEMPLATESis present.- Template fields are optional and prefill-only; create/update payloads still persist explicit form values.
- Supported template keys include existing
T_COMMERCIAL_ORDERfields plusORDER_NUMBER_PATTERN; signature presets may useSELLER_SIGNATUREandBUYER_SIGNATURE. SHIPPING_PERIODis the user-facingDue Date; create/update payloads store date-onlyYYYY-MM-DDvalues.ORDER_NUMBER_PATTERNsupports[yyyymmdd],[yymmdd],[yyyy],[mm],[dd], and[material].- Current Commercial Order mutations run in one DB transaction. Create requires a same-tenant counterparty and at least one positive-quantity valid-UOM line; an unchanged preview number is reserved under a tenant/type/date lock.
- The current UI stores an optional Purchase-to-Sales relation from the Purchase editor. The backend accepts only a same-tenant, non-self, opposite-type active row but does not enforce status or cardinality.
- The current implementation classifies pre-execution by active
T_LOAD.COMMERCIAL_ORDER_IDcount: count zero lets PATCH replace the complete item set; positive count skips item replacement and rejects type change and DELETE while other submitted header fields remain editable.T_LOAD_ITEM.COMMERCIAL_ORDER_ITEM_ID-only execution is not covered by that guard and must not be inferred safe from an empty Detail execution list. - Commercial
STATUSacceptsDRAFT,OPEN,PARTIAL,FULFILLED, andCANCELLED; these are not automatically derived from execution state. - The shared legacy-compatible body adapter currently uppercases non-signature scalar values recursively. Callers must verify exact detail read-back; changing this compatibility behavior requires a separate scoped packet.
OMS purchase/sales orders¶
-
Canonical operator behavior and recovery are documented separately in
docs/processes/MK_INBOUND_PURCHASE_WORKFLOW.mdanddocs/processes/MK_OUTBOUND_SALES_WORKFLOW.md; API route existence does not imply a unified completion state or permission to mutate progressed data. -
Inbound purchase order API v2 routes are
GET/POST /api/oms/inbound-orders,GET/PATCH/DELETE /api/oms/inbound-orders/{id},POST /api/oms/inbound-orders/{id}/atomic-save,POST /api/oms/inbound-orders/{id}/complete-without-scale,POST /api/oms/inbound-orders/{id}/items,PATCH/DELETE /api/oms/inbound-orders/{id}/items/{itemId},GET /api/oms/inbound-orders/options,GET /api/oms/inbound-orders/commodity-rate-options,GET /api/oms/inbound-orders/schedule,GET /api/oms/inbound-orders/calendar-events, andPOST /api/oms/inbound-orders/doortrade-packing-list/ai-extract. POST /api/oms/inbound-orders/{id}/atomic-saveis used only by the shared inbound editor's existing-order Save. Its body is{ HEADER, ITEMS, DELETED_ITEM_IDS }; the server validates that every existing/deleted item belongs to the same tenant/order, applies header, deletes, item updates/inserts, and final state synchronization in one transaction. Any rejected child rolls back the complete request. Existing header/item endpoints remain available for their current callers.- Outbound sales order API v2 routes are
GET/POST /api/oms/outbound-orders,GET/PATCH/DELETE /api/oms/outbound-orders/{id},POST /api/oms/outbound-orders/{id}/items,PATCH/DELETE /api/oms/outbound-orders/{id}/items/{itemId},GET /api/oms/outbound-orders/options, andGET /api/oms/outbound-orders/schedule. - Export brokerage booking autocomplete is
GET /api/oms/export-brokerage/bookings/search; it returns bounded existing booking suggestions under the sameoms.outbound-orderplusoms.inbound-orderand export brokerage workflow gates as the page. Export brokerage document extraction isPOST /api/oms/export-brokerage/documents/ai-extract; document booking numbers are returned asDOCUMENT_BOOKING_NUMBERhints only. One-step create isPOST /api/oms/export-brokerage/jobs; ocean-freight payloads must send a selected existingBOOKING_IDand must not rely on PDF-extracted booking text to create a booking. Export brokerage create uses one job-level time forIN_TIME,OUT_TIME, andINGATE_TIME; commodity line weight is normalized asGROSS_WEIGHT = NET_WEIGHTwithTARE_WEIGHT = 0; rates must be positive; and rates and UOM must be identical for the sameCOMMODITY_IDacross containers. These routes requireoms.outbound-orderplusoms.inbound-orderand the export brokerage workflow tenant config. Create reuses the inbound/outbound OMS write helpers in one API transaction and does not create or require a scale ticket. Cancel isPOST /api/oms/export-brokerage/jobs/cancelwithINBOUND_ORDER_IDandOUTBOUND_ORDER_IDS; it rejects orders with downstream scale, delivery, transload, inventory ledger, cost, or outside allocation activity. - Inbound purchase and outbound sales create/header update bodies may omit
COMMERCIAL_ORDER_ID; blank or non-positive values are stored as-1until a commercial PO/SO is available. Positive inbound values must validate asORDER_TYPE='PURCHASE', and positive outbound values must validate asORDER_TYPE='SALES'.POST /api/yms/scale/purchase-inbound/walk-inalso creates PO-less walk-in shells, but it must ignore generic order-create fields and server-normalize the shell to aLOCAL/OPENwalk-in with scheduled items. List/detail responses includeCOMMERCIAL_ORDER_NUMBERandCOMMERCIAL_ORDER_REFERENCE_NUMBERfor PO/SO display. - Inbound purchase create/header update bodies may include
OPERATIONAL_STATUS(SCHEDULED,UNLOADED,TRANSLOADED;MIXEDis response-only/no bulk update) andAPPLY_OPERATIONAL_STATUS=1to apply the status to purchase items. When a non-emptyOUT_TIMEis newly entered without a meaningful status override, the write path treats the order asUNLOADED; either path can synchronize the transload and materialize an inventory lot outside explicit Scale/No-scale finalize. This is current behavior with an unapproved business-policy boundary, not an implicit completion recommendation. POST /api/oms/inbound-orders/{id}/complete-without-scaleacceptsOUT_TIMEandEXECUTION_BRANCH(WAREHOUSE_ONLY,DIRECT_OUTBOUND,MIXED) for brokerage/no-scale purchase completion. It only accepts scheduled inbound purchase orders withORDER_TYPE='OCEAN_FREIGHT', rejects cancelled, progressed/completed, and scale check-in-linked orders, treats existing purchase item input as the actual basis, sets purchase items toUNLOADED, syncsT_INVENTORY_LOT, and updates the purchase transload without creating a scale ticket.- The three inbound execution-branch values produce the same durable received order/item/transload/lot state. Direct/Mixed only return an Allocation Workbench URL; the selection is not persisted and does not create an allocation.
- Current source-transload inventory materialization requires exactly one active purchase item. Scale finalize can calculate multi-line weight parts, but the following exact transload-to-lot sync rejects more than one item and rolls the request back; multi-line receipt completion is not a supported/proven contract.
- Normal inbound create uses submitted
NET_WEIGHT, falling back toQUANTITYwhen omitted; only physical scale finalize redistributes measured gross/tare/net across lines. Callers must not assume a universal backend Gross-minus-Tare derivation. - Direct outbound create/add-item remains
UNMAPPEDand does not writeT_LOAD_ALLOCATIONor reduce a lot. OutboundOPERATIONAL_STATUS,READINESS, and Schedule rows are derived read projections, not completion commands. - The current Outbound editor sends Ocean create/update compatibility flags that allow a missing Booking and an unbooked or absent equipment bridge. An Ocean header can therefore save without Booking/Container/Size; this is an incomplete current state, not a server-enforced required-field contract.
- Positive Outbound Booking and party IDs do not have complete same-tenant active-row validation in the header write path; commodity ID/name direct-input validation also requires negative fixtures. Do not treat a successful header write as tenant-reference integrity evidence.
- Outbound create/update synchronizes the optional Booking reverse reference plus equipment/container, equipment-load, commodity-summary, and scale-ticket bridges. Allocation, Booking lifecycle, Packing, Scale execution, Delivery, and Cost remain separately owned effects.
- Outbound cost API v2 routes are
GET/POST /api/oms/outbound-orders/{id}/costsandDELETE /api/oms/outbound-orders/{id}/costs/{transactionId}. - Shared MK inbound/outbound order editors use domain API v2 routes for order options, detail, header writes, item writes, outbound cost writes, and commodity-rate options. File, delivery, and transload helper calls remain with their owning tasks until migrated.
- Direct inbound/outbound order creates with blank
ORDER_NUMBERreserve tenant/date-scoped numbers asPOYYYYMMDD-###andSOYYYYMMDD-###.
Allocation workbench¶
- API v2 routes are
GET /api/oms/allocations/workbench,GET /api/oms/allocations/target-shipments,GET /api/oms/allocations/allocatable-lots/search, andPOST /api/oms/allocations/apply. POST /api/oms/allocations/applyis the only allocation apply write route; callers must not useMK_SALES_ORDER ACTION=APPLY_WORKBENCH.- Target shipments must have an active execution container with
CONTAINER_NUMBERandSIZE; workbench reads must not surface no-container targets, and apply writes must reject them. - Lot rows expose inventory visibility fields such as
STOCK_BUCKET,STOCK_SOURCE_LABEL,SOURCE_ITEM_STATUS,IS_STALE_PARTIAL,AGE_DAYS, andVISIBILITY_NOTES. - Warehouse inventory summary rows expose lot counts, partial/stale partial counts, received date range, and source item statuses.
- Apply writes
T_LOAD_ALLOCATIONthrough the OMS allocation handler and must remain inside a transaction with sync task flushing.
Trade summary / deal ledger¶
oms.trade-summaryowns the trade summary and deal ledger read models, even though the current page lives underfrontend/pages/system/BMS/reports/.- API v2 routes are
GET /api/oms/trade-summary,GET /api/oms/trade-summary/{equipmentId},GET /api/oms/deal-ledger, andGET /api/oms/deal-ledger/{equipmentId}. - These routes are read-only and must preserve the trade-summary response contract. Implementations may use the optimized base-table read model plus targeted
T_TRANSACTION/T_TRANSACTION_LISTAP/AR/cost totals instead of materializingV_TRADE_SUMMARY.
WMS inbound / inventory¶
- WMS inbound API v2 routes are
GET /api/wms/inbound/transloads/check-in-list,GET /api/wms/inbound/transloads/completed,POST /api/wms/inbound/imports/transload,POST /api/wms/inbound/imports/delivery-orders,POST /api/wms/inbound/import-delivery-orders/ai-extract, andGET/PATCH /api/wms/inbound/import-delivery-orders/ai-prompt. IMPORT_DELIVERY_ORDERAI extraction and prompt editing are WMS inbound-owned; callers should useKJ.api.ai()/KJ.api.aiPrompt()so the central client can route to the owner endpoint.- WMS inventory API v2 routes are
GET /api/wms/inventory/lots,GET/PATCH /api/wms/inventory/lots/{id},POST /api/wms/inventory/lots/{id}/adjust,GET /api/wms/inventory/reload-source-lots,GET /api/wms/inventory/warehouse-map/state,GET /api/wms/inventory/warehouse-map/locations,GET /api/wms/inventory/warehouse-map/location-options,GET /api/wms/inventory/report,GET /api/wms/inventory/physical-report,POST /api/wms/inventory/physical-report/draft,POST /api/wms/inventory/physical-report/finalize, andGET /api/wms/storage/by-company. - Bale adjustment API v2 routes are
GET /api/wms/inventory/bale-adjustments,POST /api/wms/inventory/bale-adjustments/apply,GET /api/wms/inventory/bale-reviews,POST /api/wms/inventory/bale-reviews/confirm,POST /api/wms/inventory/bale-reviews/apply-weight,POST /api/wms/inventory/bale-reviews/reopen,GET /api/wms/inventory/bale-sources/options,GET /api/wms/inventory/bale-sources,POST /api/wms/inventory/bale-sources/manual,GET /api/wms/inventory/bale-sources/{lotUuid}/ledger,POST /api/wms/inventory/bale-sources/{lotUuid}/count-check, andPOST /api/wms/inventory/bale-sources/{lotUuid}/void. - Inventory lot writes preserve the existing transaction path and update
T_INVENTORY_LOTthrough the WMS inventory handler. T_INVENTORY_LOTis the WMS inventory source of truth; tenant-scoped reads and writes must includeCLIENT_ID.- Bale adjustment responses expose UUIDs through explicit string aliases (
LOT_UUID,LEDGER_UUID,SOURCE_TRANSLOAD_UUID,RELATED_TRANSLOAD_UUID,RELATED_ALLOCATION_UUID) and must not expose raw binaryUUID. - Bale adjustment queue state is computed from completed
T_TRANSLOADrows, final count/weight readiness, source balance, andT_INVENTORY_LOT_LEDGER; v1 has no persistent adjustment queue table. - Bale adjustment write routes run inside transactions. Extra applies decrement source lot remaining balance and insert
EXTRA_APPLIED; reload completion decrements the selected active WMS source lot and insertsRELOAD_APPLIED; created-leftover-load apply decrements selected source lots and insertsLEFTOVER_LOAD_APPLIED; leftover/spare/manual source creation inserts or marksT_INVENTORY_LOTand inserts a creation ledger row; count check insertsCOUNT_CHECK; void never deletes original history and instead insertsREVERSAL. Warehouse Map itself is read-only after Task #1339. - Bale adjustment writes reject missing required UUID aliases, already-applied transload adjustments, non-spare
SPARE_CREATErequests, and extra/leftover/spare source quantities or weights that do not match the completed transload variance.
BMS rate / scale-ticket / invoice / transaction¶
- BMS rate API v2 routes are
GET /api/bms/rates/{commodities|trucking|freight}/options,GET/POST /api/bms/rates/{commodities|trucking|freight},PATCH/DELETE /api/bms/rates/{commodities|trucking|freight}/{id},GET /api/bms/rates/form-row?table=<table>&id=<id>for legacy popup edit hydration, andPOST/PATCH /api/bms/rates/formfor legacy popup rate-table creates/updates/deletes. - Rate lookup dependencies use
GET /api/bms/rates/trucking/lookup,GET /api/bms/rates/chassis/by-equipment-load, andGET /api/bms/rates/chassis/by-company. - BMS scale-ticket API v2 routes are
GET /api/bms/scale-tickets/history?TICKET_NUMBER=TYYYYMMDD-NNNNfor the tenant-scoped, date-bounded axle change history;POST /api/bms/scale-tickets;GET/PATCH/DELETE /api/bms/scale-tickets/{id};POST /api/bms/scale-tickets/closing; andPOST /api/bms/scale-tickets/outbound-weight-apply. The history route returns only scale-ticket axle/timestamp fields from successful same-day JSONL create/update records, never the raw log payload. - BMS invoice read API v2 routes are
GET /api/bms/invoices/local-purchaseandGET /api/bms/transaction-documents/{id}. Print pages may keep server-rendered PHP helpers, but client/API contracts must not reintroduceBMS_LOCAL_*legacy requests. - BMS transaction API v2 routes are
GET /api/bms/transactions/{id},POST/PATCH /api/bms/transactions/form,POST/DELETE /api/bms/transactions/{trucking|transload|chassis|scale-ticket},DELETE /api/bms/transactions,PATCH /api/bms/transactions/close,POST /api/bms/transactions/chassis/bulk-input, andPOST /api/bms/transactions/apply-final-transload. - AR Billing API v2 routes under
/api/bms/ar-billing/*use UUID request/response identifiers for presets, bookings, containers, transaction rows, and transaction lines.GET /api/bms/ar-billing/workbenchacceptsDATE_FROM,DATE_TO,BILLING_COMPANY_UUID,BOOKING_NUMBER,CONTAINER_NUMBER,STATUS, and the kj-table paging parametersjtStartIndex/jtPageSize, while legacyKEYWORDremains a combined booking/container fallback. The response returns pageditemsplustotal,page,pageSize, andstartIndex, and each row includes booking, equipment, customer, existing source AR amount or suggested AR amount, invoice/date/check/payment/status/QBO, and charge-source context for the AR Billing container table. Preview routes must not createT_TRANSACTION; confirm must reject containers that already have source AR transactions or charges for multiple billing customers, and confirmed container invoices write oneT_TRANSACTIONheader plus multipleT_TRANSACTION_LISTrows. - Exact legacy
MK_BILLING_PURCHASE_LIST,MK_BILLING_SALES_LIST, andMK_BILLING_REPORTcallers/handlers were not found in the 2026-06-27 active scan outside the module guard prefix. Do not add/api/bms/billing/*compatibility routes for those names; future P&L or billing report work should use a named report-owned API v2 route. - Transaction popup billing address lookup uses
GET /api/bms/companies/{id}/billing-address; callers must not reintroduceBILLING_ADDRESS_BY_COMPANY_ID. GET /api/bms/reports/trucking-summaryandGET /api/bms/reports/trucking-summary/driver-transactionsown the trucking summary report reads.POST /api/bms/reports/trucking-summary/refresh-ap-ratesrecalculates zeroT_DELIVERY.AP_TRUCKING_RATEvalues with no AP transaction for one driver/date range by reusing the trucking-rate lookup rules. This is BMS/report boundary work and no longer uses the shared legacy query contract.- BMS rate, scale-ticket, invoice read, transaction action, and trucking summary active callers use API v2 request envelopes, not
TYPE/ACTION/USERNAME.
Booking¶
- MK booking editor persists
PICKUP_TERMINAL_ID,RETURN_TERMINAL_ID,PORT_OF_LOADING,PORT_OF_DISCHARGE,MINIMUM_WEIGHT, andMAXIMUM_WEIGHTonT_BOOKING. GET /api/tms/bookings/searchreturns boundedsuggestionsanditemsfor booking autocomplete, including booking number, shipping line, vessel, cutoff/SI cutoff, POL/POD, and 20S/40S/40H/40F/45H quantity columns.GET /api/tms/bookings/drayage-empty-optionsreturns bounded current Export Dashboard export-truckingbooking options with booking, quantity, billing company, and terminal ids for Export Dispatch Drayage Queue empty creation. Optionalfrom/toquery params apply the sameCUTOFFdate window used by the dashboard booking list; Export Dispatch passesfrom=todayby default.- MK booking create/update requires at least one shipper company in
SHIPPER_COMPANY_ID_LIST; the primarySHIPPER_COMPANY_IDmirrors the first selected company. - Booking confirmation print reads terminal display names from
T_COMPANYand prints POL/POD/weight values from saved booking data with visible-fallbacks for blanks. tms.bookingownsMK_BOOKING,MK_BOOKING_*, booking list/detail/options, packing list reads/files/save/email, booking loading options, duplicate reference checks, weight requirement checks, clone booking, empty-plan summary/create/booking inquiry email, and export-container revert routes.- API v2 routes:
GET /api/tms/bookingsPOST /api/tms/bookingsPOST /api/tms/bookings/booking-instruction/ai-extractGET/PATCH /api/tms/bookings/booking-instruction/ai-promptPOST/PATCH /api/tms/bookings/formGET /api/tms/bookings/{id}PATCH /api/tms/bookings/{id}POST /api/tms/bookings/{id}/cloneGET /api/tms/bookings/{id}/containersGET /api/tms/bookings/{id}/packing-list- Optional query parameter
EQUIPMENT_LOAD_ID/equipmentLoadIdfilters the MK packing list to one container. When omitted for MK, the packing list returns all valid linked booking containers.
- Optional query parameter
GET /api/tms/bookings/{id}/packing-list/filesPOST /api/tms/bookings/{id}/packing-list/emailPATCH /api/tms/bookings/{id}/packing-list/equipment-loadsPATCH /api/tms/bookings/{id}/packing-list/rates- Updates packing-list sales order item
RATE. The displayed invoice weight unit is a report rendering choice and is not persisted toT_LOAD_ITEM.UOM; callers that let users edit rates in a temporary display UOM must convert the submittedRATEback to the stored order-item billing UOM basis.
- Updates packing-list sales order item
GET /api/tms/bookings/optionsGET /api/tms/bookings/drayage-empty-optionsGET /api/tms/bookings/loading-optionsGET /api/tms/bookings/weight-requirementPOST /api/tms/bookings/duplicate-referenceGET /api/tms/empty-plan/summaryPOST /api/tms/empty-plan/createPOST /api/tms/empty-plan/booking-inquiry-emailPOST /api/tms/export-containers/revert
Carrier¶
tms.carrierowns carrier master lookup/export routes used by TMS appointment, inbound planning, popup, and table export flows.GET /api/tms/carriers/by-phonelooks up carrier master rows by phone number.GET /api/tms/carriers/{id}andPOST/PATCH /api/tms/carriers/formown carrier popup detail and form writes.POST /api/tms/carriers/export-masterreturns the export list and marks exported carrier master rows through the existing helper, so treat it as a write route.
Customer PO bridge¶
POST /api/oms/customer-pos/by-load-numbersis the API v2 bridge for popup load-number to customer-PO lookup.GET /api/oms/customer-pos/{id}and/itemsare the API v2 bridge for customer-PO popup edit reads.POST /api/oms/customer-posowns customer-PO popup create with item rows;POST/PATCH /api/oms/customer-pos/formowns scoped form updates/deletes.- Ownership remains
oms.inbound-order; booking/transload callers must not call sharedquery.phpforGET_CUSTOMER_PO_BY_LOAD_NUMBERS.
Inbound planning¶
- Read board:
GET /api/tms/transloads/planning-board. - Load schedule AI extraction:
POST /api/tms/transloads/load-schedule/ai-extract; prompt read/save:GET/PATCH /api/tms/transloads/load-schedule/ai-prompt. - Export transload schedule target extraction:
POST /api/tms/transloads/export-schedule/ai-extract; the response has no availability or write authority. - Check-in:
POST /api/tms/transloads/check-in. - Preview:
POST/PATCH /api/tms/transloads/plan-preview. - Apply plan:
POST/PATCH /api/tms/transloads/plan-apply. - Confirm:
POST/PATCH /api/tms/transloads/assign-submit. - Planner form/event writes:
POST/PATCH /api/tms/loading-planner/form,PATCH /api/tms/loading-planner/{id}, andPATCH /api/tms/transload-planner/events/{id}. - Runtime:
/api/tms/transloads/dispatch,/cancel,/no-show,/confirm-plan,/plan,/mobile-check-in,/dock-in,/stage,/start-*,/complete-*, and/undo. - Loader work queue:
GET/POST /api/tms/transloads/work-assignments; Loader-onlyGET /work-assignments/currentconceals scheduled-assignment detail untilPOST /work-assignments/{id}/start;POST /complete,/advance-clock-out, and/clock-outretain the existingT_LOADING_PLANNERand staff-time event authority.
Email reschedule¶
- Read decision:
GET /api/tms/transload-emails/reschedule-decision. - Write apply:
POST /api/tms/transload-emails/reschedule-apply. - Allowed source statuses:
SCHEDULED,PRE_PLANNED. - Possible decisions:
EXACT_AVAILABLE,NEXT_AVAILABLE,MANUAL_CONTACT,NO_CHANGE.
Menu management¶
- Menu management uses API v2 routes under
/api/platform/menu/*. - Menu reads:
GET /api/platform/menu/tree,GET /api/platform/menu/roles,GET /api/platform/module-pages. - Menu writes:
POST /api/platform/menu/items,PATCH/DELETE /api/platform/menu/items/{id},PATCH /api/platform/menu/tree, andPATCH /api/platform/menu/roles/{id}/default-menu. - Menu writes clear
KJ_MENU_CACHEafter a successful commit.
AI extraction¶
- Legacy compatibility endpoint:
app/controllers/chatgpt.php. - Active browser AI callers use
KJ.api.ai()andKJ.api.aiPrompt()throughpublic/assets/vendor/kj/kj.js; direct seal-photo OCR callers require theCONTAINER_SEAL_PHOTOowner route. Unsupported browser task or prompt names fail visibly and do not callchatgpt.php. - Owner API v2 routes are active for all browser extraction tasks:
IMPORT_DELIVERY_ORDER,LOAD_SCHEDULE,BOOKING_INSTRUCTION,DOORTRADE_PACKING_LIST,EXPORT_BROKERAGE_DOCUMENT,INGATE_TICKET, andCONTAINER_SEAL_PHOTO. chatgpt.phpremains a compatibility surface for direct legacy/external AI callers and tenant prompt actions not yet exposed through owner prompt routes. Delete it only after the controller-specific source inventory and runtime tests confirm active browser/API flows use owner API v2 routes; direct external legacy usage would receive 404 by design after deletion.APPOINTMENT_ACTION_PLANis registered inAiTaskRegistry, but transload appointment email intake callsTransloadAppointmentActionAgentdirectly rather than routing throughchatgpt.php.GET_PROMPTandSAVE_PROMPTremain supported controller actions for direct legacy/external prompt editing where no owner prompt route exists; browser prompt editing must use owner GET/PATCH prompt endpoints.- Preferred request: multipart form-data with a file.
- JSON request remains supported for existing callers.
- Env vars:
GEMINI_KEY, fallbackGEMINI_API_KEY. - Prompt overrides live in
media/ai-prompts/<TASK_NAME>.txt.
Naming Rules¶
- Keep uppercase
TYPEandACTIONvalues. - New direct endpoints should keep existing envelopes until all callers are migrated.
- Do not introduce compatibility dispatchers or pass-through wrapper functions.
- Add a module guard mapping when adding a new endpoint or
TYPE. - Do not use legacy naming rules as precedent for API v2 routes; API v2 routes must use explicit domain/module paths.
Migration Completion Criteria¶
Local TMS Assignment Work candidate¶
- API v2 routes under
/api/tms/transloads/assignment-workprovide manager batch create/list/edit/cancel/Telegram retry and Loader concealed-current/start/complete behavior. - Started Clock Out adds Loader-only
cleaning-complete,final-break, andclock-outactions; general/api/tms/staff-time/eventClock Out rejects while that workflow is Started. final-breakis available only for a Started Clock Out assignment withfinalBreakRequired=true; the server enforces cleaning completion, one linkedBREAK_IN, and a full 10 server minutes before workflow Clock Out creates the linkedBREAK_OUT.-
Responses retain standard v2 envelopes. Local assignment commit is independent from Telegram or QuickBooks provider outcome; linked Final Break
BREAK_OUTsuppresses only the regular-work QuickBooks resume path. -
Frontend caller uses the module direct endpoint.
- Shared controller route remains removed; do not restore it for compatibility.
- Module gate behavior matches shared endpoint behavior.
- Error envelope is visible to the user.
- Tests or smoke checks cover both enabled and disabled module paths.
- For API v2 cutover, all active
TYPE/ACTIONcallers must be migrated, deleted, or explicitly deferred in.agents/rules/API_V2_CONTRACT_INVENTORY.md.
---¶
Source:
.agents/rules/API_CONTRACTS.md— ctc repository · This page is an English translation of the source document. Identifiers, file paths and code symbols are unchanged.