Skip to content
English
  • There are no suggestions because the search field is empty.

Known Limitations and Security Notes (Staff Only)

Staff-only roundup of known Tai TMS limitations, edge cases, and security caveats so support and engineering know where to be careful. Never share.

This staff-only article is a consolidated reference to known limitations, edge cases, and security caveats across the Tai TMS, so support and engineering staff know what to expect and where to be careful. It must never be shared with customers.

Overview

Every system has rough edges: behaviors that are intentional trade-offs, known review items, or places where the current implementation differs from what someone might assume. This article gathers those in one place for internal staff. Each item below states what it means and the practical impact so you can set expectations, troubleshoot faster, and avoid drawing the wrong conclusion when something behaves unexpectedly. This is internal-only context. None of it should be surfaced to customers.

How it works

The items are grouped loosely by area: internal API and access, external and public interfaces, carrier integrations, shipment locations, background processing, accounting sync, reference numbers, and data. Each is a short, self-contained note describing the limitation and who or what it affects.

Business rules & limits

Access and internal API caveats

  • Some internal endpoints use an authorization marker that has no effect there. A number of internal API endpoints (11 controllers at the time of this review) are marked with an access restriction that belongs to a different part of the framework than the one those endpoints actually run in, so the marker does not take effect. What it means: those endpoints are not actually enforcing the intended role restriction at the framework level. Where the controller also carries a general "any signed-in user" restriction, the named role is simply not enforced; where it carries nothing else, the endpoint is effectively unauthenticated. Impact: this is a known review item; do not assume an endpoint is protected just because it appears to carry a restriction, and verify before relying on it.

  • Access is opt-in, not deny-by-default, on the internal API. Protection on internal endpoints is applied per endpoint rather than being on by default. What it means: an endpoint that was not explicitly given an access restriction is reachable by any caller who can reach the application. About 49 of the roughly 294 internal API controllers carry no authorization marker at all. Impact: new endpoints do not inherit protection automatically; treat any endpoint without an explicit restriction as a review item. (A superuser support role also passes every internal authorization check by design.)

  • Feature flags can be changed by any signed-in user through the internal API. The screen for managing application feature flags is restricted in the interface, but the underlying update endpoint has only the general "signed in" restriction and the service performs no role check. What it means: a signed-in caller who knows the endpoint could toggle a flag. Impact: a flag change affects the whole tenant. Each change that alters a flag's state posts a notice to the developer channel, which is the only record, so use that channel to check who changed a flag. Changing the flag that makes reference settings follow shipment organizations also queues a data-migration job.

  • The cross-organization approval endpoints assume an accounting organization. They read the caller's accounting organization directly, so a caller without one gets an unexpected server error instead of a clear message.

  • Carrier confirmation response links work without signing in, by design. The carrier-facing accept and reject calls are open to anonymous callers and identify the shipment through an encrypted shipment id in the link, ignoring any shipment id in the body. Impact: the link itself is the credential, so treat tender and confirmation links as sensitive.

