SauceCode.MyData
1.0.0
dotnet add package SauceCode.MyData --version 1.0.0
NuGet\Install-Package SauceCode.MyData -Version 1.0.0
<PackageReference Include="SauceCode.MyData" Version="1.0.0" />
<PackageVersion Include="SauceCode.MyData" Version="1.0.0" />
<PackageReference Include="SauceCode.MyData" />
paket add SauceCode.MyData --version 1.0.0
#r "nuget: SauceCode.MyData, 1.0.0"
#:package SauceCode.MyData@1.0.0
#addin nuget:?package=SauceCode.MyData&version=1.0.0
#tool nuget:?package=SauceCode.MyData&version=1.0.0
SauceCode.MyData
SauceCode.MyData is a .NET library that provides a robust client for integrating with the AADE MyData (Independent Authority for Public Revenue) invoicing platform in Greece. It is designed to be simple, resilient, and easy to integrate into modern .NET applications.
Features
- Two access modes -
MyDataErpClientfor an entity transmitting its own documents, andMyDataProviderClientfor a provider acting on behalf of its client entities. - Runtime environment selection - Target Sandbox or Production per call via a client factory, so one process can serve both without re-registering.
- Per-call credentials - Credentials are passed on each call rather than bound at registration, so a single registered client can serve many tenants.
- Built-in HTTP resilience - Per-attempt timeout, retry with exponential backoff, and a circuit breaker, each client isolated so one environment's outage can't trip another's breaker. Fully configurable.
- Errors as exceptions, business outcomes as data - Transport/protocol failures throw
MyDataException; AADE's per-item results (including partial rejections) come back to you as data.
Installation
Install via NuGet:
dotnet add package SauceCode.MyData
Or search for SauceCode.MyData on NuGet.org.
Quickstart
1. Register services
In Program.cs (or your startup), register the mode you need. Each call registers a client factory plus a named HttpClient per environment, each with its own resilience pipeline:
using SauceCode.MyData;
var builder = WebApplication.CreateBuilder(args);
// ERP mode (entity transmits its own documents):
builder.Services.AddMyDataErp();
// Provider mode (provider acts for client entities) — register either or both:
builder.Services.AddMyDataProvider();
var app = builder.Build();
Optionally tune the resilience behaviour (timeout, retry, circuit breaker) with a callback — see Resilience:
builder.Services.AddMyDataErp(options =>
{
options.Timeout = TimeSpan.FromSeconds(5);
options.MaxRetryAttempts = 3;
});
2. Create a client for an environment
Inject the factory and call Create with the target MyDataEnvironment. The returned client is bound to that environment; call Create again for the other environment — no second registration needed.
using SauceCode.MyData;
using SauceCode.MyData.Clients;
public class InvoiceService(IMyDataErpClientFactory factory)
{
private readonly MyDataErpClient _client = factory.Create(MyDataEnvironment.Production);
// ...
}
3. Submit invoices
Pass the caller's credentials on each call. SendInvoicesAsync returns AADE's per-item outcomes as a List<ResponseType>:
using SauceCode.MyData.Clients;
using SauceCode.MyData.Exceptions;
using SauceCode.MyData.Models;
using SauceCode.MyData.MyDataContracts;
public class InvoiceService(IMyDataErpClientFactory factory)
{
private readonly MyDataErpClient _client = factory.Create(MyDataEnvironment.Production);
public async Task SubmitAsync(InvoicesDoc invoices, CancellationToken ct)
{
var credentials = new MyDataErpCredential(
username: "your-aade-user-id", // sent as the aade-user-id header
password: "your-subscription-key"); // sent as the ocp-apim-subscription-key header
try
{
List<ResponseType> outcomes = await _client.SendInvoicesAsync(invoices, credentials, ct);
foreach (var outcome in outcomes)
{
if (outcome.StatusCode == "Success")
{
// Accepted — outcome.InvoiceMark is AADE's unique registration number (MARK).
Console.WriteLine($"Invoice {outcome.Index} registered as MARK {outcome.InvoiceMark}.");
}
else
{
// Rejected — inspect the per-item errors (this is not an exception).
foreach (var error in outcome.Errors)
Console.WriteLine($"Invoice {outcome.Index} rejected: [{error.Code}] {error.Message}");
}
}
}
catch (MyDataException ex)
{
// Transport/protocol failure (non-success HTTP status, unreadable payload, transport error).
Console.WriteLine($"MyData call failed ({(int)ex.StatusCode}): {ex.Message}");
Console.WriteLine(ex.ErrorDetail is null ? ex.RawResponse : "See ex.ErrorDetail for parsed AADE detail.");
}
}
}
The same shape applies to the other ERP calls — SendIncomeClassificationAsync, SendExpensesClassificationAsync, and CancelInvoiceAsync(long mark, ...) — and to the Provider client's SendInvoicesAsync. Document retrieval (RequestTransmittedDocsAsync / RequestDocsAsync) takes a DocumentRetrievalQuery and returns the requested documents.
Error handling at a glance
| Situation | How it surfaces |
|---|---|
| Non-success HTTP status, empty/undeserializable body, or transport error | throws MyDataException (StatusCode, RawResponse, best-effort parsed ErrorDetail) |
| Batch accepted, or partially rejected | returns List<ResponseType> — check each item's StatusCode, Errors, and InvoiceMark |
Per-item business outcomes are never signalled through an exception; a partially-rejected batch is a normal, successful call.
Resilience
Every HTTP call is wrapped in a per-client resilience pipeline. Each (mode, environment) pair gets its own pipeline instance, so a Sandbox outage can never trip the Production circuit breaker. Defaults reproduce the library's historical behaviour and can be overridden via the callback on AddMyDataErp / AddMyDataProvider (MyDataResilienceOptions):
| Option | Default | Behaviour |
|---|---|---|
Timeout |
2 s | Per-attempt timeout; a slower attempt is abandoned and counts as a transient failure. |
MaxRetryAttempts |
2 | Retries after the initial attempt (3 attempts total), with exponential backoff and jitter. |
RetryBaseDelay |
200 ms | Base delay for the backoff. |
CircuitBreakerFailureThreshold |
3 | Failures within the sampling window that open the circuit. |
CircuitBreakerBreakDuration |
30 s | How long the circuit stays open before a trial call. |
CircuitBreakerSamplingDuration |
30 s | Rolling window over which failures are counted. |
Transient failures (5xx, 408, timeouts, HttpRequestException) are retried and metered against the breaker. 429 Too Many Requests is deliberately not retried; other non-transient responses (400, 401, 404, …) pass through directly.
Versioning & AADE schema
The library follows Semantic Versioning. The generated XSD contracts are the public API, so an AADE schema change that alters a contract is a breaking (major) change — see the SemVer policy.
Each package records the AADE schema version its contracts target. Check it at runtime, or read the aade-schema-* tag on nuget.org:
Console.WriteLine(MyDataSchema.TargetedVersion); // e.g. "2.0.1"
The stable package tracks the production schema. Prerelease packages (e.g. 1.1.0-preview.1) are built from the ahead-of-production sandbox schema, so early adopters can test upcoming AADE changes before they go live.
Packages ship with SourceLink and a symbol package (snupkg on nuget.org), so you can step straight into the library's source while debugging.
License
This project is licensed under the PolyForm Noncommercial License 1.0.0.
Free usage
You may use this library for any personal, hobby, research, educational, or other non‑commercial purpose at no cost.
Examples of allowed free usage include:
- Personal or hobby projects
- Student or academic work
- Non‑profit or research use
- Internal evaluation or experimentation
- Open‑source projects that are not used commercially
Commercial usage
A commercial license is required if you:
- Use this library in a commercial product
- Use it within a business or organization for revenue‑generating activities
- Provide it as part of a paid service
- Use it in production environments that support commercial operations
If your company earns revenue, sells software, or uses this library in production, you must obtain a commercial license.
Commercial License
For commercial usage, a paid license is required. See the full commercial license agreement here:
Contributing
Please read our CONTRIBUTING.md before submitting pull requests. By contributing, you agree to the terms described there.
Support
For questions, issues, or feature requests, please open an issue in this 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
- Microsoft.Extensions.Http (>= 10.0.10)
- Microsoft.Extensions.Http.Resilience (>= 10.8.0)
- SauceCode.Common (>= 1.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.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 113 | 7/27/2026 |
| 1.0.0-alpha.3 | 82 | 2/16/2026 |
| 1.0.0-alpha.2 | 74 | 2/9/2026 |
| 1.0.0-alpha.1 | 79 | 2/8/2026 |