Freight Invoice Processing and ERP Synchronization

Overview

This scenario demonstrates the best practices on how to get freight invoice data from the Shipwell platform into your ERP (Enterprise Resource Planning) system or another system [i.e. FMS (Financial Management System), accounting systems, etc.] and keep both systems synchronized when processing freight invoices. The diagram below (click to view a larger version) is an overview of the process that ensures that the systems are always up-to-date with shared invoice amounts and statuses.

Freight Invoice Processing - Recommended Approach

Steps

1. Authenticate and Receive API Token

Authenticate to the API using these steps.

Note

Authorization HTTP headers in API requests, e.g. Authorization: YOUR_AUTHORIZATION_HEADER, typically take the form of Authorization: Token <user-token>. For more information on API authentication, navigate to the Authenticate documentation.

2. Subscribe to Freight Invoice-Related Events in a Webhook

Receive notifications when freight invoices are generated (typically received from the carrier or service provider or sent if you are a carrier or provider) or when a freight invoice changes status by subscribing to webhook events.

Subscribe to the particular webhook events outlined in the code samples below. For more information on webhook payloads, click here.

Tip

If you are not familiar with events and webhooks in the Shipwell platform, learn more here.

Example webhook subscription request
curljavascriptpythonjava
Copy
Copied
curl -i -X POST \
  'https://sandbox-api.shipwell.com/webhooks' \
  -H 'Authorization: YOUR_AUTHORIZATION_HEADER' \
  -H 'Content-Type: application/json' \
  -d '{
        "status": "ENABLED",
        "url": "https://example.com/your-endpoint-url",
        "enabled_events": [
            "freight_invoice.received",
            "freight_invoice.received.status_updated",
            "freight_invoice.sent",
            "freight_invoice.sent.status_updated"
        ],
        "event_version": 1,
        "error_contact_email": "jane.doe@example.com"
}'
Copy
Copied
const payload = {
  "status": "ENABLED",
  "url": "https://example.com/your-endpoint-url",
  "enabled_events": [
      "freight_invoice.received",
      "freight_invoice.received.status_updated",
      "freight_invoice.sent",
      "freight_invoice.sent.status_updated"
  ],
  "event_version": 1,
  "error_contact_email": "jane.doe@example.com"
};

const basePath = "";
const host = "sandbox-api.shipwell.com";
const targetUrl = `https://${host}${basePath}/webhooks`;
const resp = await fetch(
  targetUrl,
  {
    method: "POST",
    headers: {
      "Authorization": "YOUR_AUTHORIZATION_HEADER",
      "Content-Type": "application/json"
    },
    body: JSON.stringify(payload)
  }
);

const data = await resp.json();
console.log(data);
Copy
Copied
import requests

base_path = ""
host = "sandbox-api.shipwell.com"
target_url = (
    "https://"
    + host
    + base_path
    + "/webhooks/"
)

headers = {
    "Authorization": "YOUR_AUTHORIZATION_HEADER",
    "Content-Type": "application/json",
}

payload = {
  "status": "ENABLED",
  "url": "https://example.com/your-endpoint-url",
  "enabled_events": [
      "freight_invoice.received",
      "freight_invoice.received.status_updated",
      "freight_invoice.sent",
      "freight_invoice.sent.status_updated"
  ],
  "event_version": 1,
  "error_contact_email": "jane.doe@example.com"
}

response = requests.post(target_url, headers=headers, json=payload)
data = response.json()
print(data)
Copy
Copied
import java.io.IOException;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

OkHttpClient client = new OkHttpClient();
String basePath = "";
String host = "sandbox-api.shipwell.com";
String targetUrl = "https://" +
  host +
  base_path +
  "/webhooks/";

