ShipEngine.Contracts 1.4.0

dotnet add package ShipEngine.Contracts --version 1.4.0
                    
NuGet\Install-Package ShipEngine.Contracts -Version 1.4.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ShipEngine.Contracts" Version="1.4.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ShipEngine.Contracts" Version="1.4.0" />
                    
Directory.Packages.props
<PackageReference Include="ShipEngine.Contracts" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ShipEngine.Contracts --version 1.4.0
                    
#r "nuget: ShipEngine.Contracts, 1.4.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ShipEngine.Contracts@1.4.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ShipEngine.Contracts&version=1.4.0
                    
Install as a Cake Addin
#tool nuget:?package=ShipEngine.Contracts&version=1.4.0
                    
Install as a Cake Tool

ShipEngine.Contracts

Shared DTOs (Data Transfer Objects) and contracts for ShipEngine shipping services. This package provides all the data models needed to integrate with shipping APIs and services.

Installation

dotnet add package ShipEngine.Contracts

Package Contents

DTO Objects

  • AddressDTO - Shipping address representation (sender/recipient)
  • DTOShipmentObject - Complete shipment information
  • ShipmentDbObject - Database entity for shipment storage
  • LabelObject - Shipping label request/response data
  • RateObject - Shipping rate quotes and estimates (includes optional customs for international)
  • PackageObject - Package dimensions, weight, and details
  • TrackingDTOObject - Package tracking information
  • ImportDtos - Data import/export structures
  • UpdateShipmentDto - Shipment update requests

International Shipping (v1.2.0+)

  • DTOCustoms - Customs declaration for international shipments
  • DTOCustomsItem - Individual customs line items (description, quantity, value, HS code)
  • DTOMonetaryValue - Currency and amount for customs values

Enums

  • DTOCountry - ISO 3166 country codes (US, CA, GB, AU, DE, JP, MX, etc.)
  • DTOPackageContents - Customs package contents type (Merchandise, Documents, Gift, etc.)
  • DTONonDelivery - Non-delivery handling (ReturnToSender, TreatAsAbandoned)
  • DTOCurrency - Currency codes (USD, CAD, GBP, EUR, etc.)
  • AddressResidentialIndicator - Residential/commercial address indicator
  • DTOValidateAddress - Address validation options
  • ShipmentEnums - Shipment status and type enumerations
  • PackageSpecifications - Package type specifications

Utilities

  • StateDictionary - US state code lookups
  • CountryDictionary - ISO country code to name mappings
  • CountryAbbreviations - Country code mappings
  • VersionCompatibility - Library version checking

Usage Examples

Domestic Shipment

using ShipEngineShippingAPI.ClassLibrary.DTO_Objects;
using ShipEngineShippingAPI.ClassLibrary.Enums;

var address = new AddressDTO
{
    Name = "John Doe",
    AddressLine1 = "123 Main Street",
    CityLocality = "New York",
    StateProvince = "NY",
    PostalCode = "10001",
    CountryCode = DTOCountry.US,
    AddressResidentialIndicator = AddressResidentialIndicator.Residential
};

International Shipment with Customs

using ShipEngineShippingAPI.ClassLibrary.DTO_Objects;
using ShipEngineShippingAPI.ClassLibrary.Enums;

// Create label request with customs data
var labelRequest = new dtoLabelObject
{
    dtoShipToAddress = new AddressDTO
    {
        Name = "Jane Smith",
        AddressLine1 = "10 Downing Street",
        CityLocality = "London",
        StateProvince = "Greater London",
        PostalCode = "SW1A 2AA",
        CountryCode = DTOCountry.GB,
        Phone = "+44-20-7930-4832"
    },
    dtoShipmentPackage = packageDetails,
    serviceCode = "ups_worldwide_expedited",
    isInternational = true,
    customs = new DTOCustoms
    {
        Contents = DTOPackageContents.Merchandise,
        NonDelivery = DTONonDelivery.ReturnToSender,
        CustomsItems = new List<DTOCustomsItem>
        {
            new DTOCustomsItem
            {
                Description = "Handcrafted Poi",
                Quantity = 2,
                Value = new DTOMonetaryValue { Amount = 45.00m, Currency = DTOCurrency.USD },
                HarmonizedTariffCode = "9506.99",
                CountryOfOrigin = DTOCountry.US
            }
        }
    }
};

Label Response with Customs Form

