# Introduction Conduit helps warehouses and other facilities schedule and run their pickups and deliveries. This site explains how to connect Conduit to your own systems, such as a WMS, TMS or ERP, so appointment data flows between them without manual entry. :::scalar-callout{type="neutral"} Questions that aren't answered here? Contact us at . ::: ## Ways to integrate Conduit works on its own, so you only need the integrations that fit your business. Most combine a few of these: | Integration | What it does | Start here | | --- | --- | --- | | **Import orders, loads and shipments** | Send the loads you expect from your WMS, TMS or ERP. Carriers can then only book against real loads, and appointment details are filled in for them. | [Orders, Loads & Shipments](https://developers.getconduit.ai/developer-guide/orders) | | **Receive appointment updates** | Get notified when appointments are booked, checked in, checked out, cancelled and more, so your systems stay in sync. | [Webhooks](https://developers.getconduit.ai/developer-guide/webhooks) | | **Book and manage appointments** | Check availability and book, update or cancel appointments from your own portal or system. | [API Docs](https://developers.getconduit.ai/api-docs) | | **Read appointment data** | Pull appointments into your systems or data warehouse. | [List FacilityAppointments](https://developers.getconduit.ai/api-docs#tag/default/post/conduit.v1.get_facility_appointments) | | **Single sign-on** | Let your team sign in to Conduit with your identity provider. | [SSO](https://developers.getconduit.ai/developer-guide/sso) | If these don't cover what you need, we also build custom integrations, such as: - direct connections to your TMS, WMS or ERP - EDI - files delivered over SFTP or Amazon S3 - sending events to several systems in different formats Contact us at to discuss. For a non-technical overview of integration options, see [Integrations (WMS, TMS & ERP)](https://help.getconduit.ai/articles/8366724091-integrations-wms-tms-erp) in the Conduit help center. ## Getting started 1. **Get an API key.** Organization admins can create one in Conduit. See [Authentication](https://developers.getconduit.ai/developer-guide/authentication). 2. **Find your facility IDs.** Most endpoints take a facility ID. Get them from [List Facilities](https://developers.getconduit.ai/api-docs#tag/default/post/v1/list_facilities). 3. **Pick your integrations** from the table above and follow their guides. To try things out without affecting live data, use the UAT environment at `https://api-uat.getconduit.ai`. Production is `https://api.getconduit.ai`. ## How the API works - **Requests:** every endpoint is an HTTP `POST` with a `JSON` body, and its URL names the action, such as `/conduit.v1.get_facility_appointment`. - **Authentication:** send your API key as a bearer token in the `Authorization` header. - **Responses:** `JSON`, with standard HTTP status codes. A `400` includes a message explaining what to fix. - **Dates and times:** ISO 8601. Appointment times are returned in the facility's time zone, for example `2025-05-11T11:00:00-07:00`. ## Key concepts ### Organization Your company's account in Conduit. It contains your facilities, users and API keys. ### Facility A warehouse, plant, store or other location where pickups and deliveries happen. Each facility sets its own schedule and booking rules, such as when trucks can arrive, how far in advance they must book, and whether appointments need approval. Facilities are set up and managed in Conduit, and the API can read them. ### Appointment A truck's scheduled visit to a facility, called a `FacilityAppointment` in the API. Each appointment is either `Inbound` (a delivery) or `Outbound` (a pickup), and includes: - when the truck is expected - what it's carrying, as one or more orders - the carrier and driver - where it is in its visit An appointment usually moves through these statuses: 1. `Requested`, if the facility approves bookings 2. `Scheduled` 3. `Checked In` 4. `Unloading` or `Loading` 5. `Unloaded` or `Loaded` 6. `Checked Out` It can also be cancelled, declined or rejected along the way. See the `FacilityAppointment` model in the [API Docs](https://developers.getconduit.ai/api-docs) for every status and field. ### Order An order, load or shipment you expect at a facility, identified by a reference ID such as a PO#, SO#, load number or shipment ID. An appointment can carry several orders, and a large order can be split across several appointments. Orders are optional; facilities that import them can check that carriers book against real loads. See [Orders, Loads & Shipments](https://developers.getconduit.ai/developer-guide/orders). ## Common workflows ### Book an appointment 1. Call [Get Facility Availability](https://developers.getconduit.ai/api-docs#tag/default/post/conduit.v1.get_facility_availability) to find open times for the facility, direction and reference IDs. 2. Call [Request FacilityAppointment](https://developers.getconduit.ai/api-docs#tag/default/post/conduit.v1.request_facility_appointment) with the chosen time. Depending on the facility's settings, the appointment is either `Scheduled` right away or `Requested` until the facility approves it. ### Keep your system in sync 1. Subscribe to [webhooks](https://developers.getconduit.ai/developer-guide/webhooks) for the events you care about. 2. When an event arrives, fetch the appointment with [Get FacilityAppointment](https://developers.getconduit.ai/api-docs#tag/default/post/conduit.v1.get_facility_appointment) and update your records. ### Manage an appointment Update an appointment's ETA, orders or customer, or cancel it, with the appointment endpoints in the [API Docs](https://developers.getconduit.ai/api-docs). What can be changed, and when, depends on the facility's settings. # Authentication :::scalar-callout{type="warning"} Your API key allows you to use our API and are meant to be kept secret. Be sure not to share your secret API keys in publicly accessible areas such as GitHub, client-side code, etc. ::: ### Overview The Conduit API uses API keys to authenticate requests. ### Access Organization admins can manage their API keys by visiting the `Organization Settings > Developer` ([link](https://getconduit.ai/facility-app/organization-settings/developer)) page. ### Usage Authentication to the API is performed via HTTP Bearer Auth. All API calls to Conduit should include the following header: ``` Authorization: Bearer SECRET_KEY ``` # Webhooks ## Overview Webhooks notify your system in real time when something happens to an appointment in Conduit: it's booked, confirmed, checked in, rescheduled, cancelled, and so on. This is useful for keeping a TMS, WMS, ERP or other system in sync with appointment status, check in and check out times, dock assignments and other appointment data. Each webhook is a small `JSON` notification sent over `HTTPS`. It tells you **which appointment changed and what kind of change it was**. It does not include the appointment's data. To get the data, call the Conduit API when you receive the event. ### Custom webhooks This guide describes Conduit's default webhooks. Conduit can also support custom adapters that send webhooks in a different format, such as a payload that includes appointment data, a specific schema, or a different authentication method. If your system needs something different, contact us at to discuss. ## How it works 1. Something happens to an appointment, such as a driver checking in. 2. Conduit sends a `POST` request to your endpoint with the event. The event contains the appointment's ID, not the appointment itself. 3. Your endpoint verifies the signature, records the event and returns a `200`. 4. Your system fetches the appointment from [Get FacilityAppointment](https://developers.getconduit.ai/api-docs#tag/default/post/conduit.v1.get_facility_appointment) using the `facility_appointment` ID in the event, and updates its own records from the response. :::scalar-detail{title="Why fetch the appointment instead of reading it from the event?"} Appointments often change several times in quick succession. For example, a check in, dock assignment and load start can happen within a minute of each other. If each event carried a copy of the appointment, a delayed or retried event could overwrite newer data with older data. Fetching the appointment always gives you its current state, so it doesn't matter what order events arrive in or whether one is delivered twice. This means: - **Treat the event as a signal to refresh, not as the change itself.** Read `status`, times, dock, references and other fields from the fetched appointment. - **The fetched appointment may already reflect later changes.** If you receive `APPOINTMENT_CHECK_IN` and fetch the appointment a moment later, it may already be checked out. - **To find out what changed, compare the fetched appointment with your stored copy.** The event doesn't say which fields changed. ::: ## Payload ```json { "id": "6f1c2a7e-9b3d-4c1f-8e2a-5d7b9c0e1f23", "facility": "2aae24c7-438d-473f-aba8-7793b7efdec3", "facility_appointment": "0bc8eae3-2e91-43ef-bd4a-164c76618942", "created_at": "2025-01-08T15:04:05.123456+00:00", "event_category": "APPOINTMENT_CHECK_IN" } ``` | Field | Description | | --- | --- | | `id` | Unique ID of the event. Use it to ignore duplicate deliveries. | | `facility` | ID of the `Facility` the appointment belongs to. | | `facility_appointment` | ID of the `FacilityAppointment`. Pass it as `id` to [Get FacilityAppointment](https://developers.getconduit.ai/api-docs#tag/default/post/conduit.v1.get_facility_appointment). | | `created_at` | When the event happened, as an ISO 8601 date-time in UTC. This is not when it was delivered. | | `event_category` | What happened. See [Event categories](#event-categories). | ## Event categories Conduit sets which event categories your endpoint receives when we set up your webhooks. Let us know if you only want some of them. One action can produce more than one event. For example, editing an appointment's dock and its scheduled time together sends both `APPOINTMENT_INFO_UPDATED` and `APPOINTMENT_FACILITY_RESCHEDULED`. :::scalar-detail{title="Booking and confirmation"} | Event | Sent when | Status afterwards | | --- | --- | --- | | `APPOINTMENT_REQUESTED` | A carrier requests an appointment on the Conduit scheduling page or through [Request FacilityAppointment](https://developers.getconduit.ai/api-docs#tag/default/post/conduit.v1.request_facility_appointment), and the facility must approve it. | `Requested` | | `APPOINTMENT_CREATED` | An appointment is booked without needing approval. This happens when:
- facility staff book it in Conduit
- a carrier books it on the scheduling page or through the API at a facility that confirms bookings automatically
- a connected integration creates it
- facility staff rebook an appointment to another facility (the event is for the new appointment)