String requestBody = "{\"status\": \"ENABLED\", \"url\": \"https:\/\/example.com\/your-endpoint-url\", \"enabled_events\": [ \"freight_invoice.received\", \"freight_invoice.received.status_updated\", \"freight_invoice.sent\", \"freight_invoice.sent.status_updated\ "], \"event_version\": 1, \"error_contact_email\": \"jane.doe@example.com\"}";

Request request = new Request.Builder()
  .url(targetUrl)
  .post(requestBody)
  .header("Authorization", "YOUR_AUTHORIZATION_HEADER")
  .header("Content-Type", "application/json")
  .build();

try (Response response = client.newCall(request).execute()) {
  if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
  response.body().string();
}
Example webhook subscription response
Copy
Copied
{
    "id": "01J7EDHQTV6C4F2RGAQ4MF2515",
    "status": "ENABLED",
    "created_at": "2025-11-26T19:39:49.951432Z",
    "url": "https://example.com/your-endpoint-url",
    "secret": "...",
    "enabled_events": [
        "freight_invoice.received",
        "freight_invoice.received.status_updated",
        "freight_invoice.sent",
        "freight_invoice.sent.status_updated"
    ],
    "include_updated_object": false,
    "event_version": 1,
    "error_contact_email": "jane.doe@example.com",
    "custom_data": null,
    "resource_type": "webhook",
    "self_link": "https://sandbox-api.shipwell.com/webhooks/01J7EDHQTV6C4F2RGAQ4MF2515"
}

3. Process Freight Invoice Status Changes Delivered via Webhook

Tip

View information about the freight invoice statuses and when they occur here.

Handle freight_invoice.received Webhook Payload

When a freight invoice is initially received by Shipwell from the carrier or service provider, the freight_invoice.received webhook payload will be delivered via an HTTP POST (over HTTPS) to your webhook endpoint(s) that subscribe to the event. This occurs before the Shipwell AI and ML-based invoice First Pass Match is performed.

Copy
Copied
{
  "id": "01J6WNKNW0RA12Q39S1TS2HW15",
  "occurred_at": "2025-09-08T19:25:58.522688+00:00",
  "source": {
    "user_id": "6dd592ce-b09e-467b-b42b-bc11bedcf4c2",
    "company_id": "905f4da3-70bc-4884-8f77-1ea9bdd183ac",
    "request_id": "00-66d762c4000000000987496b933edb70-dcb436687a53f4ed-01",
    "publishing_system": "settlements",
    "environment": "sandbox"
  },
  "event_name": "freight_invoice.received",
  "webhook_id": "01J6WN655FNEB7PAXT58SKJA24",
  "custom_data": null,
  "details": {
    "id": "01J6WNKN1BZTXEERAT7HATJ1K1",
    "notes": null,
    "due_date": "2025-10-09",
    "documents": [
      {
        "self_link": "https://example.com/documents/01J6WNKN1BZTXEERAT7HATJ1K1/custom-file-name_0KwmtZ_qhLKjm.pdf?abc=...",
        "resource_type": "BOL"
      }
    ],
    "self_link": "/freight-invoices/01J6WNKN1BZTXEERAT7HATJ1K1",
    "invoiceable": {
      "id": "6586aebf-e7b6-410e-ba6f-75d3de072ee7",
      "type": "V2_SHIPMENT",
      "references": [
        {
          "value": "SW2290892",
          "qualifier": "BOL_NUMBER"
        }
      ],
      "total_amount": null,
      "reference_number": "HUEW7C"
    },
    "total_amount": {
      "value": "3050.00",
      "currency": "USD"
    },
    "resource_type": "freight_invoice",
    "invoice_number": "123456",
    "invoice_source": "SHIPWELL_WEB",
    "service_provider_name": "Carrier Name"
  }
}

The invoiceable object in the webhook payload contains details about the shipment associated with the invoice. The property id in the invoiceable object is the shipment id.

