ShipEngine.Contracts
1.4.0
dotnet add package ShipEngine.Contracts --version 1.4.0
NuGet\Install-Package ShipEngine.Contracts -Version 1.4.0
<PackageReference Include="ShipEngine.Contracts" Version="1.4.0" />
<PackageVersion Include="ShipEngine.Contracts" Version="1.4.0" />
<PackageReference Include="ShipEngine.Contracts" />
paket add ShipEngine.Contracts --version 1.4.0
#r "nuget: ShipEngine.Contracts, 1.4.0"
#:package ShipEngine.Contracts@1.4.0
#addin nuget:?package=ShipEngine.Contracts&version=1.4.0
#tool nuget:?package=ShipEngine.Contracts&version=1.4.0
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
| Product | Versions 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. |
-
net10.0
- System.ComponentModel.Annotations (>= 5.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.