// Response includes customs form URL for carriers like UPS
var response = await labelService.GetLabelAsync(labelRequest);

// For UPS international: separate customs form PDF
if (!string.IsNullOrEmpty(response.formUrl))
{
    Console.WriteLine($"Customs form: {response.formUrl}");
}

// For USPS international: customs printed on label
if (response.isInternational && string.IsNullOrEmpty(response.formUrl))
{
    Console.WriteLine("Customs declaration is on the shipping label");
}

International Rate Request with Customs (v1.4.0+)

Customs data is required for international rate quotes. The RateObjectDTO accepts the same DTOCustoms type used for label creation, so you can reuse the same customs-building logic for both rate lookups and label purchases.

using ShipEngineShippingAPI.ClassLibrary.DTO_Objects;
using ShipEngineShippingAPI.ClassLibrary.Enums;

var rateRequest = new RateObjectDTO
{
    dTOShipToAddress = new AddressDTO
    {
        Name = "Marie Dupont",
        AddressLine1 = "5 Rue Roland Barthes",
        CityLocality = "Paris",
        PostalCode = "75012",
        CountryCode = DTOCountry.FR,
        Phone = "838383838"
    },
    dTOShipmentPackage = new ShipmentPackageDTO
    {
        Weight = new DTOWeight { Value = 22, Unit = DTOWeightUnit.Ounce },
        Dimensions = new DTODimensions { Length = 6, Width = 6, Height = 4, Unit = DTODimensionUnit.Inch }
    },
    customs = new DTOCustoms
    {
        Contents = DTOPackageContents.Merchandise,
        NonDelivery = DTONonDelivery.ReturnToSender,
        CustomsItems = new List<DTOCustomsItem>
        {
            new DTOCustomsItem
            {
                Description = "Handcrafted Poi",
                Quantity = 2,
                Value = new DTOMonetaryValue { Amount = 45.00m, Currency = DTOCurrency.USD },
                HarmonizedTariffCode = "9506.99",
                CountryOfOrigin = DTOCountry.US
            }
        }
    }
};

API Response Format

All API endpoints return responses using the standard RFC 7807 ProblemDetails JSON format. This applies to both successful and error responses.

Successful Rate Response (HTTP 200)

When rates are found, the response includes the rates in the ReturnedRates extension field. It may also include Warnings, CorrectedAddress, and ResponseErrors when address validation detects issues.

Basic response (no warnings):

{
  "type": "Rates Found",
  "title": "Rates were found",
  "status": 200,
  "detail": "We found some results",
  "ReturnedRates": [
    {
      "shippingCarrier": "ups",
      "estimatedShippingDays": "1",
      "shippingPriceUSD": "6.65",
      "shippingService": "UPS® Ground",
      "packageType": "",
      "serviceCode": "ups_ground"
    },
    {
      "shippingCarrier": "stamps_com",
      "estimatedShippingDays": "5",
      "shippingPriceUSD": "6.21",
      "shippingService": "USPS Ground Advantage",
      "packageType": "package",
      "serviceCode": "usps_ground_advantage"
    }
  ]
}

Response with address warnings and corrected address:

The API validates the ship-to address and may return warnings when it detects potential issues, even if rates were successfully returned. It also returns a CorrectedAddress when ShipEngine modified the address (e.g., corrected postal code, standardized street name, added ZIP+4).

{
  "type": "Rates Found",
  "title": "Rates were found",
  "status": 200,
  "detail": "We found some results",
  "ReturnedRates": [
    {
      "shippingCarrier": "ups",
      "estimatedShippingDays": "1",
      "shippingPriceUSD": "8.42",
      "shippingService": "UPS® Ground",
      "packageType": "",
      "serviceCode": "ups_ground"
    }
  ],
  "Warnings": [
    "This address has been verified but some corrections were applied",
    "The postal code has been corrected to match the city/state"
  ],
  "CorrectedAddress": {
    "name": "John Doe",
    "addressLine1": "123 MAIN ST",
    "addressLine2": "APT 4B",
    "cityLocality": "SALEM",
    "stateProvince": "MA",
    "postalCode": "01970-3823",
    "countryCode": "US"
  },
  "ResponseErrors": [
    "stamps_com: Unable to get rates for this carrier"
  ]
}

Extension fields on success responses:

Field Type Always Present Description
ReturnedRates List<ShippingOptionsReturnedDTO> Yes The available shipping rates, sorted by price ascending
Warnings List<string> No Address validation warnings and carrier advisories. Present only when warnings exist
CorrectedAddress object No The corrected/standardized address from ShipEngine. Present when the address was modified during validation. Compare with the original to show "Did you mean...?" prompts
ResponseErrors List<string> No Top-level errors from ShipEngine (e.g., one carrier failed but another succeeded). Present only when partial errors occurred

Common warnings you may see:

Warning Meaning Recommended Action
This address has been verified but some corrections were applied Address is deliverable but was modified Show corrected address to user
The postal code has been corrected ZIP/postal code didn't match city/state Update postal code from CorrectedAddress
The street address was standardized Street name/format was cleaned up Informational — address is valid
The city/state were corrected based on postal code City or state didn't match the postal code Show corrected city/state to user
This address is a PO Box Address is a PO Box Some services (UPS) cannot deliver to PO Boxes
Address is a military address APO/FPO/DPO address Only USPS delivers to military addresses
Suite/apartment number is missing Multi-unit building without unit number Prompt user to add apartment/suite number

Parsing rates and warnings in C#:

using System.Text.Json;
using ShipEngineShippingAPI.ClassLibrary.DTO_Objects;

var response = await httpClient.GetAsync($"/GetRatesAsync?rateObject={encodedJson}");
var json = await response.Content.ReadAsStringAsync();

using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;

// Parse rates
if (root.TryGetProperty("ReturnedRates", out var ratesElement))
{
    var rates = JsonSerializer.Deserialize<List<ShippingOptionsReturnedDTO>>(
        ratesElement.GetRawText());

    foreach (var rate in rates)
    {
        Console.WriteLine($"{rate.shippingService}: ${rate.shippingPriceUSD} " +
            $"({rate.estimatedShippingDays} days)");
    }
}

// Check for address warnings
if (root.TryGetProperty("Warnings", out var warningsElement))
{
    var warnings = JsonSerializer.Deserialize<List<string>>(warningsElement.GetRawText());
    foreach (var warning in warnings)
    {
        Console.WriteLine($"⚠ Warning: {warning}");
    }
}

// Check for corrected address (show "Did you mean...?" to user)
if (root.TryGetProperty("CorrectedAddress", out var correctedElement))
{
    var corrected = JsonSerializer.Deserialize<Dictionary<string, string?>>(
        correctedElement.GetRawText());

    Console.WriteLine("Suggested address correction:");
    Console.WriteLine($"  {corrected["addressLine1"]}");
    if (!string.IsNullOrEmpty(corrected["addressLine2"]))
        Console.WriteLine($"  {corrected["addressLine2"]}");
    Console.WriteLine($"  {corrected["cityLocality"]}, {corrected["stateProvince"]} " +
        $"{corrected["postalCode"]}");
}

// Check for partial errors (some carriers failed)
if (root.TryGetProperty("ResponseErrors", out var errorsElement))
{
    var errors = JsonSerializer.Deserialize<List<string>>(errorsElement.GetRawText());
    foreach (var error in errors)
    {
        Console.WriteLine($"⚠ Carrier error: {error}");
    }
}

Error Responses

Error responses use the same ProblemDetails format. The detail field contains actionable error information from ShipEngine, including address validation errors and carrier-specific failures.

Address Validation Errors (HTTP 422)

Returned when ShipEngine rejects the request outright (e.g., completely invalid address, missing required fields).

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "ShipEngine Validation Error",
  "status": 422,
  "detail": "ShipEngine API error: Invalid address. The postal code 99999 is not valid for MA. (ErrorCode: FieldValueRequired, ErrorSource: Shipengine, ErrorType: Validation)"
}

The detail field includes:

  • The error message from ShipEngine describing what's wrong
  • ErrorCode — machine-readable error code (e.g., FieldValueRequired, InvalidAddress, Unspecified)
  • ErrorSource — where the error originated (Shipengine, Carrier, OrderSource)
  • ErrorType — error category (Validation, BusinessRules, Security, System)
No Rates Returned (HTTP 404)

Returned when ShipEngine accepted the request but no carriers returned valid rates. The detail field contains the specific reasons from each carrier, separated by |.

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
  "title": "No Rates Returned",
  "status": 404,
  "detail": "ups UPS® Ground: The destination postal code is invalid | ups UPS 2nd Day Air®: The destination postal code is invalid | stamps_com USPS Priority Mail: Invalid destination address"
}