Copy
Copied
    "invoiceable": {
      "id": "6586aebf-e7b6-410e-ba6f-75d3de072ee7",
      "type": "V2_SHIPMENT",
      "references": [
        {
          "value": "SW2290892",
          "qualifier": "BOL_NUMBER"
        }
      ],
      "total_amount": null,
      "reference_number": "HUEW7C"
    }

The details about the shipment may be retrieved by calling the GET /v2/shipments/{shipmentId}/ API endpoint (see API reference). Store or update as much or as little of the details about the invoice, invoice documents, or shipment as you need before the freight invoice changes status (you may also wait to store the details until a freight invoice status change occurs).

4. Update the ERP/FMS with Freight Invoice Details from Shipwell

When a freight invoice status changes, the freight_invoice.received.status_updated event is triggered and the freight_invoice.received.status_updated webhook payload for that status change event will be delivered via an HTTP POST (over HTTPS) to your webhook endpoint(s) that subscribe to the event. Depending on your needs, inspect the webhook payloads to see if the freight invoice is in any of these states: PASSED, APPROVED, or SCHEDULED.

Important
  • Freight invoices may change status several times in the lifecycle of an invoice and not every status needs to be stored in your ERP or external systems.
  • Inspect freight_invoice.received.status_updated webhook payloads for the freight invoice status of PASSED , APPROVED , or SCHEDULED in the new_status property of the details object.
  • If needed, the details about the shipment may be retrieved by calling the GET /v2/shipments/{shipmentId}/ API endpoint (see API reference ) where the invoiceable.id property represents the shipmentId/shipment_id .
Example freight_invoice.received.status_updated webhook payload
Copy
Copied
{
  "id": "01J6WNRJ3S4W17ZDB2241QQJAN",
  "occurred_at": "2025-09-08T19:28:38.516558+00:00",
  "source": {
    "user_id": null,
    "company_id": null,
    "request_id": "00-66d76363000000002bfdfeca35e3e591-9aa4b9e05b848a38-01",
    "publishing_system": "settlements",
    "environment": "sandbox"
  },
  "event_name": "freight_invoice.received.status_updated",
  "webhook_id": "01J6WN655FNEB7PAXT58SKJA24",
  "custom_data": null,
  "details": {
    "id": "01J6WNKN1BZTXEERAT7HATJ1K1",
    "self_link": "/freight-invoices/01J6WNKN1BZTXEERAT7HATJ1K1",
    "new_status": "PASSED",
    "old_status": "DISPUTED",
    "invoiceable": {
      "id": "6586aebf-e7b6-410e-ba6f-75d3de072ee7",
      "type": "V2_SHIPMENT",
      "reference_number": "HUEW7C"
    },
    "resource_type": "freight_invoice"
  }
}

5. Update the Freight Invoice Status in Shipwell on Invoice Payment from your ERP/FMS

When a freight invoice is SCHEDULED or PAID in your ERP or financial management system (FMS), update the freight invoice status for that particular freight invoice in Shipwell using these steps to stop accruing freight charges (aka finalize the freight invoice). This ensures that the freight invoice statuses in your financial or ERP system and Shipwell are synchronized.

Note

Depending on your workflow(s) in your ERP or financial management systems, write back the freight invoice payment status to Shipwell using one of the following approaches:

  • Mirrored
    • The freight invoice status is mirrored as SCHEDULED and/or PAID in your ERP and Shipwell. Shipwell receives either both of these status changes from your systems or only receives the PAID status change.
  • Mapped ( SCHEDULED Status Mapped To PAID )
    • When a freight invoice payment is scheduled in the ERP or financial management system, then Shipwell freight invoice status is updated as PAID as PAID (SHIPWELL) = SCHEDULED (ERP) instead of mapping to SCHEDULED (SHIPWELL) = SCHEDULED (ERP) and PAID (SHIPWELL) = PAID (ERP) .

Settlements Freight Invoice Status Update On Scheduled or Paid Diagram

Copyright © Shipwell 2024. All right reserved.