Skip to main content

Turvo Trigger

The Turvo Trigger starts a workflow when Turvo — a cloud transportation management system (TMS) — reports an event. When a shipment is created or updated, a shipment's status changes, or a customer invoice is created or updated in Turvo, Turvo posts the event to Splice, and this trigger turns it into a workflow execution. Use it to react to Turvo activity in real time: sync shipments into another system, generate and transmit EDI, automate billing, validate data, or raise exceptions as they happen.

Overview

Use the Turvo Trigger when you need to:

  • React to shipment lifecycle events - Start a workflow the moment a Turvo shipment is created, changes, or moves to a new status
  • Automate billing - Act on customer invoice creation and updates (e.g. push invoices into an accounting system or send an 810)
  • Keep systems in sync - Push shipment and invoice changes from Turvo into a WMS, ERP, billing system, or data warehouse
  • Drive EDI from Turvo activity - Generate and send EDI (e.g. 204/214/990/810) in response to Turvo events
  • Act on full shipment data - Shipment events carry the complete shipment object, so the workflow can branch and transform without an extra lookup

Endpoint & Setup

The Turvo Trigger is delivered over the same HTTP ingress as the Webhook trigger. Turvo posts events to the workflow's public endpoint:

POST https://<your-splice-api-domain>/hook/{workflowId}

Configure a Turvo webhook subscription to send events to this URL (copy it from the workflow), then choose which events should start the workflow with the Action setting below. The events this node consumes are Turvo's standard webhook events — see Turvo's Events documentation for the authoritative event catalog and payload reference.

Trigger vs. the Turvo API

The trigger node itself takes no credential — it only receives the inbound event. If a workflow needs to call back into Turvo (to fetch related records or push updates), use an HTTP Request or a Turvo service node with a separate Turvo API credential. That credential holds the Environment (Sandbox/Production), Client ID, Client Secret, Username, Password, and API Key used for outbound Turvo API calls.

Configuration

Action (required)

The set of Turvo events that may start the workflow. Select one or more; only the selected event types trigger a run.

EventValueFires when
Add Shipmentshipment-createA new shipment is created in Turvo
Update Shipmentshipment-updateAn existing shipment is updated in Turvo
Shipment Status Updateshipment-status-updateA shipment's status changes
Customer Invoice Createcustomer-invoice-createA customer invoice is created
Customer Invoice Updatecustomer-invoice-updateA customer invoice is updated

Output

The trigger emits a single output keyed by the node's name. The payload shape depends on the event type, and Turvo uses two different envelopes:

  • Shipment events (shipment-create, shipment-update) — { event, data }, with the full shipment object under data.
  • Status events (shipment-status-update) — primarily { event, data } with a compact status summary (an alternate { eventName, eventPayload } form also occurs).
  • Invoice events (customer-invoice-create, customer-invoice-update) — { tenantId, eventName, eventTime, eventPayload }, with the invoice under eventPayload.document.

Because the envelope and fields vary, inspect the captured sample for the events you actually receive before mapping fields downstream.

Shipment events

shipment-create and shipment-update deliver the complete shipment under data:

{
"Turvo Trigger": {
"event": "shipment-update",
"data": {
"id": 42250,
"customId": "31423-79336",
"status": {
"code": { "id": 100162, "key": "2102", "value": "Covered" }
},
"type": { "key": "5000", "value": "FTL" },
"lane": { "start": "Palo Alto, CA", "end": "California City, CA" },
"customerOrder": [ { "id": 42870, "customer": { "id": 149090, "name": "testWebhookEventCust" } } ],
"carrierOrder": [ { "id": 25738, "carrier": { "id": 149091, "name": "testWebhookEventCarrier", "scac": "AAXEW" } } ],
"globalRoute": [ /* stops with address, appointment, stopType, ... */ ],
"items": [ /* commodities */ ]
}
}
}
  • data - The complete Turvo shipment object. It is large and nested; the most commonly used fields are:
    • data.id - The Turvo shipment ID.
    • data.customId - The human-readable shipment / custom ID.
    • data.status.code.value - The shipment status (e.g. Covered, Tendered, Delivered).
    • data.customerOrder[] / data.carrierOrder[] - Customer and carrier order details, including parties, costs, equipment, invoices, and payments.
    • data.route[] / data.globalRoute[] - The stops, with addresses, appointment windows, stop types, and PO numbers.
    • data.items[] - The commodities on the shipment (weights, dimensions, hazmat, quantities).
    • data.externalIds[] - External reference values such as SCAC and PO numbers.