Each entry in the pipe-separated list follows the format: {carrier_code} {service_name}: {error_message}

Common error messages you may see in detail:

Error Message Meaning
The destination postal code is invalid Postal code doesn't exist or doesn't match the state/city
Invalid destination address Address could not be validated by the carrier
Service not available for destination Carrier doesn't serve this address (e.g., remote area)
The shipment weight exceeds the maximum for this service Package too heavy for selected service
Dimensions exceed maximum allowed Package too large for selected service
Residential delivery not available Service only delivers to commercial addresses
International shipments require customs information Missing customs data for international label (rates don't require this)
ShipEngine Service Unavailable (HTTP 503)

Returned when the API cannot communicate with ShipEngine at all (network issues, authentication failures).

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.6.4",
  "title": "ShipEngine Service Unavailable",
  "status": 503,
  "detail": "There is a problem communicating with the ShipEngine external API. Error: <exception message>"
}
Invalid Input (HTTP 400)

Returned when the request JSON is malformed or missing required package data.

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "Missing Required Data",
  "status": 400,
  "detail": "Shipment package weight is required."
}

Handling Errors in C#

var response = await httpClient.GetAsync($"/GetRatesAsync?rateObject={encodedJson}");
var json = await response.Content.ReadAsStringAsync();

using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;

var status = root.GetProperty("status").GetInt32();
var detail = root.GetProperty("detail").GetString() ?? "";

switch (status)
{
    case 200:
        // Success — parse ReturnedRates
        if (root.TryGetProperty("ReturnedRates", out var ratesEl))
        {
            var rates = JsonSerializer.Deserialize<List<ShippingOptionsReturnedDTO>>(
                ratesEl.GetRawText());
            // Display rates to user
        }
        break;

    case 400:
        // Missing required data — show detail to user
        // e.g., "Shipment package weight is required."
        DisplayError($"Please check your input: {detail}");
        break;

    case 404:
        // No rates found — detail contains carrier-specific errors
        // Parse individual errors if needed:
        var carrierErrors = detail.Split(" | ");
        foreach (var error in carrierErrors)
        {
            Console.WriteLine($"  - {error}");
        }
        // Or show a user-friendly summary:
        if (detail.Contains("postal code", StringComparison.OrdinalIgnoreCase))
            DisplayError("The shipping address postal code appears to be invalid.");
        else if (detail.Contains("address", StringComparison.OrdinalIgnoreCase))
            DisplayError("The shipping address could not be validated.");
        else
            DisplayError("No shipping options available for this destination.");
        break;

    case 422:
        // ShipEngine validation error — address rejected outright
        // detail includes ErrorCode/ErrorSource/ErrorType for debugging
        DisplayError($"Address validation failed: {detail}");
        break;

    case 503:
        // ShipEngine service unavailable — retry later
        DisplayError("Shipping service temporarily unavailable. Please try again.");
        break;
}

Rate Request Requirements

The GetRatesAsync endpoint requires a full ship-to address for accurate rate quotes. All of these fields should be populated in the AddressDTO:

Field Required Notes
Name Yes Recipient name
AddressLine1 Yes Street address
AddressLine2 No Apt/Suite/Unit
CityLocality Yes City name
StateProvince Yes State/province code (e.g., "MA", "ON")
PostalCode Yes ZIP/postal code
CountryCode Yes ISO country code (e.g., DTOCountry.US)
Phone No Recipient phone number
customs International only DTOCustoms with customs items (required for international rates)

Providing incomplete address data (e.g., only postal code) may result in no rates or inaccurate pricing. For the most accurate quotes that match actual label costs, provide the complete address.

Note: Customs information is required for international rate quotes (v1.4.0+). ShipEngine needs customs items to return rates for international services. Use the same DTOCustoms data for both rate requests and label purchases. For domestic shipments, customs data is not needed.

Target Framework

  • .NET 10.0

Dependencies

  • System.Text.Json
  • System.ComponentModel.Annotations

License

MIT License - see LICENSE for details.

Repository

https://github.com/DarkMonkDev/ShipEngineShippingAPI

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.4.0 552 2/4/2026
1.3.1 135 2/4/2026
1.3.0 528 1/19/2026
1.2.1 161 1/16/2026
1.2.0 118 1/16/2026
1.1.0 246 1/11/2026
1.0.0 526 12/22/2025