Appointments generated from a recurring series don't send this event. | `Scheduled` | | `APPOINTMENT_CONFIRMED` | A requested appointment is confirmed. This happens when:
- facility staff approve a request
- a reschedule request is approved by the facility or the carrier

When a reschedule is approved, the scheduled time has changed, so re-read `scheduled_start_time` and `scheduled_end_time`. | `Scheduled` | | `APPOINTMENT_DECLINED` | Facility staff decline a requested appointment or work-in. | `Request Declined` | | `WORK_IN_CREATED` | Facility staff add a work-in for a truck that is already on site. The appointment is created already checked in, so no separate check in event is sent. | `Checked In` | ::: :::scalar-detail{title="Check in and check out"} | Event | Sent when | Status afterwards | | --- | --- | --- | | `DRIVER_CHECKED_IN` | The driver checks themselves in at a kiosk or on their phone. If the driver adds a work-in that wasn't booked, this is the first event you'll receive for that appointment. Its status is `Requested` until the facility confirms or declines it. | `Checked In` | | `APPOINTMENT_CHECK_IN` | Facility staff check the appointment in, change its check in time, or undo the check in. | `Checked In`, or the previous status if undone | | `APPOINTMENT_CHECKED_OUT` | Facility staff check the appointment out, change its check out time, or undo the check out. | `Checked Out`, or the previous status if undone | Undoing a check in or check out sends the same event as the original action. To tell them apart, check whether `checked_in_at` or `checked_out_at` on the fetched appointment is empty. ::: :::scalar-detail{title="Changes to an appointment"} | Event | Sent when | | --- | --- | | `APPOINTMENT_INFO_UPDATED` | Details on the appointment change. This includes:
- dock or pick trailer assignment
- notes
- carrier, shipper, receiver, booker or customer details
- driver, tractor, trailer and seal details
- quantity and units
- references and orders
- load types
- tags
- custom fields