Public and external interface caveats

  • The public API allows permissive cross-origin access. The public version-2 endpoints are configured to accept cross-origin browser requests from any origin. What it means: combined with the header-based API key model, the broad cross-origin setting is broader than strictly necessary. Impact: it is a known internal review item; keep it in mind when reasoning about how the public API can be called from a browser.

  • Public-API rate limiting is observe-only, partial, and lives at the edge. Per-organization and per-API-key request quotas (per-minute/day/month) are enforced by an edge layer (a Cloudflare worker) in front of the API, not by any check inside the application. What it means: in its current form the edge layer only observes: it counts usage and flags an over-limit request with response headers, but it does not block or return a rejection, and it fails open (on an internal error it forwards the request unrecorded). It also counts only an allow-list of public API path prefixes, so driver tracking, the retired v1 shipping area, and the inbound webhooks are never counted. The quota sync to the edge runs in production only, so non-production environments never receive quotas. Impact: do not assume the public API is actually shielded by a hard rate limit today; an over-quota caller is still served. Missing usage counts are not proof that traffic did not happen.

  • The sign-in token issued by the public API is not an API credential. The token endpoint issues a five-minute token meant for the web application's single-sign-on handoff. The v2 endpoints do not accept it. What it means: an integrator who tries to use it as a bearer token will fail. Impact: direct integrators to the API key. The token's signature is checked, but issuer and audience are not, so the signing secret is the entire protection.

  • Webhook authentication and error codes vary by partner, and some have none. Inbound partner webhooks each use their own authentication scheme and can return different error codes for missing versus invalid credentials. Several partner endpoints (DAT Convoy, DexFreight, Highway TFX, Motive book-it-now, MacroPoint, OpenTrack, Shipco, TruckerTools, and Truckstop) show no credential check at the endpoint itself, and the older driver-tracking status endpoint only rejects a blank key without validating it. What it means: there is no single webhook auth or error convention, and for those endpoints any protection must come from somewhere else (not confirmed). Impact: when supporting a partner integration, check that partner's specific scheme and preserve its error responses, since partners may key their retry behavior on them; do not copy an unauthenticated webhook as a pattern.

  • Older public API operations are being retired in stages. Most v1 operations have been deleted and now return a plain "not found"; a few more return a "fully deprecated" message once their retirement switch is on; only three v1 rate-quote operations still work. The v2 "Deprecated" group is still served. Impact: a customer whose v1 integration broke should be moved to v2; do not re-add v1 behavior.

  • Resolving a variance twice fails. The public API operations that move a bill or invoice out of variance return an error when nothing is in variance, so a retry after success looks like a failure even though the first call worked.

Carrier integration caveats

  • The carrier-integration service has authenticated routes, but its older routes are still open. The standalone service that brokers all carrier communication (rating, dispatch, tracking, imaging) now offers "secure" routes that require an Azure AD bearer token from an allowed group. The main application calls them only where the Azure-authentication setting is turned on for that environment; otherwise it still calls the original routes. Those original routes remain reachable without any credential, and the service has no global requirement. What it means: protection of the original routes depends on where and how the service is deployed, and an environment with the setting off is using them. Impact: never expose this service beyond its trusted network boundary, and do not assume an endpoint is authenticated without checking that it is one of the secure routes. An empty allowed-group setting makes every secure call fail.

  • The carrier rating service does not cache and does not retry. When a rate quote is requested from a carrier, the request goes to the live carrier every time, and a failure is returned as a failed result on the first attempt with no automatic retry. What it means: there is no cached rate reuse and no built-in second attempt. Impact: expect every quote to hit the live carrier (slower, and subject to carrier rate limits), and expect transient carrier failures to surface immediately rather than being retried; callers must inspect the failed-result details rather than relying on an error being thrown.

  • Rating never throws an error to its caller; it returns a "failed" result. A carrier rating failure comes back as a failed rating entry (with error, "not serviced," or authentication-error indicators) rather than as an outright error response. What it means: a caller that only checks for a hard failure will miss problems. Impact: support and integrations must read the failed-result fields to understand what happened; a successful HTTP call does not mean a successful quote. An empty carrier response shows up as "No quotes returned," not as a parsing error.

  • "Not serviced" detection partly depends on recognizing carrier wording. Whether a lane is flagged as "not serviced" can depend on matching known phrases (a list of a few dozen) in a carrier's response. What it means: a new or reworded carrier "no service / no rates" message that is not yet recognized will be treated as a generic failure rather than a clean "not serviced." Impact: occasionally a not-serviced lane shows up as a generic error until the new wording is accounted for.

  • Carrier-call activity logs are best-effort and can be lost. The carrier-integration service records each carrier call to an activity log, but those log entries are buffered in memory and sent in the background (on a time/size threshold, fire-and-forget) without retry. What it means: entries still waiting in the buffer when the service restarts, or a send that fails, are dropped. Impact: the carrier-call activity log is not a guaranteed-complete audit trail; a missing entry does not necessarily mean the underlying call did not happen.

