Table of Contents

Shipment CRUD APIs

External systems may need to create shipments, update cargo information or maintain references after a booking has been received. The FMS shipment CRUD APIs provide dedicated resources for these operations instead of treating every change as a new incoming integration message. CRUD means Create, Read, Update and Delete.

Important

Planned for V29, with a planned release date of 26/10/2026*. This functionality has not yet been merged into Develop. The scope below reflects the current implementation under development, not a generally available release. Endpoint names and behavior may change before delivery. Confirm availability and the final API contract with your implementation consultant before building a production integration.

* Planned date; availability depends on deployment. The application release V29 is separate from the API contract version v2.0.

Before you start

  • Confirm that the deployed Transportation extension includes these APIs.
  • Configure OAuth 2.0 authorization and grant the integration the permissions needed for its shipment operations.
  • Identify the environment and company ID. Maintain shipment number series, customers, order types and status templates.
  • Use a sandbox to test creation, partial updates, explicit clearing, status changes and deletion, including blocked statuses and related records.
Note

The examples below are illustrative, source-verified request and response shapes, not recordings from a running environment. Replace example customer numbers, reference codes and status codes with configured values. Generated numbers, IDs, defaults and ETags will differ. Response bodies are shortened for readability; additional properties and OData annotations can be returned.

Endpoint

For Business Central online, the custom API root is:

https://api.businesscentral.dynamics.com/v2.0/{tenantId}/{environmentName}/api/boltrics/transportation/v2.0

In the examples, {apiRoot} represents that complete URL, without a trailing slash. Replace {companyId} with the company GUID and {shipmentId}, {lineId} or {referenceId} with the resource's returned id. Use GUID values without braces in actual URLs. Resource IDs are not shipment numbers or line numbers.

For an on-premises installation, obtain the API base URL from your administrator; the publisher, group and API version remain boltrics/transportation/v2.0.

Read the deployed schema before mapping fields:

GET {apiRoot}/$metadata
Authorization: Bearer {accessToken}
Accept: application/xml

The metadata describes property types, enum values, navigation and bound actions. These are custom Boltrics APIs, not the Microsoft standard /api/v2.0 shipment resources.

Resources and navigation

All eight resource sets support GET, POST, PATCH and DELETE, subject to permissions, status restrictions and business validation:

  • shipments: shipment headers.
  • shipmentLines: cargo and equipment document lines.
  • documentAddresses: addresses associated with the shipment header.
  • documentReferences: shipment references.
  • documentParties: parties associated with the shipment header.
  • documentDetailLines: details associated with a shipment line.
  • documentSplitGoodsLines: split-goods records associated with a shipment line.
  • documentTariffNumbers: tariff numbers associated with a shipment line.

Each set is available at {apiRoot}/companies({companyId})/{resourceSet}. Individual records use {resourceSet}({id}).

Use the following navigation paths to access related records:

shipments({shipmentId})/shipmentLines
shipments({shipmentId})/documentAddresses
shipments({shipmentId})/documentReferences
shipments({shipmentId})/documentParties
shipmentLines({lineId})/documentDetailLines
shipmentLines({lineId})/documentSplitGoodsLines
shipmentLines({lineId})/documentTariffNumbers

Prefix each path with {apiRoot}/companies({companyId})/. For example, list the cargo details of a line with GET {apiRoot}/companies({companyId})/shipmentLines({lineId})/documentDetailLines.

For a standalone POST, supply the parent relationship:

  • shipmentLines: documentNumber, containing the existing shipment number.
  • documentAddresses: documentSystemId, containing the shipment GUID.
  • documentReferences and documentParties: relatedSystemId, containing the shipment GUID.
  • documentDetailLines, documentSplitGoodsLines and documentTariffNumbers: documentNumber and documentLineNumber, identifying the existing shipment line by its document number and numeric line number.

Navigation-based creation supplies the relationship from the parent. Other business fields still depend on the resource and configuration. parentSystemId is read-only on shipment lines; do not use it to create or reparent a line.

These APIs are restricted to shipments. Equipment details, record links and cost/revenue navigation are outside this API scope. Existing read-only APIs are not made writable by this change.

Request headers

Use these headers unless an operation states otherwise:

  • Authorization: Bearer {accessToken}: required for every request.
  • Accept: application/json: requests a JSON response.
  • Content-Type: application/json: required when sending a JSON body.
  • If-Match: {etag}: required for PATCH and DELETE. Copy the resource's current @odata.etag value from a preceding read, including its weak-validator prefix and quotation marks.

ETags protect against overwriting changes made by another user or integration. Read the record again if a concurrency conflict occurs; review the changes before retrying. The examples use {etag} as a placeholder, not a literal header value.