The shipment payload is large

A shipment event contains hundreds of fields across nested orders, routes, and items. Use a Set or Code node early in the workflow to pull out just the fields you need, and reference them by path (e.g. {{$json.data.status.code.value}}) downstream.

Status events

shipment-status-update delivers a compact status summary rather than the full shipment object:

{
"Turvo Trigger": {
"event": "shipment-status-update",
"data": {
"id": 6677898,
"status": {
"code": { "id": 100164, "key": "2104", "value": "At pickup" },
"description": "At pickup",
"notes": "",
"miles": 1364,
"eta_seconds": 11708339,
"statusDate": { "date": "2024-08-15T14:19:00-04:00", "timezone": "America/New_York" },
"location": { "name": "Fort Myers, FL", "lat": 26.6054192, "lng": -81.8704111 },
"updatedBy": { "id": 1786, "name": "Regression Broker" }
},
"customerOrder": [ { "id": 2367, "customer": { "id": 762 } } ],
"carrierOrder": [ { "id": 1429, "carrier": { "id": 669 } } ]
}
}
}
  • data.id - The Turvo shipment whose status changed.
  • data.status.code.value - The new status (e.g. At pickup, Delivered); data.status.description is the human-readable label.
  • data.status.location - Where the shipment is, with name, lat, and lng.
  • data.status.miles / data.status.eta_seconds - Remaining distance and ETA to the next stop.
  • data.status.updatedBy / data.status.statusDate - Who changed the status and when.
Status field shapes vary

Turvo's status feed is not perfectly uniform — some integrations emit a different envelope ({ eventName: "SHIPMENT_STATUS_UPDATE", eventTime, eventPayload: { ... } }) instead of { event, data }. Inspect the captured sample for the events you actually receive and read defensively.

Invoice events

customer-invoice-create and customer-invoice-update use Turvo's { tenantId, eventName, eventTime, eventPayload } envelope. The invoice lives under eventPayload.document, alongside the parent shipment's context:

{
"Turvo Trigger": {
"tenantId": "181",
"eventName": "CARRIER_INVOICE_ADD",
"eventTime": "2021-07-14T14:46:48.009Z",
"eventPayload": {
"id": 6889103,
"custom_id": "R3160-12764",
"document": {
"type": "Carrier invoice",
"status": { "id": 110591, "key": "2800", "value": "Draft" },
"invoice": {
"id": "68381591861ddd5d7fdcad6c",
"number": "Carrier-Invoice-01",
"amount": 100,
"date": "2025-05-29T05:00:00.000Z",
"dueDate": "2025-05-30T05:00:00.000Z"
},
"currency": "CAD",
"account": { "id": 2035483, "accountId": 4897112, "name": "CreditMemoCarrier", "type": "CARRIERORDER" },
"memo": { "issuances": [ /* ... */ ], "allocations": [ /* ... */ ] }
},
"carrierOrder": [ /* order, costs, equipment, externalIds, ... */ ],
"status": { "code": { "id": 100162, "key": "2102", "value": "Covered" } },
"lane": { "start": "Los Angeles, CA, US", "end": "Los Angeles, CA, US" },
"totalPayableAmount": 100,
"totalReceivableAmount": 500
}
}
}
  • eventName - CARRIER_INVOICE_ADD (create) or CARRIER_INVOICE_UPDATE (update).
  • eventPayload.id / eventPayload.custom_id - The shipment the invoice belongs to.
  • eventPayload.document.invoice - The invoice's id, number, amount, date, and dueDate.
  • eventPayload.document.status.value - The invoice status (e.g. Draft, Approved).
  • eventPayload.document.currency - The invoice currency (a string here, e.g. CAD).
  • eventPayload.document.account - The billed account (name, type).
  • eventPayload.status.code.value - The parent shipment's status.