Shipment locations and geocoding caveats

  • Geocoding resolves the full street address, and a failed address is not retried automatically. The shipment-locations service geocodes the shipment's full street address against the mapping provider (it does not fall back to a postal-code centroid, and it keeps no private geocode cache). What it means: a bad or unresolvable address returns no coordinates, and the service marks that location as having a failed geocoding attempt so the re-geocode passes skip it thereafter. Impact: a permanently bad address will not plot and will not be retried on its own; someone must correct the address. The only reuse is matching an existing stored coordinate for the same location string. Only US, Canadian, and Mexican addresses are recognized; a result in any other country is labeled as US.

  • Location writes are direct service calls with no cross-store transaction. The monolith's own location tables and the change-tracking queue that used to feed the service are gone; every location write, read, and delete is now an HTTP call to the service with a default 30-second timeout. What it means: a service outage or timeout fails the write, and background jobs run with no automatic retry. In the driver-tracking pull job, the monolith-side updates are saved before the location call and the activity logs after it, and the location call is outside the per-shipment guard, so a service failure can leave the first part saved. Impact: after a location-service incident, expect some shipments with updated tracking state but missing location points.

  • The meaning of "newest location" differs between operations. Reads and de-duplication use the latest location time, while some updates and the history view use the latest record id. What it means: with a future-dated or back-filled row they can point at different rows. Impact: be careful when explaining why a remaining-miles update or a history view disagrees with the latest-location read.

Dispatch, load-board, and background-processing caveats

  • EDI-based dispatch can lag the real-time API path. Electronic dispatch to a carrier through the direct API path happens in real time, whereas EDI-based exchange is processed by scheduled background jobs. What it means: an EDI dispatch or update is not instantaneous the way an API dispatch is. Impact: expect some delay between an action and its EDI reflection, and do not assume EDI and API dispatch happen on the same timeline when comparing them.

  • Reposting to load boards is handled by status, not a dedicated repost action. For load boards, updating or reposting a load is not a separate operation; it is handled within the normal post flow based on the load's processing status (post, repost, or remove). What it means: there is no independent "repost" action that runs on its own. Impact: when troubleshooting a repost, look at the load's status-driven post handling rather than expecting a distinct repost operation; some boards implement a repost as a fresh post under the hood.

  • Background jobs do not retry by default. The background-job system is configured so that, unless a specific job opts into retries, a job that fails is not retried automatically. What it means: a transient failure can permanently drop that run of a job unless it opts in or is picked up on its next scheduled run. Impact: when a scheduled task appears to have "not run," consider that a transient failure may have dropped it; jobs are designed to be safe to re-run on the next cycle. Locally, scheduled jobs are not registered at all and must be triggered by hand.

  • The background-job dashboard is protected only by "signed in." Any authenticated user who can reach the dashboard passes its check; there is no role requirement. Impact: restrict who can reach it at the network or identity level.

  • Non-production environments use fakes for outbound delivery. Outside production, file-transfer uploads, email, fax, and (except on the beta environment) webhook delivery are replaced by fakes. Impact: "it worked in a test environment" says nothing about whether those deliveries really work.

Accounting sync caveats

  • Some accounting-sync options are referenced but not present in this build. The accounting-sync layer refers to a Dynamics GP strategy and a mock/test strategy by name, but neither is actually included in this build; only the QuickBooks Online integration ships through the sync layer. What it means: the code paths that would branch to those strategies are effectively inert here. Impact: do not expect Dynamics GP or the mock strategy to be available in this build, and treat references to them as placeholders for other editions rather than active features.

  • There are two QuickBooks sync engines, and the newer one is now the one the screen uses. The original sync action and the newer "v2" action both exist, but the feature flag that once hid the newer one has been removed, so the accounting-sync screen always calls the newer one. What it means: sync behavior can still differ between the two if something calls the original action. Impact: when investigating an accounting-sync issue, confirm which action was used, since a behavior change may need to be understood (or made) in both.

  • Canadian tax lines never reach carrier payables. Where Canadian tax handling is enabled, a tax line is forced to equal its sell amount on the buy side and is marked as having no accounting, so it is never a carrier-payable line. The province rates come from an outside lookup, and if it fails the system uses built-in fallback rates. Impact: a rate that looks stale on a shipment may be a fallback.