Shipment properties

Common properties used in the examples:

  • id (GUID, read-only): resource identity used in URLs.
  • number (string, read-only): shipment number generated from the configured number series.
  • sellToCustomerNumber (string): required when creating a shipment. The customer must exist.
  • sellToCustomerName (string, read-only): customer name derived by validation.
  • orderTypeCode (string): order type; can affect document defaults and number-series selection. Supply a configured value when required by your process.
  • externalDocumentNumber (string): external booking or document reference.
  • documentDate, orderDate, postingDate (date): dates in YYYY-MM-DD format.
  • statusTemplateCode, statusCode (string, read-only): workflow information. Use the status action rather than PATCH.
  • systemCreatedAt, systemModifiedAt (date/time, read-only): system audit timestamps.

The schema also exposes transport, address, dimension and attribute fields. Consult $metadata for the complete property list and types. Generated IDs, audit information, status and derived display properties are not directly writable.

List shipments

HTTP request

GET {apiRoot}/companies({companyId})/shipments

Request body

Do not supply a request body.

Example request

This example selects a small set of properties and filters by the external document number. URL-encode query values as required by your HTTP client.

GET {apiRoot}/companies({companyId})/shipments?$select=id,number,sellToCustomerNumber,externalDocumentNumber&$filter=externalDocumentNumber eq 'BOOK-1001'
Authorization: Bearer {accessToken}
Accept: application/json

Response

Successful requests return 200 OK and a collection in value. An empty result returns "value": []. If a response contains @odata.nextLink, follow that URL to retrieve the next page.

HTTP/1.1 200 OK
Content-Type: application/json
{
  "value": [
    {
      "@odata.etag": "W/\"sample-shipment-etag\"",
      "id": "11111111-1111-4111-8111-111111111111",
      "number": "SH000123",
      "sellToCustomerNumber": "C00010",
      "externalDocumentNumber": "BOOK-1001"
    }
  ]
}

Get a shipment

HTTP request and example

GET {apiRoot}/companies({companyId})/shipments({shipmentId})
Authorization: Bearer {accessToken}
Accept: application/json

Do not supply a request body.

Response

Successful requests return 200 OK and one shipment object, not a value collection.

HTTP/1.1 200 OK
Content-Type: application/json
{
  "@odata.etag": "W/\"sample-shipment-etag\"",
  "id": "11111111-1111-4111-8111-111111111111",
  "number": "SH000123",
  "sellToCustomerNumber": "C00010",
  "externalDocumentNumber": "BOOK-1001"
}

Create a shipment

HTTP request

POST {apiRoot}/companies({companyId})/shipments

Request body

Supply a JSON object containing sellToCustomerNumber and any other writable properties needed for your process. The shipment number is generated and document defaults are applied. Do not send generated identity or status fields.

Example request

POST {apiRoot}/companies({companyId})/shipments
Authorization: Bearer {accessToken}
Accept: application/json
Content-Type: application/json
{
  "sellToCustomerNumber": "C00010",
  "externalDocumentNumber": "BOOK-1001",
  "documentDate": "2026-10-26"
}

Response

Successful requests return 201 Created and the created shipment.

HTTP/1.1 201 Created
Content-Type: application/json
{
  "@odata.etag": "W/\"sample-shipment-etag\"",
  "id": "11111111-1111-4111-8111-111111111111",
  "number": "SH000123",
  "sellToCustomerNumber": "C00010",
  "externalDocumentNumber": "BOOK-1001",
  "documentDate": "2026-10-26"
}

Save the returned id for subsequent resource requests and number for standalone line creation.

Update a shipment

HTTP request

PATCH {apiRoot}/companies({companyId})/shipments({shipmentId})

Request body

Supply only the properties to change. Only supplied fields are revalidated. Omitted properties retain their values or are recalculated by normal validation of other fields. Sending "" explicitly requests a blank value; it is not the same as omitting the property and can fail validation.

Example request

PATCH {apiRoot}/companies({companyId})/shipments({shipmentId})
Authorization: Bearer {accessToken}
Accept: application/json
Content-Type: application/json
If-Match: {etag}
{
  "externalDocumentNumber": "BOOK-1001-REV"
}

Response

Successful requests return 200 OK and the updated shipment.

HTTP/1.1 200 OK
Content-Type: application/json
{
  "@odata.etag": "W/\"sample-updated-shipment-etag\"",
  "id": "11111111-1111-4111-8111-111111111111",
  "number": "SH000123",
  "sellToCustomerNumber": "C00010",
  "externalDocumentNumber": "BOOK-1001-REV"
}

Use the new ETag for the next update or deletion.

