Workflow External Action
Fires an outbound HTTPS POST to any URL from an in-app workflow, with the current shipment's full data plus a configurable auth model. Used to hand shipments off to external systems (AI agents, third-party dispatchers, customer-side automations, etc.) without a custom integration.
Overview
Workflow External Action is a one-way outbound trigger from Tai to your
system. Tai does not read or accept a response body as part of the
workflow — the payload is essentially a rich webhook that hands your
system a fully-hydrated shipment and any context parameters you've
configured. It's meant to start work on your side, not to exchange
data in a single call.
The end-to-end flow:
- A dispatcher (or an automation) triggers the workflow against one or
more shipments in TMS. - Tai
POSTs a JSON payload — full shipment details plus any configured
auth/context parameters — to the URL configured on the Integration Source. - Tai logs the request and (optionally) the response against the shipment
and always drops an AI Agent Call alert on it. - Your system reacts to the payload — spin up an AI agent, dispatch to
a driver, create a ticket in your own platform, etc. - When your system needs to update Tai (append a note, change a
status, upload a document, submit a quote, etc.), it calls Tai's
Public API.
Prerequisites
- LSP-level access to configure Integration Sources.
- Your endpoint publicly reachable over HTTPS.
- Contact your Tai account team to enable the Workflow External Action
Integration Source type. - A BrokerTMS Public API key if you plan to push updates back to Tai
from your system (see the [Public API Documentation]).
Create the Integration Source
In BrokerTMS, go to LSP → Integration Sources → Add New Integration Source and choose type
Workflow External Action. The SourceName you enter shows up on the
shipment activity log as AI Agent Call executed via <SourceName>. and on
the shipment alert as AI Agent Call via <SourceName>.
Configuration Parameters
Every knob is either a field on the Integration Source itself or a row on
its IntegrationSourceParameters table. Parameter names are matched
case-insensitively.
Required
| Parameter | Purpose |
|---|---|
url | Destination URL for the outbound POST. Must be present and non-empty — omitting it causes Tai to return 400 Integration source does not have a url parameter. |
Reserved (behavior-controlling, not sent to your endpoint)
| Parameter | Value | Effect |
|---|---|---|
EnableLogging | true / false | When true: Tai awaits the response body, stores it in the ApiActivityLog, and writes a private ShipmentActivityLog on the shipment. When false (or omitted): the request is fired without awaiting a response body. ApiActivityLog is written either way. |
DefaultStaffId | integer StaffId | Fallback carrier rep — used if the shipment has no CarrierRep. |
Custom Headers
Any parameter whose name starts with Header_ is sent as an HTTP header on
the outbound call. The prefix is stripped to form the header name.
| Parameter Name | Header Sent |
|---|---|
Header_Authorization | Authorization: <value> |
Header_x-api-key | x-api-key: <value> |
Header_X-Vendor-Account | X-Vendor-Account: <value> |
Multiple Header_* parameters are supported and all are sent on every call.
Values are added with TryAddWithoutValidation, so any header format is
accepted (no strict RFC 7230 checks). This is the recommended path for
Bearer tokens, API keys, or any other auth scheme your endpoint requires.
Custom Body Parameters
Any Integration Source parameter that is not url, EnableLogging,
DefaultStaffId, or a Header_* entry is added as a top-level key inside
the integrationSourceParameters object on the outbound payload, keeping
the exact parameter name as the JSON key.
Use these to pass anything your endpoint needs to identify the connection
(vendor account ID, workflow ID, environment tag, etc.).
Integration Source Field Handling
Two fields on the Integration Source itself are automatically injected into
integrationSourceParameters on every call — only when non-empty:
| Field on IntegrationSource | Injected as | Condition |
|---|---|---|
LicenseKey | integrationSourceParameters.licenseKey | Only if non-empty. |
AccountNumber | integrationSourceParameters.accountNumber | Only if non-empty. |
UserName and Password fields on the Integration Source are NOT sent
by this integration. If you need to send credentials to your endpoint,
either:
- Add them as custom parameters (e.g. an
IntegrationSourceParameternamed
UserNamewill surface asintegrationSourceParameters.UserName), or - Send them as HTTP headers via the
Header_*convention (recommended for
Bearer tokens and API keys).
The Outbound Request
- Method:
POST - URL: the
urlparameter value, unchanged - Content-Type:
application/json; charset=utf-8 - Headers: any
Header_*parameter values, plusContent-Type - Body: JSON object with two top-level keys —
shipmentand
integrationSourceParameters. See the full example below.
Triggers
The Workflow External Action can be fired from three places in the TMS UI:
- Check Call — On an individual shipment's Check Call screen, any
configured Workflow External Action integration source appears as a
callable action. Runs synchronously for that single shipment. - Shipment Search / Company Loadboard — Bulk Operations — Select multiple shipments on
the Shipment Search page and choose the Workflow External Action from
the bulk operations menu. Runs in the background as a Hangfire job. - Workflow Automations — Configure a workflow rule to fire the
action automatically when its trigger conditions are met (status
change, alert added, etc.).
Response Handling
- Any HTTP status from your endpoint is tolerated. Non-2xx responses do
not halt the workflow. Network errors and exceptions are swallowed —
Tai still writes the activity log and the shipment alert. - Response bodies are only captured when
EnableLoggingistrue. - Regardless of outcome, every call:
- Adds an AI Agent Call shipment alert.
- When
EnableLogging = true, additionally: a privateShipmentActivityLog
entry visible in the shipment's activity feed.
Sending Updates Back to Tai
The Workflow External Action is one-way. There is no reserved "return"
endpoint or expected response format — Tai does not read the response body
into the shipment record, and any state change on Tai's side after the
webhook fires must come from a Public API call your system makes.
That's the intended design: your system uses the payload as its trigger and
then uses Tai's Public API for any updates it needs to push back —
comments, status changes, attachments, quotes, tracking updates, and so on.
See the [Public API Documentation] for the full endpoint catalog. Common
patterns include:
- Posting shipment activity notes / comments
- Updating shipment status
- Uploading attachments (documents, BOLs, PODs)
- Submitting a truckload quote (
POST /PublicApi/Shipping/v2/TruckloadQuote) - Updating tracking, appointments, or stop actuals
Your system uses its own Public API key for these calls — the credentials
configured on the Workflow External Action Integration Source are for
authenticating inbound to your system, not for calling back to Tai.
Carrier Rep Resolution
shipment.carrierRep in the outbound payload is resolved in this order:
- Whatever CarrierRep is already set on the shipment.
- Otherwise, if
DefaultStaffIdis configured on the Integration Source,
the Staff record with that ID — but only if that Staff belongs to the
same accounting organization as the Integration Source owner. - Otherwise (or if the Staff is in a different accounting org), the
DefaultStaffconfigured on the Integration Source's owner
organization.
This guarantees the outbound payload always carries a CarrierRep, even for
shipments that don't have one assigned yet.
Example
For an integration that hits https://agent.example.com/v1/dispatch with a
Bearer token and a vendor workflow tag:
| Where | Field / Parameter | Value |
|---|---|---|
| IntegrationSource | SourceName | Acme Dispatcher Agent |
| IntegrationSource | LicenseKey | LK-9F2A |
| IntegrationSource | AccountNumber | ACME-001 |
| IntegrationSourceParameters | url | https://agent.example.com/v1/dispatch |
| IntegrationSourceParameters | EnableLogging | true |
| IntegrationSourceParameters | Header_Authorization | Bearer eyJhbGciOi… |
| IntegrationSourceParameters | WorkflowId | dispatch-standard |
| IntegrationSourceParameters | Environment | production |
Outbound request headers:
Authorization: Bearer eyJhbGciOi…
Content-Type: application/json; charset=utf-8
Outbound request body:
{
"shipment": {
"latitude": 42.61458,
"longitude": -89.62367,
"locationString": "06/30 08:04 ET : North 29th Avenue, Monroe, WI, 53566",
"lastLocationUpdate": "2026-06-30T12:04:00Z",
"mileage": 4093.64,
"customer": {
"name": "Acme Manufacturing",
"referenceNumber": null,
"staffID": 896203,
"staffName": "Shipping",
"staffReferenceNumber": null,
"salesRepNames": "Sales Rep",
"billToOrganizationId": 217393,
"officeOrganizationId": 798833,
"officeName": "Field Sales"
},
"carrierRep": {
"staffId": 1040914,
"contactName": "Acme Automation",
"email": null,
"phone": null
},
"payerOrganization": {
"organizationId": 217393,
"name": "Acme Manufacturing",
"address": {
"streetAddress": "8950 Seward Road",
"streetAddressTwo": null,
"city": "Fairfield",
"state": "OH",
"zipCode": "45014",
"country": "USA",
"contactName": null
}
},
"totalBuy": 1500.00,
"totalSell": 1600.00,
"status": "Delivered",
"carrierList": [
{
"carrierMasterId": 516202,
"transitLegId": 29837094,
"shipmentStopIds": [54235677, 54659984, 54235678],
"name": "Sample Carrier Corp",
"scac": "",
"dotNumber": "3305176",
"mcNumber": "1048914",
"trackingURL": "",
"city": "Murfreesboro",
"state": "TN",
"zipCode": "37129",
"phoneNumber": "+15551234567",
"tariffName": null,
"transitType": "Linehaul",
"status": "Delivered",
"buy": 1500.00,
"sell": 1600.00,
"parentShipmentId": null,
"childShipmentIds": []
}
],
"attachments": [
{
"attachmentName": "CarrierConfirmationTruckload_130037578_signed.pdf",
"attachmentUrl": "https://<tenant>.taicloud.net/Files/SecureDownload?token=<token>",
"attachmentType": "Carrier Confirmation",
"documentId": 63309845
},
{
"attachmentName": "RateQuoteSheet_130037578.pdf",
"attachmentUrl": "https://<tenant>.taicloud.net/Files/SecureDownload?token=<token>",
"attachmentType": "Document",
"documentId": 63309861
}
],
"shipmentType": "Truckload",
"stackable": false,
"trailerType": "53 ft Van | Dry",
"trailerSize": "Full",
"weightUnits": "lbs",
"dimensionUnits": "in",
"serviceLevel": "Normal",
"importExport": null,
"shipmentReferenceNumbers": [
{ "referenceType": "Shipper Reference Number", "value": "63746" },
{ "referenceType": "Customer PO Number", "value": "QSTP000019138" },
{ "referenceType": "Trailer Number", "value": "012" },
{ "referenceType": "Tracking Reference Number", "value": "Stop 1 Arrived 06/29 12:38 - Chain (Geofence)" },
{ "referenceType": "Driver Cell Phone Number", "value": "+15551234567" },
{ "referenceType": "Linehaul Carrier Pro Number", "value": "63746" },
{ "referenceType": "Driver Name", "value": "Sample Driver" },
{ "referenceType": "Truck Number", "value": "104" },
{ "referenceType": "Carrier Dispatcher Name", "value": "Alex" },
{ "referenceType": "Carrier Dispatcher Phone Number", "value": "+15551234567" },
{ "referenceType": "Carrier Rep", "value": "Sample Rep" },
{ "referenceType": "Customer Confirmation", "value": "False" },
{ "referenceType": "Carrier Confirmation", "value": "False" },
{ "referenceType": "Carrier Dispatcher Email", "value": "[email protected]" },
{ "referenceType": "Offer Rate", "value": "1450" },
{ "referenceType": "Min Buy Rate", "value": "1350" },
{ "referenceType": "Max Buy Rate", "value": "1550" },
{ "referenceType": "External Carrier Confirmation Id", "value": "10107785|20242312" },
{ "referenceType": "Shipment Id", "value": "130037578" },
{ "referenceType": "Linehaul Carrier Pro Number Clean","value": "63746" },
{ "referenceType": "Built by", "value": "Sample User" },
{ "referenceType": "Tracking Check Call Notes", "value": "Empty in Walton, KY" },
{ "referenceType": "Tracking Miles to Next Stop", "value": "0.1 miles to Stop 2 : 06/30 08:04 ET" },
{ "referenceType": "Est ETA", "value": "06/30 08:00 CT" },
{ "referenceType": "VIN", "value": "1XKYD00X0XX000000" },
{ "referenceType": "Customer Tracking Link", "value": "https://example.com/tracking/307e91da" }
],
"stops": [
{
"shipmentStopId": 54235677,
"companyName": "Acme Manufacturing",
"streetAddress": "8950 Seward Rd.",
"streetAddressTwo": null,
"city": "Fairfield",
"state": "OH",
"zipCode": "45011",
"country": "USA",
"contactName": "Shipping/Receiving",
"phone": "+15551234567",
"fax": null,
"email": null,
"instructions": "MUST HAVE LOCKS OR STRAPS TO SECURE",
"notes": "SET RATE -- 4PM",
"referenceNumber": null,
"estimatedReadyDateTime": "2026-06-29T12:00:00+00:00",
"estimatedCloseDateTime": "2026-06-29T18:00:00+00:00",
"appointmentReadyDateTime": null,
"appointmentCloseDateTime": null,
"actualArrivalDateTime": "2026-06-29T16:38:00+00:00",
"actualDepartureDateTime": null,
"stopType": "First Pickup",
"shipmentStopReferenceNumbers": [],
"shipmentStopPickupCommodities": [
{
"shipmentCommodityId": 36866679,
"pickupStopId": null,
"deliveryStopId": null
}
],
"shipmentStopDeliveryCommodities": []
},
{
"shipmentStopId": 54659984,
"companyName": "Intermediate Stop",
"streetAddress": "555 Main Street",
"streetAddressTwo": "Suite 1",
"city": "Anaheim",
"state": "CA",
"zipCode": "92807",
"country": "USA",
"contactName": null,
"phone": null,
"fax": null,
"email": null,
"instructions": null,
"notes": null,
"referenceNumber": null,
"estimatedReadyDateTime": "2026-06-29T21:00:00+00:00",
"estimatedCloseDateTime": "2026-06-29T22:00:00+00:00",
"appointmentReadyDateTime": null,
"appointmentCloseDateTime": null,
"actualArrivalDateTime": "2026-06-29T20:00:00+00:00",
"actualDepartureDateTime": null,
"stopType": "Both",
"shipmentStopReferenceNumbers": [],
"shipmentStopPickupCommodities": [],
"shipmentStopDeliveryCommodities": []
},
{
"shipmentStopId": 54235678,
"companyName": "Sample Consignee",
"streetAddress": "303 North 29th Ave",
"streetAddressTwo": null,
"city": "Monroe",
"state": "WI",
"zipCode": "53566",
"country": "USA",
"contactName": null,
"phone": null,
"fax": null,
"email": null,
"instructions": null,
"notes": null,
"referenceNumber": null,
"estimatedReadyDateTime": "2026-06-30T13:00:00+00:00",
"estimatedCloseDateTime": "2026-06-30T16:00:00+00:00",
"appointmentReadyDateTime": null,
"appointmentCloseDateTime": null,
"actualArrivalDateTime": null,
"actualDepartureDateTime": null,
"stopType": "Last Drop",
"shipmentStopReferenceNumbers": [],
"shipmentStopPickupCommodities": [],
"shipmentStopDeliveryCommodities": [
{
"shipmentCommodityId": 36866679,
"pickupStopId": null,
"deliveryStopId": null
}
]
}
],
"commodities": [
{
"shipmentCommodityId": 36866679,
"handlingQuantity": 1,
"packagingType": "Skid",
"length": null,
"width": null,
"height": null,
"weightTotal": 15000.0,
"hazardousMaterial": false,
"piecesTotal": 1,
"freightClass": "70",
"nmfc": "120700-19",
"description": "Conveyors, Elevators or Lifts",
"additionalMarkings": null,
"unNumber": null,
"packingGroup": null,
"referenceNumber": null,
"hazmatCustomClassDescription": null,
"hazmatPieceDescription": null,
"harmonizedCode": null,
"hazardClasses": [],
"shipmentCommodityReferenceNumbers": []
}
],
"accessorialCodes": [],
"shipmentAlerts": [
{
"type": "On Hand Origin",
"alertId": 2,
"createdDate": "2026-06-29T16:38:59+00:00",
"resolved": true,
"shipmentStopId": null
},
{
"type": "AI Agent Call",
"alertId": 271,
"createdDate": "2026-07-22T15:36:28+00:00",
"resolved": false,
"shipmentStopId": null
},
{
"type": "Team: Purple Team",
"alertId": 477,
"createdDate": "2026-06-29T14:15:27+00:00",
"resolved": false,
"shipmentStopId": null
},
{
"type": "Customer Approved Quote",
"alertId": 1005,
"createdDate": "2026-06-29T14:16:25+00:00",
"resolved": false,
"shipmentStopId": null
}
],
"driverCellPhoneNumber": "+15551234567",
"hazmatEmergencyContactNumber": null,
"transitTime": null,
"shipmentId": 130037578
},
"integrationSourceParameters": {
"WorkflowId": "dispatch-standard",
"Environment": "production",
"licenseKey": "LK-9F2A",
"accountNumber": "ACME-001"
}
}Related Articles
- Webhook Integration Guide
- Shipment Events
- Public API Documentation
- External Load Board Integration Guide
Updated 5 days ago