Reference-number caveats

  • Built-in reference numbers are being moved into the custom reference table, and the move is partial. While the dual-write setting is on, every writer of a built-in reference value must also write the mirrored copy, or the copy goes stale for readers that have switched to the custom table. The scheduled backfill and the manual repair jobs run only in an early-morning window (about 05:00 to 08:59 UTC), process only the shipment level (stop and commodity levels are not migrated), and run in bounded chunks. The repair job refuses to run once the custom table is the read source. Impact: a mismatch between the two copies can persist until the next window; do not run repairs after the read switch.

  • Which reference fields appear depends on several settings at once. The shipment-organizations setting, the shipment-validation and required-reference settings, and the customer-reference-settings setting each change what a shipment shows, and the closest-organization rule lets a setting that is on override a closer one that is off. Impact: when a customer reports a missing or unexpected reference field, check all of these and both the customer-scoped and shipment-scoped settings.

Data caveats

  • Shipment location tables are gone from the main database. Any report, script, or query that still reads them fails. Use the last-known-location table or the location service. The drop cannot be reversed.

  • The archive has one write path and moves only activity logs. If archiving looks stuck, look at the archive service and the job's call to it; there is no setting to fall back to an older path. Location history is not archived by any job.

  • No optimistic concurrency. Two people saving the same record at the same time do not get a conflict warning; the last writer wins.

  • Bulk operations bypass validation. Field-level validation does not run on bulk inserts, merges, updates, and deletes; only the database's own constraints apply.

  • Stored procedures come back on every migration. A procedure dropped in one migration but still listed in the seed list is recreated on the next run.

LTL weight/class auto-update caveats

  • A carrier-reported weight difference over 40% is silently dropped, with no update and no alert. When a carrier reports an LTL weight, the TMS auto-adjusts only when the difference is at least 20 lb and under 40% of the current weight. A difference of 40% or more is neither applied nor flagged: no weight change is made and no alert is created. What it means: the "Carrier Weight Difference" alert fires only on the successful auto-adjustment (the 20 lb to under-40% band), never on the 40%-or-over case. Impact: a large carrier/shipment weight discrepancy can pass unnoticed unless someone reviews the carrier bill; do not rely on an alert to catch big discrepancies. (Note: the public-facing article frames over-40% as "review manually"; the system does not itself surface it.)

  • Freight class is never auto-updated. The carrier-reported update path changes shipment weight only; there is no reclassification logic anywhere in it. What it means: if a carrier reclassifies freight, the class in the TMS is not changed automatically. Impact: any customer/AI claim that Tai "auto-updates class where supported" is incorrect; class changes are manual. Weight auto-updates also apply only through Delivered status.

Frequently asked questions

Are all of the Tai TMS internal API endpoints protected by an access check?

No. In the Tai TMS, protection on internal API endpoints is applied per endpoint rather than on by default, so an endpoint without an explicit access restriction is reachable by any caller who can reach the application (about 49 of roughly 294 controllers carry none). In addition, some endpoints carry an access marker that belongs to a different part of the framework than the one they run in, so that marker does not actually take effect. Both are known internal review items, and staff should verify an endpoint's protection rather than assuming it.

Who can change a feature flag in the Tai TMS?

The management screen is limited in the interface, but the underlying internal endpoint only requires a signed-in user and the service does no role check, so the restriction is not enforced server-side. A state change posts a notice to the developer channel, which is the practical audit trail. Flag changes affect the whole tenant.