Changes can come from facility staff, from the carrier on the scheduling page, from [Update FacilityAppointment Order](https://developers.getconduit.ai/api-docs#tag/default/post/conduit.v1.updated_facility_appointment_order), from [Update FacilityAppointment Customer](https://developers.getconduit.ai/api-docs#tag/default/post/v1/update_facility_appointment_customer), or from a connected integration. Some actions, like assigning a dock, send this event even if the value didn't change. | | `APPOINTMENT_FACILITY_RESCHEDULED` | Facility staff move a scheduled appointment to a new time. | | `APPOINTMENT_CARRIER_RESCHEDULED` | A carrier moves an appointment to a new time on the scheduling page at a facility that confirms reschedules automatically. If the facility must approve the new time, you'll receive `APPOINTMENT_CONFIRMED` once it's approved instead. | | `APPOINTMENT_ETA_UPDATED` | A carrier updates the appointment's ETA on the scheduling page or through [Update FacilityAppointment ETA](https://developers.getconduit.ai/api-docs#tag/default/post/v1/update_facility_appointment_eta). It is sent even if the ETA didn't change. ETA changes made by facility staff send `APPOINTMENT_INFO_UPDATED` instead. | | `ETA_UPDATE_REQUESTED` | Conduit emailed the carrier asking for an ETA, because the appointment is past its scheduled time with no check in and no ETA. | | `APPOINTMENT_ATTACHMENT_CREATED` | A file is attached to the appointment by facility staff, the carrier, the driver over chat, or Conduit, such as a signed document. Files uploaded during driver check in or with a booking request don't send this event. Use [List FacilityAppointment Attachments](https://developers.getconduit.ai/api-docs#tag/default/post/v1/list_facility_appointment_attachments) to get the files. | | `APPOINTMENT_ATTACHMENT_DELETED` | A file is removed from the appointment. | ::: :::scalar-detail{title="Cancellation"} | Event | Sent when | Status afterwards | | --- | --- | --- | | `APPOINTMENT_CANCELLED` | The appointment is cancelled by facility staff, through [Cancel FacilityAppointment](https://developers.getconduit.ai/api-docs#tag/default/post/v1/cancel_facility_appointment), by the carrier on the scheduling page, or by a connected integration. | `Cancelled` or `Carrier Cancelled` | | `APPOINTMENT_CARRIER_CANCELLED` | The carrier cancels the appointment. | `Carrier Cancelled` | | `APPOINTMENT_LOAD_REJECTED` | Facility staff reject the load. This can happen after check in. | `Load Rejected` | | `APPOINTMENT_AUTO_CANCELLED` | Conduit cancels a no-show appointment using the facility's auto-cancel rules, or a connected integration removes the shipment. | `Auto Cancelled` | To find out why an appointment was cancelled, read `cancelled_reason` and `cancelled_note` on the fetched appointment rather than relying on the event category. ::: ## Setup 1. Create an `HTTPS` endpoint that accepts `POST` requests with a `JSON` body and returns a `200`. 2. Test the endpoint with the sample payload above. 3. Deploy the endpoint so that it is publicly accessible. 4. Contact us at with your endpoint URL and the event categories you want. We'll send you your signing secret. ## Receiving events :::scalar-callout{type="warning"} Return a `200` as soon as you've verified and recorded the event, before doing any other work like fetching the appointment or updating your database. Conduit waits up to 45 seconds for a response. Conduit only treats a `200` as success. Any other response, including other `2xx` codes like `201` or `204`, is treated as a failure and retried. ::: We recommend handling each event like this: 1. [Verify the signature](#verification). Reject the request if it doesn't match. 2. If you've already processed an event with the same `id`, return `200` and stop. 3. Store the event or put it on a queue, then return `200`. 4. In the background, fetch the appointment and update your system. ### Retries and ordering If your endpoint doesn't return a `200`, Conduit retries the event a few times over the next several minutes, then keeps retrying periodically for up to 24 hours. After that the event is dropped. Endpoints that fail consistently for 7 days will be turned off until we can get in contact with you. Because of retries: - **You may receive the same event more than once.** Use `id` to ignore duplicates. - **Events may arrive late or out of order.** Use `created_at` for when the event happened, and fetch the appointment for its current state. ## Verification Each webhook includes a `Conduit-Signature` header so you can confirm it came from Conduit. The signature is an `HMAC-SHA256` of the request, signed with your signing secret. ``` Conduit-Signature: t=1683607883;v0=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd ``` ### How to verify 1. **Read the timestamp and signature from the header.** Split the header on `;`, then split each part on the first `=`. `t` is the Unix timestamp, in seconds, when the request was signed. `v0` is the signature. 2. **Build the signed payload.** Join the timestamp and the raw request body: `{t}{raw body}`, with nothing in between. Use the body exactly as received. Parsing the `JSON` and serializing it again can change spacing and break the signature. 3. **Compute the expected signature.** Calculate an `HMAC-SHA256` of the signed payload, using your signing secret as the key, and hex-encode it. 4. **Compare the signatures.** Compare the expected signature with `v0` using a constant-time comparison. If they match, check that `t` is within your tolerance of the current time, for example 5 minutes, to protect against replayed requests. Each retry is signed again with a new timestamp, so retried events still pass a timestamp check. ### Examples :::scalar-detail{title="Python"} ```python import hashlib import hmac import time def is_valid_conduit_signature(raw_body: bytes, signature_header: str, signing_secret: str, tolerance_seconds: int = 300) -> bool: parts = dict(part.split("=", 1) for part in signature_header.split(";")) timestamp = parts["t"] signature = parts["v0"] signed_payload = timestamp.encode() + raw_body expected_signature = hmac.new(signing_secret.encode(), signed_payload, hashlib.sha256).hexdigest() if not hmac.compare_digest(expected_signature, signature): return False return abs(time.time() - int(timestamp)) <= tolerance_seconds ``` ::: :::scalar-detail{title="Node.js"} ```javascript const crypto = require("crypto"); function isValidConduitSignature(rawBody, signatureHeader, signingSecret, toleranceSeconds = 300) { const parts = Object.fromEntries( signatureHeader.split(";").map((part) => { const separatorIndex = part.indexOf("="); return [part.slice(0, separatorIndex), part.slice(separatorIndex + 1)]; }) ); const expectedSignature = crypto .createHmac("sha256", signingSecret) .update(parts.t + rawBody) .digest("hex"); const expected = Buffer.from(expectedSignature); const received = Buffer.from(parts.v0 ?? ""); if (expected.length !== received.length || !crypto.timingSafeEqual(expected, received)) { return false; } return Math.abs(Date.now() / 1000 - Number(parts.t)) <= toleranceSeconds; } ``` ::: :::scalar-detail{title="Java"} Requires Java 17 or later. ```java import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.time.Instant; import java.util.HashMap; import java.util.HexFormat; import java.util.Map; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; public final class ConduitWebhookVerifier { public static boolean isValidConduitSignature(byte[] rawBody, String signatureHeader, String signingSecret, long toleranceSeconds) throws Exception { Map parts = new HashMap<>(); for (String part : signatureHeader.split(";")) { String[] keyValue = part.split("=", 2); if (keyValue.length == 2) { parts.put(keyValue[0], keyValue[1]); } } String timestamp = parts.get("t"); String signature = parts.get("v0"); if (timestamp == null || signature == null) { return false; } Mac mac = Mac.getInstance("HmacSHA256"); mac.init(new SecretKeySpec(signingSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256")); mac.update(timestamp.getBytes(StandardCharsets.UTF_8)); String expectedSignature = HexFormat.of().formatHex(mac.doFinal(rawBody)); if (!MessageDigest.isEqual(expectedSignature.getBytes(StandardCharsets.UTF_8), signature.getBytes(StandardCharsets.UTF_8))) { return false; } return Math.abs(Instant.now().getEpochSecond() - Long.parseLong(timestamp)) <= toleranceSeconds; } } ``` ::: :::scalar-detail{title="C#"} Requires .NET 5 or later. ```csharp using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; public static class ConduitWebhookVerifier { public static bool IsValidConduitSignature(byte[] rawBody, string signatureHeader, string signingSecret, long toleranceSeconds = 300) { var parts = new Dictionary(); foreach (var part in signatureHeader.Split(';')) { var keyValue = part.Split('=', 2); if (keyValue.Length == 2) { parts[keyValue[0]] = keyValue[1]; } } if (!parts.TryGetValue("t", out var timestamp) || !parts.TryGetValue("v0", out var signature)) { return false; } var signedPayload = Encoding.UTF8.GetBytes(timestamp).Concat(rawBody).ToArray(); using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(signingSecret)); var expectedSignature = Convert.ToHexString(hmac.ComputeHash(signedPayload)).ToLowerInvariant(); if (!CryptographicOperations.FixedTimeEquals(Encoding.UTF8.GetBytes(expectedSignature), Encoding.UTF8.GetBytes(signature))) { return false; } return long.TryParse(timestamp, out var timestampSeconds) && Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - timestampSeconds) <= toleranceSeconds; } } ``` ::: # Importing Orders, Loads and Shipments ## Overview Import the orders, loads and shipments you expect at your facilities so Conduit can use them when appointments are booked. :::scalar-callout{type="info"} Conduit calls each of these records an **order**, but an order can represent anything carriers book against in your system: a purchase order, sales order, load or shipment. This guide and the API use "order" for all of them. ::: Importing your orders lets Conduit: - **Validate reference IDs.** Carriers can only book with a PO#, SO#, load number, shipment ID or other reference ID that matches one of your orders. - **Fill in appointment details.** Carrier, shipper or receiver, customer, items and load types come from the order instead of being typed in by hand. - **Hold appointments until an order is ready.** Conduit doesn't offer appointment times before an order's earliest scheduled start time. Orders usually come from your TMS, WMS or ERP. You can send them as a CSV file or one at a time through the REST API, and we can build custom integrations for other sources. ### Choosing what to import Import one order for each thing carriers book appointments against, and use the ID carriers and drivers will have on hand as its reference ID. For example: | If carriers book by | Import each | Reference ID | | --- | --- | --- | | Purchase order | Purchase order | PO number | | Sales order | Sales order | SO number | | Load | Load | Load number | | Shipment | Shipment | Shipment ID | If carriers might quote a different ID for the same order, such as a BOL number or your system's internal ID, add it as the [external reference ID](#fields) or a [custom reference](#custom-references). Conduit matches those too. ## How orders are used ### Matching reference IDs to orders When a carrier, driver or facility staff member enters a reference ID, such as a PO number, Conduit looks for a matching order at that facility. It checks every ID you've given the order, not just its main reference ID. Once a reference ID matches, the appointment is linked. An appointment can include several orders, and an order can be included on more than one appointment. ### Reference ID validation Facilities can require carriers to book with a reference ID that matches one of your orders. This stops appointments from being booked against orders that don't exist. Validation can be turned on separately for inbound and outbound appointments, and the facility can choose how the reference ID field is labelled, such as "PO Number". Contact us to change these settings. If you book appointments from your own system, use [Validate Reference Ids](https://developers.getconduit.ai/api-docs#tag/default/post/conduit.v1.validate_reference_ids) to check reference IDs before booking. ### Filling in appointment details When a reference ID matches an order, Conduit fills in the appointment's details, such as the carrier, shipper or receiver, customer and load types, from the order. Carriers and facility staff don't have to type them in, and they match what's in your system. When you book through [Request FacilityAppointment](https://developers.getconduit.ai/api-docs#tag/default/post/conduit.v1.request_facility_appointment), include the appointment's details in the request. Changing an order after an appointment is booked doesn't update the appointment. ### Earliest scheduled start time If an order can't be picked up or delivered before a certain date, such as a ready-by date, give it an earliest scheduled start time. Conduit won't offer appointment times before it. If you book appointments from your own system, choose a time from [Get Facility Availability](https://developers.getconduit.ai/api-docs#tag/default/post/conduit.v1.get_facility_availability) so the earliest scheduled start time is respected. ## Fields | Field | CSV column | REST API field | Custom integration | Description | Required | | --- | --- | --- | --- | --- | --- | | Reference ID | `Reference ID` | `reference_id` | ✓ | The ID carriers and drivers use for the order, such as a PO#, SO#, load number or shipment ID. | Yes | | Facility ID | `Facility ID` | `facility_id` | ✓ | The facility the order belongs to, as returned by [List Facilities](https://developers.getconduit.ai/api-docs#tag/default/post/v1/list_facilities). | Yes | | Direction | `Direction` | `type` | ✓ | `Inbound` or `Outbound`. Leave it blank if the order can go either way. | CSV: No
API: Yes | | External Reference ID | `External Reference ID` | `external_reference_id` | ✓ | Another ID carriers might use for the order, such as your system's internal ID. | No | | Load Type | `Load Type` | `load_type_name` | ✓ | A load type set up for the facility, such as `Dry Van`. | No | | Earliest Scheduled Start Time | `Earliest Scheduled Start Time` | `earliest_scheduled_start_time` | ✓ | The earliest date and time the order can be booked. | No | | Item IDs | `Item IDs` | `item_ids` | ✓ | What's in the order, such as SKUs or item numbers. | No | | Shipper Receiver | `Shipper Receiver` | `shipper_receiver` | ✓ | The shipper for inbound orders, or the receiver for outbound orders. | No | | Carrier | `Carrier` | `carrier` | ✓ | The carrier for the order. | No | | Carrier SCAC | `Carrier SCAC` | `carrier_scac` | ✓ | The carrier's SCAC code. | No | | Carrier Emails | `Carrier Emails` | — | ✓ | The carrier's email addresses, separated by commas. Not available through the REST API. | No | | Customer | `Customer` | `customer` | ✓ | The customer the order is for, commonly used by 3PLs. | No | | Notes | `Notes` | `notes` | ✓ | Notes to show in Conduit. | No | | Custom references | One column per reference type | `order_reference_types` | ✓ | Other IDs set up for your organization. See [Custom references](#custom-references). | No | ### Formatting tips - **Dates and times:** use ISO 8601 with a time zone offset, for example `2025-01-08T08:00:00-08:00`. - **Direction:** write `Inbound` or `Outbound` with a capital letter. - **Facility IDs:** copy them exactly as Conduit returns them. ### Custom references If your orders have more than one ID carriers might use, such as a BOL number alongside a PO# or load number, Conduit can set up custom references for your organization. Carriers and drivers can then find an order by any of them. Contact us at to set them up. ## Sending orders ### Custom integrations Conduit can receive orders straight from your systems through: - Direct integrations with your TMS, WMS or ERP - CSV files delivered over SFTP - EDI Contact us at to discuss a custom integration. You can also send orders yourself with a CSV upload or the REST API. ### CSV upload Upload a CSV file to [Upload Orders](https://developers.getconduit.ai/api-docs#tag/default/post/conduit.v1.upload_facility_orders). - **Columns:** include `Reference ID` and `Facility ID`, plus any other columns from the [Fields](#fields) table. Column names aren't case-sensitive. - **Facilities:** one file can include orders for several facilities. - **Format:** save the file as UTF-8 without a byte order mark, and don't include blank lines. If any row has a problem, nothing in the file is saved and the response explains what to fix. :::scalar-detail{title="Example CSV"} This example includes a purchase order, a sales order, a load and a shipment: ```csv Reference ID,External Reference ID,Facility ID,Direction,Load Type,Earliest Scheduled Start Time,Item IDs,Shipper Receiver,Carrier,Carrier Emails,Customer,Notes PO-10045,ERP-55821,0db07caf-5005-4144-a983-e210c96cd451,Inbound,Dry Van,2025-01-08T08:00:00-08:00,"SKU-1, SKU-2",Sierra Bottling,Ftl Trucks,"dispatch@ftltrucks.com,ops@ftltrucks.com",Globex,Deliver to dock 4 SO-20981,,0db07caf-5005-4144-a983-e210c96cd451,Outbound,,,SKU-3,Acme Foods,,,, LOAD-58213,TMS-88120,0db07caf-5005-4144-a983-e210c96cd451,Inbound,,,,Sierra Bottling,Ftl Trucks,,,Mixed pallets from two POs SHP-4471,,0db07caf-5005-4144-a983-e210c96cd451,Outbound,,2025-01-10T06:00:00-08:00,,Acme Foods,,,, ``` You can also download complete examples: - [All optional fields included](https://conduit-django-frontend-production.s3.us-east-2.amazonaws.com/docs/Full+Example+-+Orders.csv) - [Required fields only](https://conduit-django-frontend-production.s3.us-east-2.amazonaws.com/docs/Minimal+Example+-+Orders.csv) ::: :::scalar-callout{type="info"} **Full and partial uploads** By default, each upload replaces the orders for every facility in the file. Orders that aren't in the file are removed, so always send the complete list of open orders. Facilities that aren't in the file, and appointments that are already booked, aren't affected. If you'd rather send only new and changed orders, Conduit can set up partial uploads for your organization instead. Contact us at to discuss. ::: ### REST API To send one order at a time, use [Create (or Update) Order](https://developers.getconduit.ai/api-docs#tag/default/post/conduit.v1.create_facility_order). If the facility already has an order with the same reference ID, it's replaced, so send every field each time. # SSO ## Overview Conduit offers flexible Single Sign-On (SSO) implementation options, allowing you to require SSO authentication for either your entire organization or specific users based on your security requirements. Currently, SAML protocol is fully supported, with OpenID Connect (OIDC) integration scheduled for deployment in the near future. For SAML integration instructions, please reference the guide below. Upon SSO activation for your organization, users will automatically be directed to the dedicated SSO authentication portal: https://getconduit.ai/sso/login/ ## SAML Please contact Conduit's engineering team at solutions@getconduit.ai to initiate SSO implementation via SAML for your organization. You can provide your Identity Provider (IdP) federation metadata document (XML file or URL), which contains all of the fields below, or provide the individual fields directly: | Parameter | Description | Required | |-----------|-------------|----------| | SAML signing certificate (X.509) | Public certificate used to verify the signature on SAML assertions. | Required | | IdP Entity ID / Issuer | Unique identifier of your Identity Provider. | Required | | Sign-In URL | IdP Single Sign-On (SSO) endpoint where authentication requests are sent. | Required | | Sign-Out URL | IdP Single Logout (SLO) endpoint used to terminate the session. | Optional | Conduit's complete SAML configuration parameters can be found in the sections below. ## SAML Configuration Parameters Please configure your Identity Provider (IdP) with the following parameters for the environment you are configuring. ### Production | Parameter | Value | |-----------|-------| | Entity ID / Issuer | `getconduit.ai` | | Sign-In URL | `https://getconduit.ai/sso/login/` | | Assertion Consumer Service (ACS) URL | `https://getconduit.ai/sso/acs/` | | Binding Method | HTTP-POST | | NameID Format | Email Address (do not include name format) | ### UAT (optional) | Parameter | Value | |-----------|-------| | Entity ID / Issuer | `uat.getconduit.ai` | | Sign-In URL | `https://uat.getconduit.ai/sso/login/` | | Assertion Consumer Service (ACS) URL | `https://backend-uat.getconduit.ai/sso/acs/` | | Binding Method | HTTP-POST | | NameID Format | Email Address (do not include name format) | ## Required Attributes Conduit requires the following user attributes to be included in the SAML assertion: | Conduit Attribute | IdP Attribute | |-------------------|---------------| | http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress | email | ### Okta | Name | Name format | Value | |------|-------------|-------| | emailAddress | Unspecified | user.email |