Midnight.SOAP.SDK
2.2.7
dotnet add package Midnight.SOAP.SDK --version 2.2.7
NuGet\Install-Package Midnight.SOAP.SDK -Version 2.2.7
<PackageReference Include="Midnight.SOAP.SDK" Version="2.2.7" />
<PackageVersion Include="Midnight.SOAP.SDK" Version="2.2.7" />
<PackageReference Include="Midnight.SOAP.SDK" />
paket add Midnight.SOAP.SDK --version 2.2.7
#r "nuget: Midnight.SOAP.SDK, 2.2.7"
#:package Midnight.SOAP.SDK@2.2.7
#addin nuget:?package=Midnight.SOAP.SDK&version=2.2.7
#tool nuget:?package=Midnight.SOAP.SDK&version=2.2.7
Midnight.SOAP.SDK
Overview
Midnight.SOAP.SDK is a .NET 8 library that provides a modern, strongly-typed interface for integrating with PrintReach's Midnight SOAP API. It simplifies authentication, request construction, and XML response parsing for all SOAP operations currently exposed. The SDK is designed for developers who need to interact with the Midnight API in a robust and maintainable way.
The SOAP API documentation from PrintReach can be found here in PDF format.
Features
- Full Midnight SOAP API Wrapper: Retrieve, update, and insert any data supported by the Midnight SOAP API, including orders, inventory, customers, and more.
- Strongly-Typed Requests: Uses strongly-typed request objects to ensure type safety and reduce runtime errors caused by string concatenated XML inputs.
- Strongly-Typed Responses: Converts Midnight API XML response strings into strongly-typed C# models.
- User-Defined Fields Support: The SDK provides a flexible UserDefinedFields class, where each UDF property (UDF1 to UDF30) is implemented using the
UDFValueclass. This allows each field to accept and serialize values as string, decimal, integer, date, or time, ensuring correct XML formatting for both requests and responses. The UDFValue class handles type conversion and serializes the value as the text content of the corresponding <UDF*> XML tag. - Testing : Includes comprehensive unit tests for all services and request/response objects, ensuring reliability and correctness.
- Logging: Integrated logging for diagnostics and debugging using Serilog.
XML Serialization and Null Properties
Important:
To ensure correct XML serialization with the .NET XmlSerializer, nearly all properties in request objects are decorated with XmlElement(IsNullable=true). This approach ensures that when a property is not explicitly set, it will be serialized as xsi:nil="true" in the XML payload, except for Update requests. Update request bodies now implement the ShouldSerializeX method for XmlSerializer, which excludes fields from the rendered XML where the value was not explicitly set. This prevents unintended data from being sent to the Midnight SOAP API.
Disclaimer: In the past, particularly with Update methods of the Midnight SOAP API, we have found instances where even when not passing a field in the XML payload, that field's value can still be wiped out. We know for sure this happens with VendorUpdate.Terms, but if you experience any issues like this while using this SDK, please create an Issue in the GitHub repo and we will reach out to PrintReach for resolution.
Setup Instructions
Prerequisites
- PrintReach Midnight MIS API access (developer token)
- .NET 8 SDK
- Visual Studio 2022 or later (recommended)
- Serilog v4.3.0 or later for logging
Installation
Install-Package Midnight.SOAP.SDK
Usage
0. Soap Client Configuration
using Midnight.SOAP.SDK.Utilities;
var soapClient = SoapClient.Configure();
1. Service Initializations
using Midnight.SOAP.SDK;
var authService = new AuthenticationService(soapClient);
var customerService = new CustomerService(soapClient);
var customerContactService = new CustomerContactService(soapClient);
var djbService = new DJBService(soapClient);
var estimateService = new EstimateService(soapClient);
var inventoryItemService = new InventoryItemService(soapClient);
var inventoryService = new InventoryService(soapClient);
var jobCostingService = new JobCostingService(soapClient);
var orderService = new OrderService(soapClient);
var orderVersionService = new OrderVersionService(soapClient);
var orderVersionDetailService = new OrderVersionDetailService(soapClient);
var orderVersionDropService = new OrderVersionDropService(soapClient);
var orderVersionInventoryService = new OrderVersionInventoryService(soapClient);
var orderVersionPostageService = new OrderVersionPostageService(soapClient);
// ProofingService is the wrapper for "Request" api calls, making it clearer what the service is used for.
var proofingService = new ProofingService(soapClient);
var purchaseOrderService = new PurchaseOrderService(soapClient);
var settingsService = new SettingService(soapClient);
var venderService = new VendorService(soapClient);
var vendorContactService = new VendorContactService(soapClient);
2. Authentication
IMPORTANT: Never expose your developer token in client-side code or public repositories. Use a secrets manager or json configuration files that are in the .gitignore file
- So long as your team has purchased API access from PrintReach for Midnight MIS, you can find your dev token in Admin Settings > Global Settings > Site Token.
var validationHeader = await authService.AuthenticateAsync("your-dev-token");
3. User Defined Fields Example
User Defined Fields (UDFs) are supported in all services that accept or return UDFs. The UserDefinedFields class contains properties for UDF1 to UDF30, each of which is of type UDFValue. The UDFValue class can hold values of different types (string, decimal, integer, date, time) and ensures proper serialization/deserialization to XML.
NOTE: In scenarios where only a portion of available UDFs are available to send in a request or receive in a response, those classes inherit either UserDefinedFields_Top10 or UserDefinedFields_Top5 classes.
using Midnight.SOAP.SDK.CommonObjects;
var customerInsertUDFs = new UserDefinedFields
{
UDF7 = new UDFValue { Value = (decimal)0.999 }, // decimal type in Midnight UDF setup
UDF11 = new UDFValue { Value = 12345 }, // csharp auto-recognizes this as an integer
UDF1 = new UDFValue { Value = "testStringUDFInput" }, // csharp auto-recognizes this as a string
UDF5 = new UDFValue { Value = (decimal)999.00 } // currency-type field within Midnight UDF setup
};
var customerInsertResult = await customerService.CustomerInsertAsync(auth, new CustomerInsertRequestBody
{
InputParameter = new CustomerInsertInputParameter
{
CustomerCode = "TESTCUSTOMER1234",
CustomerName = "TEST CUSTOMER 123",
UDF7 = customerInsertUDFs.UDF7,
UDF11 = customerInsertUDFs.UDF11,
UDF1 = customerInsertUDFs.UDF1,
UDF5 = customerInsertUDFs.UDF5
}
});
4. Retrieve Order Version List by Customer
A common thing that you might need to do is retrieve a list of customers, then for each customer retrieve a list of orders, and for each order retrieve a list of order versions to then update version details/drops/postage etc. Below is an example of how to accomplish this using the SDK.
using Midnight.SOAP.SDK;
using Midnight.SOAP.SDK.Utilities;
using Midnight.SOAP.SDK.CommonObjects;
using Midnight.SOAP.SDK.RequestObjects.CustomerInputs;
using Midnight.SOAP.SDK.RequestObjects.OrderInputs;
using Midnight.SOAP.SDK.RequestObjects.VersionInputs;
var soapClient = SoapClient.Configure();
var authService = new AuthenticationService(soapClient);
var customerService = new CustomerService(soapClient);
var orderService = new OrderService(soapClient);
var orderVersionService = new OrderVersionService(soapClient);
var validationHeader = await authService.AuthenticateAsync("your-dev-token");
var customerListInput = new CustomerListRequestBody { /* set properties */ };
var customerListResult = await customerService.CustomerListAsync(validationHeader, customerListInput);
foreach (var customer in customerListResult.Customers)
{
var orderListInput = new OrderListRequestBody { /* set properties from customer */ };
var orderListResult = await orderService.OrderListAsync(validationHeader, orderListInput);
// Error check result
// filter orders as needed based on Result object
var filteredOrders = orderListResult.Orders.Where(
o => o.ProjectName.Contains("SomeFilter")).ToList();
foreach (var order in filteredOrders.Orders)
{
var versionListInput = new OrderVersionListRequestBody { /* set properties from order */ };
var versionListResult = await orderVersionService.OrderVersionListAsync(validationHeader, versionListInput);
// Error check result
foreach (var version in versionListResult.OrderVersions)
{
// Process each order version as needed
// List/Update/Insert things like OrderVersionDetails, Drops, Inventory, Postage, etc.
}
}
}
5. Retrieve Entire Order and it's Versions, optionally also retrieve VersionDetails, VersionDrops, VersionInventory and VersionPostage
using Midnight.SOAP.SDK;
using Midnight.SOAP.SDK.Utilities;
using Midnight.SOAP.SDK.CommonObjects;
using Midnight.SOAP.SDK.RequestObjects.OrderInputs;
var soapClient = SoapClient.Configure();
var authService = new AuthenticationService(soapClient);
var orderService = new OrderService(soapClient);
var validationHeader = await authService.AuthenticateAsync("your-dev-token");
var entireOrder = await orderService.GetEntireOrderAsync(validationHeader, new EntireOrderRequestBody{
OpenOrdersOnly = true, //optionally retrieve a closed order by setting this to false
OrderNumber = "123456",
IncludeServices = true, // order version details
IncludeDrops = true,
IncludeInventory = true,
IncludePostage = true // order version postage
});
This is a new method that combines several other calls into a single method, as such there might well be issues we have not accounted for when using it. If you encounter a problem using it, please file an issue via GitHub.
Errors and Exceptions
The SDK uses a combination of exceptions and error messages within the result objects to indicate errors. The inheritance of CommonResult for all output objects ensures the ReturnCode and ReturnErrors object are consistently available across all service responses.
Error Example
...
ReturnCode = -1, // Non-zero indicates an error
ReturnErrors =
{
Error = "Invalid authentication token." ,
Error = "CustomerCode is required."
}
...
Exceptions
The SDK will throw exceptions immediately after a non-zero ReturnCode is detected in the response. The ReturnCode and ReturnErrors properties are logged when this occurs.
Exceptions Possible
ArgumentNullException: Thrown when a required parameter is null.InvalidOperationException: Thrown when an operation is attempted that is not valid for the current state of the object.AuthenticationException: Thrown when authentication fails.Exception: Thrown for general errors that do not fit other categories.
Midnight API Rate Limiting Implemented
Overview
To maintain platform stability and ensure consistent performance for all Midnight customers, API rate limiting has been implemented for the Midnight API.
Why This Change Was Made
We identified API integrations generating significantly higher-than-expected request volumes. In some cases, this activity created enough load on backend database resources to impact overall system performance.
Because multiple customers may share the same infrastructure, excessive API traffic from a single integration can affect response times and performance for other customers. Rate limiting helps prevent these situations and protects the reliability of the platform.
Current Rate Limit
Midnight currently limits API traffic from a single IP address to approximately:
5,000 requests per 5-minute period
Requests exceeding this threshold will receive:
HTTP 429 - Too Many Requests
Rate limit thresholds may be adjusted in the future as we continue to evaluate usage patterns and platform requirements.
What Happens When a Limit Is Reached?
If an application exceeds the allowed request rate, the API will temporarily reject additional requests and return an HTTP 429 response.
Applications should be designed to recognize and handle this response appropriately.
Recommended Best Practices
Customers integrating with the Midnight API should:
- Handle HTTP 429 responses gracefully.
- Implement retry logic when requests are temporarily rejected.
- Use exponential backoff techniques when retrying requests.
- Avoid repeatedly submitting the same request in rapid succession.
- Filter data whenever possible to reduce the number of records being returned.
- Synchronize incremental changes rather than repeatedly retrieving all available data.
Optimization Opportunities
Customers experiencing rate limiting may be able to significantly reduce API traffic by:
- Filtering orders by date ranges.
- Using modified-date fields to retrieve only changed records.
- Limiting result sets to the data actually required.
- Reviewing integration workflows that repeatedly request the same information.
Commit Message and Branch Naming Conventions
Conventional Commit Messages
All commit messages must follow the Conventional Commits specification, which is compatible with automated versioning tools like Versionize and GitVersion. Example formats:
feat!: add support for NuGet deploy and releasefix: correct null reference in authentication servicedocs: update API usage section in READMErefactor(service): simplify request logicchore: update dependenciestest: add unit tests for AuthenticationService
Branch Naming Conventions
Branches must follow the enforced naming contract:
feature-new-api-integrationbugfix-fix-authentication-errorhotfix-critical-production-issuedocs-update-readmerefactor-service-layerchore-update-dependenciestest-add-auth-testsbuild-update-ci-workflowrelease-v1.2.3merge-main-into-feature
Branch names must match the pattern:
^(feature|bugfix|hotfix|docs|refactor|chore|test|experimental|build|release|merge)-[a-z0-9._-]+$
These conventions are enforced by git hooks and the CI/CD workflow to ensure consistency and compatibility with automated versioning and changelog generation.
Contributing
Contributions are welcome! Please fork the repository and submit a pull request.
License
This project is licensed under the MIT License.
Support
For questions or support, please open an issue on the repository.
Roadmap
The roadmap for Midnight.SOAP.SDK includes:
- Remove Serilog dependency and replace with Microsoft.Extensions.Logging for better compatibility with ASP.NET Core applications.
- Implement additional features as requested by the community.
- Enhance documentation with more examples and use cases.
Midnight.SOAP.SDK makes integrating with the Midnight SOAP API fast, reliable, and developer-friendly.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. 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. |
-
net8.0
- DocumentFormat.OpenXml (>= 3.3.0)
- Newtonsoft.Json (>= 13.0.3)
- Serilog (>= 4.3.0)
- System.ServiceModel.Http (>= 8.1.2)
- System.ServiceModel.NetTcp (>= 8.1.2)
- System.ServiceModel.Primitives (>= 8.1.2)
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 |
|---|---|---|
| 2.2.7 | 89 | 9/20/2026 |
| 2.2.6 | 102 | 8/27/2026 |
| 2.2.5 | 111 | 8/13/2026 |
| 2.2.4 | 92 | 8/13/2026 |
| 2.2.3 | 103 | 8/13/2026 |
| 2.2.2 | 104 | 8/10/2026 |
| 2.2.1 | 114 | 8/10/2026 |
| 2.2.0 | 110 | 8/10/2026 |
| 2.1.14 | 130 | 7/9/2026 |
| 2.1.13 | 127 | 6/17/2026 |
| 2.1.12 | 123 | 6/17/2026 |
| 2.1.11 | 125 | 6/4/2026 |
| 2.1.10 | 137 | 4/14/2026 |
| 2.1.9 | 125 | 4/14/2026 |
| 2.1.8 | 117 | 4/14/2026 |
| 2.1.7 | 111 | 4/14/2026 |
| 2.1.6 | 120 | 4/14/2026 |
| 2.1.5 | 125 | 2/10/2026 |
| 2.1.4 | 118 | 2/10/2026 |
| 2.1.3 | 232 | 11/4/2025 |