Inspect the invoice payload before mapping

Invoice events are the least consistent of the Turvo events. They use the { eventName, eventPayload } envelope, and the metadata's bundled sample is actually a carrier invoice (document.type: "Carrier invoice", eventName: CARRIER_INVOICE_ADD) even though the action is labeled "Customer Invoice." Map fields from the sample your Turvo tenant actually sends, not from a fixed shape.

Example Usage & Common Use Cases

Sync a Shipment into Another System

[Turvo Trigger] → [Set: map data.id / customId / status / stops]
→ [HTTP Request: upsert into WMS]

Generate EDI on Shipment Creation

Action: Add Shipment

[Turvo Trigger] → [Set: extract shipment fields] → [EDI: build 204] → [AS2 / FTP: send to carrier]

Branch on Event Type

[Turvo Trigger] → [If: event == "shipment-create"]
↓ true ↓ false (update)
[Create record] [Update record]

Act on Status Changes

Action: Shipment Status Update

[Turvo Trigger] → [If: data.status.code.value == "Delivered"] → [Send 214 / notify customer]

Automate Customer Invoicing

Action: Customer Invoice Create

[Turvo Trigger] → [Set: map invoiceNumber / customer / amount]
→ [EDI: build 810] → [AS2: send to customer]

How It Works

  1. Turvo posts an event - Turvo sends a POST to the workflow's /hook/{workflowId} URL when a subscribed event occurs, including the full shipment payload.
  2. Match the trigger - The webhook ingress resolves the workflow and selects its trigger node.
  3. Filter by action - Only events whose type is enabled in Action start the workflow.
  4. Enqueue - The event envelope ({ event, data }) becomes the trigger output and a workflow execution is started.

Best Practices

  • Select only the events you handle - Enabling just the event types the workflow is built for avoids unnecessary runs.
  • Extract early - The payload is deep and verbose; map the handful of fields you need up front so downstream nodes stay readable.
  • Make downstream actions idempotent - shipment-update can fire repeatedly for the same shipment; key downstream updates on data.id so repeats are safe.
  • Handle create/update distinctly - Branch on event when create and update should do different things (insert vs. upsert).
  • Guard against missing fields - Optional sections (invoices, payments, holds, items) may be absent or empty depending on the shipment; don't assume a fixed shape.

Troubleshooting

Common Issues

  • No workflow runs on a Turvo event - Confirm Turvo's webhook subscription points at the correct /hook/{workflowId} URL, the workflow is active, and the event type is enabled under Action.
  • A field is missing from data - Turvo omits sections that don't apply to a given shipment. Inspect the captured sample for the actual shape and code defensively.
  • Outbound Turvo API call fails - The trigger and the Turvo API are separate concerns. Verify the Turvo API credential (environment, client ID/secret, username/password, API key) used by the downstream HTTP/service node, not the trigger.

Debugging Tips

  • Inspect the captured sample - The trigger output is stored as node sample data on each run; use it to navigate the nested payload and build downstream field paths.
  • Test with a manual POST - Send a sample shipment-create / shipment-update body to the URL with curl to confirm the endpoint and downstream logic before relying on live Turvo events.
  • Webhook - The general-purpose HTTP trigger this node is built on
  • HTTP Request - Call back into the Turvo API when the workflow needs more than the event payload
  • Turvo Events documentation - Turvo's authoritative reference for the webhook events this node receives
  • Trigger Nodes - Overview of all available workflow trigger types