Delete a shipment

HTTP request and example

DELETE {apiRoot}/companies({companyId})/shipments({shipmentId})
Authorization: Bearer {accessToken}
If-Match: {etag}

Do not supply a request body.

Response

Successful requests return 204 No Content, with no response body.

HTTP/1.1 204 No Content
Warning

Deletion uses normal document processing and can delete related records. Status restrictions and related-record checks can block deletion. Test deletion behavior with representative data in a sandbox before enabling it in a production integration.

Omitting a line from a request does not delete it. Delete the intended resource explicitly.

Create a shipment line

HTTP request

Use navigation to create a line under an existing shipment:

POST {apiRoot}/companies({companyId})/shipments({shipmentId})/shipmentLines

Request body and example

This example creates a cargo line with a description. The parent relationship comes from the URL; the line number is generated. Additional fields can be required by your configuration.

POST {apiRoot}/companies({companyId})/shipments({shipmentId})/shipmentLines
Authorization: Bearer {accessToken}
Accept: application/json
Content-Type: application/json
{
  "type": "Cargo",
  "description": "Palletized spare parts"
}

Response

Successful requests return 201 Created and the created line.

HTTP/1.1 201 Created
Content-Type: application/json
{
  "@odata.etag": "W/\"sample-line-etag\"",
  "id": "22222222-2222-4222-8222-222222222222",
  "parentSystemId": "11111111-1111-4111-8111-111111111111",
  "documentNumber": "SH000123",
  "lineNumber": 10000,
  "type": "Cargo",
  "description": "Palletized spare parts"
}

For a standalone POST to shipmentLines, add "documentNumber": "SH000123" to the body. Do not send parentSystemId or lineNumber.

To read, update or delete this line, use shipmentLines({lineId}) with the same method, header and response conventions shown for shipments. For example, update only description with PATCH and the line's own current ETag. A line cannot be moved to another shipment by changing documentNumber.

Create a shipment reference

HTTP request

POST {apiRoot}/companies({companyId})/shipments({shipmentId})/documentReferences

Request body and example

Supply an existing referenceCode and the reference value. The code below is illustrative; replace it with one configured for your shipment process.

POST {apiRoot}/companies({companyId})/shipments({shipmentId})/documentReferences
Authorization: Bearer {accessToken}
Accept: application/json
Content-Type: application/json
{
  "referenceCode": "BOOKING",
  "reference": "BOOK-1001"
}

Response

Successful requests return 201 Created and the created reference.

HTTP/1.1 201 Created
Content-Type: application/json
{
  "@odata.etag": "W/\"sample-reference-etag\"",
  "id": "33333333-3333-4333-8333-333333333333",
  "relatedSystemId": "11111111-1111-4111-8111-111111111111",
  "referenceCode": "BOOKING",
  "reference": "BOOK-1001"
}

For standalone creation, use documentReferences and add relatedSystemId to the body. For later reads, updates or deletions, use documentReferences({referenceId}). Updating reference requires the reference's own ETag; its parent relationship and referenceCode cannot be changed by PATCH.

Change shipment status

Use the bound ChangeStatus action instead of writing statusCode. The action delegates to the FMS status engine, including configured checks and functions.

The action signature in the deployed $metadata determines its qualified URL and JSON parameter name. For the current implementation, invoke Microsoft.NAV.ChangeStatus with statusCode:

POST {apiRoot}/companies({companyId})/shipments({shipmentId})/Microsoft.NAV.ChangeStatus
Authorization: Bearer {accessToken}
Content-Type: application/json
{
  "statusCode": "READY"
}

Replace READY with an allowed target status from the shipment's status template. The implementation reports an updated action result when a transition occurs, or no action result when the shipment already has that status. Do not assume the response body contains a shipment object: read the shipment again after success to obtain its current status and ETag. The action's HTTP response behavior still needs verification in the deployed preview.

Errors and validation

Write operations retain normal table validation and status restrictions. A writable API does not mean that every field can be changed at every operational status.

When a request fails, inspect the HTTP status and the OData error.code and error.message properties. Error codes and messages depend on the failing validation; do not rely on one message for every failure.

  • Authentication or authorization failure: check token audience, expiry, environment access and permissions.
  • Unknown resource: check the company, resource name and GUID; do not substitute a shipment number for id.
  • Invalid business data: check the customer, order type, reference code, required fields and status restrictions.
  • Concurrency conflict: retrieve the current resource, review intervening changes and use its current ETag.

Do not blindly retry a failed or timed-out POST: first check whether a record was created. externalDocumentNumber is useful for lookup but is not an API idempotency key or a guarantee of uniqueness.

See also