Is the Tai TMS public API actually protected by rate limiting?

Only in an observe sense today. Per-organization and per-API-key quotas are counted by an edge layer in front of the API, but that layer currently only records usage and flags over-limit requests with response headers; it does not block them, and it fails open on its own errors. It also counts only an allow-list of paths, so driver tracking and the inbound webhooks are never counted, and the quota sync runs in production only. So an over-quota caller is still served; do not treat the rate limiter as a hard shield, and remember there is no rate-limit check inside the application itself.

Can an integration use the token from the public API's token endpoint to call the v2 endpoints?

No. The token is a five-minute sign-in handoff for the web application. The v2 endpoints authenticate with the API key only.

Are the partner webhooks all authenticated?

No. Each uses its own scheme, and several (DAT Convoy, DexFreight, Highway TFX, Motive book-it-now, MacroPoint, OpenTrack, Shipco, TruckerTools, and Truckstop) show no credential check at the endpoint itself. Any protection for those would have to come from deeper checks, partner network controls, or edge controls, none of which has been confirmed. Treat this as a review item.

Does the Tai TMS carrier-integration service authenticate the calls it receives?

Partly. It offers secure routes that require an Azure AD bearer token from an allowed group, and the main application uses them where the Azure-authentication setting is on. Its original routes remain open to any caller who can reach the service. The practical implication is that protection of the older routes comes from network boundaries, so the service must never be exposed outside that trusted boundary.

If a carrier rate quote fails in the Tai TMS, will it retry automatically?

No. In the Tai TMS the carrier rating service does not retry and does not cache; each quote request goes to the live carrier, and a failure comes back as a failed result on the first attempt. It also does not throw an outright error; instead it returns a failed rating entry with indicators such as error, "not serviced," or authentication error. Callers and support must inspect those result fields to understand the outcome.

Why might a carrier-call activity log entry be missing in the Tai TMS?

In the Tai TMS, the carrier-integration service records each carrier call to an activity log on a best-effort basis: entries are buffered in memory and sent in the background without retry. If the service restarts while entries are still buffered, or a send fails, those entries are lost. So a missing log entry does not necessarily mean the underlying carrier call did not occur; the activity log is not a guaranteed-complete audit trail.

A shipment address will not plot on the map in the Tai TMS. Why, and will it fix itself?

The shipment-locations service geocodes the full street address against the mapping provider, and if the address cannot be resolved it returns no coordinates and marks that location as a failed geocoding attempt. Once marked, the automatic re-geocode passes skip it, so it will not fix itself; someone has to correct the address. There is no postal-code fallback, and the only reuse is an existing stored coordinate for the same location string.

After a location-service outage, why do some shipments show updated tracking but no location points?

Location writes are direct calls to the location service with a short timeout and no cross-store transaction, and background jobs do not retry. In the driver-tracking pull job the monolith-side updates are saved first, so a service failure can leave tracking state updated while the location points are missing. They fill in on later updates.

Why did a scheduled background task in the Tai TMS appear to simply not run?

In the Tai TMS, background jobs do not retry by default; unless a specific job opts into retries, a run that hits a transient failure is dropped rather than retried. That is why a task can appear to "not run." Jobs are designed to be safe to re-run, so the usual expectation is that the work is picked up on the job's next scheduled cycle; a persistent absence, however, points to a real problem worth investigating.

Why does a report or script that reads shipment locations from the main database now fail?

The main database's location tables were dropped in September 2026 after the location service cutover, and the drop cannot be reversed. Use the last-known-location table for grids and report columns, or the location service for full history.

Can I rely on Dynamics GP or a mock accounting sync being available in this build of the Tai TMS?

No. In this build of the Tai TMS, the accounting-sync layer refers to a Dynamics GP strategy and a mock/test strategy by name, but neither is actually included; only the QuickBooks Online integration ships through the sync layer. The branches that would use those other strategies are effectively inert here, so treat references to them as placeholders for other editions rather than active features.