Use the following guide to assist in the upgrade process of the easypost-csharp library between major versions.
- Upgrading from 6.x to 7.0
- Upgrading from 5.x to 6.0
- Upgrading from 4.x to 5.0
- Upgrading from 3.x to 4.x
- Upgrading from 2.x to 3.0
Likelihood of Impact: High
.NET Framework 4.7.2+ now required.
Likelihood of Impact: High
The errors key of an error response can return either a list of FieldError objects or a list of strings. The error parsing has been expanded to include both formats. As such, you will now need to check for the format of the errors field and handle the errors appropriately for the type that is returned.
The Error model has been removed since it is unused and we directly assign properties of an error response to the ApiError type.
The PaymentRefund now uses a list of FieldError instead of Error for the errors field.
The following parameters, functions, and classes have been removed:
EasyPost.Models.API.DeliveryDateForZipPairEstimate.EasyPostTimeInTransitDataproperty (useEasyPost.Models.API.DeliveryDateForZipPairEstimate.TimeInTransitDetailsinstead)EasyPost.Models.API.Options.BillReceiverAccountproperty (useEasyPost.Models.API.Options.Paymentinstead)EasyPost.Models.API.Options.BillReceiverPostalCodeproperty (useEasyPost.Models.API.Options.Paymentinstead)EasyPost.Models.API.Options.BillThirdPartyAccountproperty (useEasyPost.Models.API.Options.Paymentinstead)EasyPost.Models.API.Options.BillThirdPartyCountryproperty (useEasyPost.Models.API.Options.Paymentinstead)EasyPost.Models.API.Options.BillThirdPartyPostalCodeproperty (useEasyPost.Models.API.Options.Paymentinstead)EasyPost.Models.API.Rate.EstDeliveryDaysproperty (useEasyPost.Models.API.Rate.DeliveryDaysinstead)EasyPost.Models.API.SmartRate.EstDeliveryDaysproperty (useEasyPost.Models.API.SmartRate.DeliveryDaysinstead)EasyPost.Models.API.RateWithEstimatedDeliveryDate.EasyPostTimeInTransitDataproperty (useEasyPost.Models.API.RateWithEstimatedDeliveryDate.TimeInTransitDetailsinstead)EasyPost.Models.API.RecommendShipDateForShipmentResult.EasyPostTimeInTransitDataproperty (useEasyPost.Models.API.RecommendShipDateForShipmentResult.TimeInTransitDetailsinstead)EasyPost.Models.API.ShipDateForZipPairRecommendation.EasyPostTimeInTransitDataproperty (useEasyPost.Models.API.ShipDateForZipPairRecommendation.TimeInTransitDetailsinstead)EasyPost.Models.API.Tracker.TrackingUpdatedAtproperty (useEasyPost.Models.API.Tracker.UpdatedAtinstead)EasyPost.Models.API.TimeInTransitDetailsclass (useEasyPost.Models.API.TimeInTransitDetailsForDeliveryDateEstimateinstead)EasyPost.Parameters.Tracker.CreateListclass (related function was removed in v6.8.0)EasyPost.Constants.CarrierAccounts.FedExAccountvariable (useEasyPost.Models.API.CarrierAccountType.FedExinstead)EasyPost.Constants.CarrierAccounts.UpsAccountvariable (useEasyPost.Models.API.CarrierAccountType.Upsinstead)
NOTICE: v6 is deprecated.
Likelihood of Impact: High
.NET Core 3.1 Support Dropped
This library no longer supports .NET Core 3.1, which has reached end-of-life.
.NET 8.0 Support Added
This library now supports .NET 8.0.
Likelihood of Impact: High
EasyPost now offers Carbon Neutral shipments by default for free! Because of this, there is no longer a need to specify if you want to offset the carbon footprint of a shipment.
The withCarbonOffset parameter of the Create, Buy, and RegenerateRates shipment functions has been removed.
The CarbonOffset parameter of the Shipment.Create, Shipment.Buy and Shipment.RegenerateRates parameter sets has been removed.
This is a high-impact change for those using EndShippers, as the signature for the Create and Buy shipment function has changed. You will need to inspect these callsites to ensure that the EndShipper parameter is being passed in the correct place.
The CarbonOffset model has also been removed.
Likelihood of Impact: Low
The create_and_buy batch endpoint has been deprecated, and the CreateAndBuy Batch service function has been removed.
The correct procedure is to first create a batch and then purchase it with two separate API calls.
NOTICE: v5 is deprecated.
Likelihood of Impact: High
Previously, only Create, Retrieve and All functions were available in services, with all other functions related to a specific instance of a resource available on the resource itself.
For example, v4.x flow of creating a pickup and then buying it:
var pickup = await myClient.Pickup.Create(parameters);
pickup.Buy(); // pickup variable is updated in-placeIn v5.0, the flow is now:
var pickup = await myClient.Pickup.Create(parameters);
purchasedPickup = await myClient.Pickup.Buy(pickup.Id); // need to capture the updated Pickup objectLikelihood of Impact: High
The process of configuring a Client has been overhauled to allow for more flexibility in the configuration process.
Old method:
Client myClient = new Client("my_api_key");New method:
Client myClient = new Client(new ClientConfiguration("my_api_key"));The ClientConfiguration class has a number of optional parameters that can be set to customize the behavior of the Client instance.
Client myClient = new Client(new ClientConfiguration("my_api_key") {
ApiBase = "optional_api_base_override",
CustomHttpClient = myOptionalCustomHttpClient,
Timeout = TimeSpan.FromMilliseconds(myCustomTimeoutMilliseconds)
});Likelihood of Impact: Medium
The RestSharp dependency in this library has been dropped in favor of using the System.Net.Http and Newtonsoft.Json libraries directly.
This should have no impact on the end-user experience of using this library, but if you were reliant on the RestSharp dependency in this library being transitively used for another aspect of your codebase, you will need to now install RestSharp directly.
Likelihood of Impact: Medium
The following classes and properties have been renamed or altered:
Smartrateis nowSmartRate
Likelihood of Impact: Medium
Some exception types have been consolidated or altered:
UnexpectedHttpErroris nowUnknownHttpErrorUnknownApiErrorhas been removed and replaced withUnknownHttpErrorExternalApiErrorno longer inherits fromApiErrorand instead inherits fromEasyPostError- Any EasyPost API failure will raise an
ApiError-based exception - Non-EasyPost API/HTTP failures (e.g. calls to Stripe) will raise an
ExternalApiErrorexception
- Any EasyPost API failure will raise an
- All
EasyPostErrorexceptions now have aPrettyPrintgetter method that returns a human-readable string representation of the error - An EasyPost API timeout will raise a
TimeoutErrorexception rather than aSystem.Threading.Tasks.TaskCanceledException
Likelihood of Impact: Medium
The Parameter objects introduced in v4.5.0 have been moved out of beta. As a result, the classes are available in a different namespace.
Old namespace:
var parameters = new EasyPost.BetaFeatures.Parameters.Addresses.Create();New namespace:
var parameters = new EasyPost.Parameters.Address.Create();Note that the namespaces have also changed from plural to singular (e.g. Addresses to Address, Shipments to Shipment) to better correlate with the service names on a Client instance.
NOTICE: v4 is deprecated.
- Updating Dependencies
- Client Instance
- Language Conventions
- Nullable Properties
- Error Types
- Namespace Changes
Likelihood of Impact: High
Dependencies
- RestSharp was upgraded from v107 to v108
- All dependencies had minor version bumps and have been locked to the latest (at the time) major version
Likelihood of Impact: High
The library is now designed around the idea of a Client. Users will initialize a Client instance with their API key
and then use that instance to make API calls.
This change allows for multiple clients to be instantiated with different API keys and for the library to be used in a multi-threaded environment.
// Old
EasyPost.ClientManager.SetCurrent("EASYPOST_API_KEY"); // global API key
// New
var client1 = new EasyPost.Client("EASYPOST_API_KEY_1"); // per-client API key
var client2 = new EasyPost.Client("EASYPOST_API_KEY_2"); // per-client API keyAll functions are now accessed via the Client instance. For example, to create a shipment:
// Old
EasyPost.Shipment shipment = await EasyPost.Shipment.Create(parameters);
// New
EasyPost.Shipment shipment = await myClient.Shipment.Create(parameters);Likelihood of Impact: High
All functions, classes and properties have been renamed to follow the C# language conventions. The most notable changes here is that all properties of an object are now PascalCase rather than snake_case.
// Old
var id = myAddress.id;
var toAddress = myShipment.to_address;
var formType = myScanForm.form_file_type;
// New
var id = myAddress.Id;
var toAddress = myShipment.ToAddress;
var formType = myScanForm.FormFileType;Likelihood of Impact: High
All properties of all objects are now nullable. This means that if a property is not returned by the API, it will be
either null or the default value for the given type (e.g. false for bool).
This change silences compilation warnings for the library.
The majority of properties for an object will likely be populated as a result of an API call, but if not, end-users will
know that the value of a non-populated property is guaranteed to be null.
End users may need to add additional null checks or nullability markers in their code, although this change will likely play well with any existing null checks.
// Old
string name = myAddress.name; // "name" is non-nullable, but not guaranteed to be populated
bool correctName = name.startsWith("John"); // compilation warning: "name" may be null
// New
string? name = myAddress.Name; // "Name" and "name" are nullable
bool correctName = name?.startsWith("John") ?? false; // no compilation warningLikelihood of Impact: High
Error handling has been overhauled and a number of specific exception types have been introduced.
All exceptions inherit from EasyPost.Exceptions.EasyPostError (which extends System.Exception). Users can catch this exception type to handle all
errors thrown by the library.
Subclasses of EasyPostError are grouped into two categories:
EasyPost.Exceptions.ApiErrorfor errors returned by the API. Subclasses of this exception type are:EasyPost.Exceptions.ConnectionError- thrown when the library is unable to connect to the APIEasyPost.Exceptions.ExternalApiError- thrown when an issue occurs with an external API (e.g. Stripe)EasyPost.Exceptions.GatewayTimeoutError- thrown when the API gateway times out (504 status code)EasyPost.Exceptions.InternalServerError- thrown when an internal server error occurs (500 status code)EasyPost.Exceptions.InvalidRequestError- thrown when the API received an invalid request (422 status code)EasyPost.Exceptions.MethodNotAllowedError- thrown when the API receives a request with an invalid HTTP method ( 405 status code)EasyPost.Exceptions.NotFoundError- thrown when the API receives a request for a resource that does not exist ( 404 status code)EasyPost.Exceptions.PaymentError- thrown when a payment error occurs (402 status code)EasyPost.Exceptions.ProxyError- thrown when the library is unable to connect to the API via a proxyEasyPost.Exceptions.RateLimitError- thrown when the API rate limit is exceeded (429 status code)EasyPost.Exceptions.RetryError- thrown when an error occurs during a retryEasyPost.Exceptions.ServiceUnavailableError- thrown when the API is unavailable (503 status code)EasyPost.Exceptions.SslError- thrown when the library is unable to connect to the API via SSLEasyPost.Exceptions.TimeoutError- thrown when the API request times out (408 status code)EasyPost.Exceptions.UnauthorizedError- thrown when the API receives an unauthorized request (401 or 403 status code)EasyPost.Exceptions.UnexpectedHttpError- thrown when an unknown HTTP error occurs (unexpected 5xx status code)EasyPost.Exceptions.UnknownApiError- thrown when an unknown API error occurs (unexpected 4xx status code)EasyPost.Exceptions.VcrError- thrown when an error occurs with the VCR (used for testing only)
- Generic exceptions
EasyPost.Exceptions.FilteringError- thrown when an error occurs during filtering (e.g. calculating lowest rate)EasyPost.Exceptions.InvalidObjectError- thrown when an invalid object is being usedEasyPost.Exceptions.JsonErrorEasyPost.Exceptions.JsonDeserializationError- thrown when an error occurs during JSON deserializationEasyPost.Exceptions.JsonSerializationError- thrown when an error occurs during JSON serializationEasyPost.Exceptions.JsonNoDataError- thrown when no data is provided for JSON deserialization
EasyPost.Exceptions.MissingPropertyError- thrown when a required property is missing (e.g.Idfor most objects)EasyPost.Exceptions.SignatureVerificationError- thrown when the signature for a webhook is invalidEasyPost.Exceptions.ValidationErrorEasyPost.Exceptions.MissingParameterError- thrown when a required parameter is missingEasyPost.Exceptions.InvalidParameterError- thrown when an invalid parameter is passed to a function
Any exception thrown by the EasyPost library will be one of the above types.
Any EasyPost.Exceptions.ApiError exception will have the following properties:
int? StatusCode- the HTTP status code returned by the API call (e.g. 404)string? Code- the error code returned by the API (e.g. "PARAMETER.INVALID")List<EasyPost.Error>? Errors- a list of errors returned by the API (e.g. "Invalid parameter: to_address")
Any EasyPost.Exceptions.ApiError exception can be pretty-printed using the PrettyPrint string property.
Users can better anticipate exception information through utilities in the EasyPost.Exceptions.Constants namespace.
- Check what exception type will be thrown for a given HTTP status code by
using
EasyPost.Exceptions.Constants.GetEasyPostExceptionType(HttpStatusCode statusCode) - Check error message strings/templates in
EasyPost.Exceptions.Constants.ErrorMessages
Likelihood of Impact: High
As a result of organizing the source code of this library, the namespace of several classes has changed.
- Most EasyPost-related objects are now in the
EasyPost.Models.APInamespace- e.g.
EasyPost.Addressis nowEasyPost.Models.API.Address
- e.g.
- Exceptions, as noted in Error Types, are now in the
EasyPost.Exceptionsnamespace - Services (static functions) are now in the
EasyPost.Servicesnamespace (see Services and Resources)- This should be opaque to end users accessing services through the
EasyPost.Clientclass.
- This should be opaque to end users accessing services through the
Likelihood of Impact: Low
Following the client instance redesign, beta features are now accessed via the Beta property of
the Client instance.
This "beta client" can only be used to access beta features. Using a beta client to access non-beta features may result in unexpected behavior.
// Old
var betaObject = await EasyPost.Beta.SomeService.SomeFunction(parameters);
// New
var betaObject = await myClient.Beta.SomeService.SomeFunction(parameters);Any beta function will use the same client (and associated API key) from which the beta function was accessed (
i.e. myClient in the example above).
Likelihood of Impact: Low
Static and instance-based methods have been divided into separate services and resources. For example, the static
method Shipment.Create is now accessible in the Shipment service via myClient.Shipment.Create. The instance
method myShipment.Buy is still accessible only via a Shipment instance.
Instances of an object cannot be initialized directly. Instead, use the service to create the instance via a Create
, Retrieve, or All API call.
Outside of the new client instance change and the namespace change, this design change should not have any additional significant impact on usage, but it is worth noting the new organizational structure.
NOTICE: v3 is deprecated.
- Updating Dependencies
- Project is Now Asynchronous
- Address Verification Parameter Changes
- Non-Static
Create()Methods Removed - Renames
List()Functions toAll() - Clarify XList vs XCollection Distinctions
Likelihood of Impact: High
Explicit .NET Framework Support Removed
easypost-csharp no longer explicitly supports .NET Framework.
.NET Standard 2.0 is compatible with .NET Framework 4.6.1+. See this article for more information.
.NET Standard 2.0 & NET 5.0 & 6.0 Support Added
easypost-csharp can now be used with .NET Standard 2.0, NET 5.0 & NET 6.0 along with Visual Basic and F#.
Dependencies
- RestSharp was upgraded from v106 to v107
- All dependencies had minor version bumps
Likelihood of Impact: High
Most functions are now asynchronous which requires prepending await to any function call and making the
functions async. This change dramatically improves API response times and prevents deadlocks. Aside from the need to
await for your async calls, the interfaces of methods remain the same (except for a couple notable changes listed below)
. A simple example of how to call an EasyPost function may look like:
// `async` now required
static async Task Main()
{
// Must call `await` on EasyPost function calls
Shipment shipment = await Shipment.Create(new Dictionary<string, object>() {
{ "from_address", fromAddress },
{ "to_address", toAddress },
{ "parcel", parcel },
});
// Must call `await` on EasyPost function calls
await shipment.Buy(shipment.LowestRate());
}This change may require refactoring the parent methods to also be asynchronous.
Likelihood of Impact: High
The parameters to verify an address have been changed from verification to verify and strict_verification
to verify_strict to match our other libraries and documentation. The new parameter names must be used to verify an
address.
// Old
addressData.Add("verifications_strict", new List<bool> { true });
// New
addressData.Add("verify_strict", new List<bool> { true });Likelihood of Impact: High
In order to make this library Visual Basic-compatible,
non-static Create() functions are no longer supported.
This affects the Address, Order, Pickup and Shipment classes.
Previously, users could create, i.e., an Address object (myAddress) locally, set its attributes, and then
call myAddress.Create() to send the address data to EasyPost's API.
Now, users must call Address.Create() to create an Address object, passing in the address attributes as a
dictionary. This will send the data to EasyPost's API and return a local Address object.
// Old
Address myAddress = new Address();
myAddress.company = "EasyPost";
await myAddress.Create();
// New
Address myAddress = await Address.Create(new Dictionary<string, object>() {
{ "company", "EasyPost" },
});Likelihood of Impact: High
Functions that called the /all method have been renamed from List() to All() to make function naming uniform (
previously there were a mix of both naming conventions) which also brings these calls inline with our documentation. If
you use any List functions in your project, you will need to update these.
// Old
ShipmentList shipments = Shipment.List()
// New
ShipmentCollection shipments = Shipment.All()Likelihood of Impact: High
We unified the names of all "collection" type objects from XList to XCollection (eg: ShipmentList -> ShipmentCollection) . If you are using these objects, you will need to correct their names.
// Old
ShipmentList shipments = Shipment.List()
// New
ShipmentCollection shipments = Shipment.All()Likelihood of Impact: Medium
Functions that were previously named Destroy are now named Delete. This change was made make this library consistent
with our other libraries and documentation while also clarifying what the action is doing. You will need to correct
these names in your code when performing actions such as deleting Webhooks, Users, and Carrier Accounts.
// Old
webhook.Destroy();
// New
webhook.Delete();Likelihood of Impact: Medium
The HTTP method used for the get_rates endpoint at the API level has changed from POST to GET and will only
retrieve rates for a shipment instead of regenerating them. A new /rerate endpoint has been introduced to replace this
functionality; In this library, you can now call the shipment.RegenerateRates method to regenerate rates. Due to the
logic change, the GetRates method has been removed since a Shipment inherently already has rates associated.
// Old
shipment.GetRates()
// New
shipment.RegenerateRates()Likelihood of Impact: Low
The Rating class is unusable as you cannot "create" a rate and has been removed. Rates must be retrieved from a
Shipment after creation.