Peppol.Ademico.Kiota
2.0.0
dotnet add package Peppol.Ademico.Kiota --version 2.0.0
NuGet\Install-Package Peppol.Ademico.Kiota -Version 2.0.0
<PackageReference Include="Peppol.Ademico.Kiota" Version="2.0.0" />
<PackageVersion Include="Peppol.Ademico.Kiota" Version="2.0.0" />
<PackageReference Include="Peppol.Ademico.Kiota" />
paket add Peppol.Ademico.Kiota --version 2.0.0
#r "nuget: Peppol.Ademico.Kiota, 2.0.0"
#:package Peppol.Ademico.Kiota@2.0.0
#addin nuget:?package=Peppol.Ademico.Kiota&version=2.0.0
#tool nuget:?package=Peppol.Ademico.Kiota&version=2.0.0
Peppol.Ademico.Kiota
A C# SDK for the Peppol e-invoicing network, built on top of Ademico's Peppol REST API and generated with Kiota.
- Ademico itself is not involved in this project and bears no responsibility for its compatibility with new versions of their API.
- To use this SDK you'll need a license key from Ademico; they charge according to their pricing policy.
- This SDK project itself is open source under the MIT License.
See CHANGELOG.md for release history and CONTRIBUTING.md for how releases and the versioning scheme work.
Install
dotnet add package Peppol.Ademico.Kiota
Setup
Set your Ademico Client ID and Client Secret as environment variables:
Ademico__Client__Id=YOUR_ADEMICO_CLIENT_ID
Ademico__Client__Secret=YOUR_ADEMICO_CLIENT_SECRET
In appsettings.json, set the TokenEndpoint and ApiBaseUrl for the environment you're targeting:
// appsettings.json
{
"Ademico": {
"TokenEndpoint": "https://test-peppol-oauth2.ademico-software.com/oauth2/token",
"ApiBaseUrl": "https://test-peppol-api.ademico-software.com",
"Client": {
"Id": "Use an environment variable 'Ademico__Client__Id'",
"Secret": "Use an environment variable 'Ademico__Client__Secret'"
}
}
}
Register the SDK's services in your DI container:
var builder = WebApplication.CreateBuilder(args);
// ...
builder.Services.AddPeppolServices(builder.Configuration);
// ...
Access token caching in development
The Ademico API rate-limits its authentication endpoint to a few calls per hour. Access tokens are valid
for one hour, which is normally enough — but a development environment loses in-memory state (and its
token) on every restart. To avoid re-authenticating on every restart during local development, set
AccessTokenPath to a local file:
// appsettings.Development.json
{
"Ademico": {
"TokenEndpoint": "https://test-peppol-oauth2.ademico-software.com/oauth2/token",
"ApiBaseUrl": "https://test-peppol-api.ademico-software.com",
"AccessTokenPath": "/tmp/AdemicoAccessToken.txt"
}
}
Only use this for local development — don't point it at a shared or production path.
Usage
Inject PeppolAdemicoApiClient wherever you need to call the API:
public class AdemicoService(PeppolAdemicoApiClient client)
{
// ...
}
The examples below assume client is a PeppolAdemicoApiClient obtained this way.
Connectivity check
await client.Api.Peppol.V1.Tools.Connectivity.GetAsync(cancellationToken: token);
Legal entities and Peppol registrations
// List legal entities
LegalEntityListRO? legalEntities = await client.Api.Peppol.V1.LegalEntities.GetAsync(cancellationToken: token);
// Create a legal entity
LegalEntityCreateResponseRO? created = await client.Api.Peppol.V1.LegalEntities.PostAsync(
new LegalEntityCreateRequestRO { /* ... */ },
cancellationToken: token);
// Peppol registrations for a legal entity
var registrations = await client.Api.Peppol.V1.LegalEntities[legalEntityId]
.PeppolRegistrations.GetAsync(cancellationToken: token);
Submitting a UBL invoice or credit note
var body = new MultipartBody();
body.AddOrReplacePart("file", "application/xml", File.OpenRead("invoice.xml"));
DocumentSubmissionResultRO? result = await client.Api.Peppol.V1.Invoices.UblSubmissions.PostAsync(
body,
cancellationToken: token);
You get notified of the outcome (sent/received/failed) asynchronously via notifications — see below.
Retrieving an incoming invoice
Stream? ubl = await client.Api.Peppol.V1.Invoices[transmissionId].Ubl.GetAsync(cancellationToken: token);
Sending an invoice response
DocumentSubmissionResultRO? result = await client.Api.Peppol.V1.InvoiceResponses.PostAsync(
new InvoiceResponseRO { /* ... */ },
cancellationToken: token);
Notifications
The API notifies you (via pull or push) when a document is sent, received, fails to send, or changes status. Poll for pending notifications with:
AS4NotificationsResponseRO? notifications = await client.Api.Peppol.V1.Notifications
.GetAsync<AS4NotificationsResponseRO>(cancellationToken: token);
foreach (var notification in notifications?.Notifications ?? [])
{
if (notification is AS4Notification n && n.InvoiceReceivingNotificationRO is not null)
{
// handle an incoming invoice/credit note notification
}
// ... check the other NotificationRO variants (OrderReceivingNotificationRO, MLRReceivingNotificationRO,
// InvoiceResponseReceivingNotificationRO, CDARReceivingNotificationRO, etc.) depending on what you need.
}
AS4NotificationsResponseRO/AS4Notification exist because the underlying NotificationRO schema is
polymorphic without a discriminator — see
src/Peppol.Ademico.Kiota/README.md for why, and its XML doc comments
for exactly which eventType/peppolDocumentType combinations map to which notification type.
Error handling
Kiota surfaces non-2xx responses as thrown exceptions typed per the mapped error model for that status code. Most endpoints in this SDK map:
- 400 Bad Request →
FileSubmissionResultError(submission endpoints) orApplicationMessage(most other endpoints) — validation failures, with details of what was wrong. - 401 Unauthorized →
ApplicationMessage— typically an expired or invalid access token; the SDK'sTokenServiceshould keep this from happening under normal use (see below), so treat a 401 as worth logging distinctly.
try
{
await client.Api.Peppol.V1.Invoices.UblSubmissions.PostAsync(body, cancellationToken: token);
}
catch (FileSubmissionResultError ex)
{
// Inspect ex for validation error details
}
catch (ApplicationMessage ex)
{
// Inspect ex.Message / ex fields for the API's error message
}
How authentication works
AddPeppolServices wires up an OAuth2 client-credentials flow (TokenService) that fetches, caches, and
transparently refreshes an access token, and an AuthProvider that attaches it to every request. You
don't need to manage tokens yourself. Ademico's API also returns some timestamps without timezone info; a
message handler in the pipeline (UtcDateTimeHandler) treats those as UTC before deserialization.
Links
- Kiota — The NEW OpenAPI Client Generator
- Ademico Peppol REST API (OpenAPI spec this SDK is generated from)
| 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 is compatible. 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 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.11)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.11)
- Microsoft.Kiota.Bundle (>= 2.1.1)
- OneOf (>= 3.0.271)
-
net8.0
- Microsoft.Extensions.Http (>= 10.0.11)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.11)
- Microsoft.Kiota.Bundle (>= 2.1.1)
- OneOf (>= 3.0.271)
-
net9.0
- Microsoft.Extensions.Http (>= 10.0.11)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.11)
- Microsoft.Kiota.Bundle (>= 2.1.1)
- OneOf (>= 3.0.271)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
See https://github.com/WimSuenens/peppol.ademico.kiota/blob/main/CHANGELOG.md for release notes.