AnafIntegration 1.0.5

dotnet add package AnafIntegration --version 1.0.5
                    
NuGet\Install-Package AnafIntegration -Version 1.0.5
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="AnafIntegration" Version="1.0.5" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="AnafIntegration" Version="1.0.5" />
                    
Directory.Packages.props
<PackageReference Include="AnafIntegration" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add AnafIntegration --version 1.0.5
                    
#r "nuget: AnafIntegration, 1.0.5"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package AnafIntegration@1.0.5
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=AnafIntegration&version=1.0.5
                    
Install as a Cake Addin
#tool nuget:?package=AnafIntegration&version=1.0.5
                    
Install as a Cake Tool

AnafIntegration

.NET 7 class library for integrating with the ANAF e-Factura API (RO e-Factura). Handles OAuth 2.0 authentication, invoice conversion from C# objects to UBL 2.1 XML (CIUS-RO), and all e-Factura API operations.

Designed to be referenced from a Blazor WASM Server application.

Installation

Add a project reference from your Blazor Server project:

<ProjectReference Include="..\AnafIntegration\AnafIntegration.csproj" />

NuGet dependencies (restored automatically):

  • UblSharp 1.1.1
  • Microsoft.Extensions.Http 7.0.0
  • Microsoft.Extensions.DependencyInjection.Abstractions 7.0.0
  • Microsoft.Extensions.Options 7.0.0

Setup

1. Register services in Program.cs

using AnafIntegration;
using AnafIntegration.Extensions;

builder.Services.AddAnafIntegration(options =>
{
    options.ClientId = "your-client-id";
    options.ClientSecret = "your-client-secret";
    options.RedirectUri = "https://yourapp.com/anaf-callback";
    options.Environment = AnafEnvironment.Test; // or AnafEnvironment.Production
});

This registers all services: AnafOAuthService, AnafApiClient, InMemoryTokenStore, and InvoiceToUblMapper.

2. ANAF prerequisites

Before using the API you must:

  1. Register as a developer at anaf.ro > Servicii Online > Inregistrare utilizatori > Dezvoltatori Aplicatii.
  2. Authenticate and go to "Editare profil Oauth".
  3. Register your application (name + e-Factura service) to receive your Client ID and Client Secret.
  4. Users of your app must be registered in SPV with a qualified digital certificate and SPV PJ rights.

OAuth 2.0 Authentication

The library implements the full OAuth 2.0 Authorization Code flow with JWT tokens.

Step 1 -- Redirect the user to ANAF login

@inject AnafOAuthService OAuthService

var authUrl = OAuthService.GetAuthorizationUrl(state: "optional-csrf-token");
NavigationManager.NavigateTo(authUrl, forceLoad: true);

The user authenticates with their qualified digital certificate on logincert.anaf.ro, then ANAF redirects back to your RedirectUri with a ?code= query parameter.

Step 2 -- Exchange the code for tokens

In your callback page/endpoint:

@inject AnafOAuthService OAuthService
@inject InMemoryTokenStore TokenStore

// Extract the authorization code from the callback URL
var code = NavigationManager.Uri.Split("code=")[1].Split("&")[0];

// Exchange for tokens
var tokenInfo = await OAuthService.ExchangeCodeForTokenAsync(code);

// Store the token so AnafApiClient can use it
await TokenStore.SetTokenAsync(tokenInfo);

Step 3 -- Refresh tokens when needed

Access tokens are valid for 90 days, refresh tokens for 365 days.

var currentToken = await TokenStore.GetTokenAsync();
if (currentToken != null && currentToken.IsExpired)
{
    var newToken = await OAuthService.RefreshTokenAsync(currentToken.RefreshToken);
    await TokenStore.SetTokenAsync(newToken);
}

Persisting tokens across restarts

InMemoryTokenStore holds tokens in memory. Subscribe to OnTokenChanged to persist them to your own storage:

// In Program.cs or a startup service
var tokenStore = app.Services.GetRequiredService<InMemoryTokenStore>();
tokenStore.OnTokenChanged += token =>
{
    if (token != null)
    {
        // Save to database, file, etc.
        MyDatabase.SaveToken(token.AccessToken, token.RefreshToken, token.ExpiresAt);
    }
};

// On app startup, restore previously saved tokens
var saved = MyDatabase.LoadToken();
if (saved != null)
{
    await tokenStore.SetTokenAsync(new TokenInfo
    {
        AccessToken = saved.AccessToken,
        RefreshToken = saved.RefreshToken,
        ExpiresAt = saved.ExpiresAt
    });
}

Sending an Invoice

Full workflow example

@inject InvoiceToUblMapper Mapper
@inject AnafApiClient ApiClient

// 1. Build the invoice
var invoice = new InvoiceData
{
    InvoiceNumber = "FV-2024-001",
    IssueDate = new DateTime(2024, 3, 15),
    DueDate = new DateTime(2024, 4, 15),
    CurrencyCode = "RON",
    Supplier = new PartyInfo
    {
        Name = "Firma Mea SRL",
        VatNumber = "RO12345678",
        Cif = "12345678",
        RegistrationNumber = "J40/1234/2020",
        StreetAddress = "Str. Exemplu nr. 1",
        City = "Bucuresti",
        County = "RO-B",
        PostalCode = "010101",
        CountryCode = "RO",
        Email = "contact@firmamea.ro",
        Phone = "+40212345678"
    },
    Customer = new PartyInfo
    {
        Name = "Client SRL",
        VatNumber = "RO87654321",
        Cif = "87654321",
        RegistrationNumber = "J40/5678/2019",
        StreetAddress = "Bd. Clientului nr. 10",
        City = "Cluj-Napoca",
        County = "RO-CJ",
        PostalCode = "400001",
        CountryCode = "RO"
    },
    Lines = new List<InvoiceLine>
    {
        new InvoiceLine
        {
            Description = "Servicii consultanta IT",
            Quantity = 10,
            UnitCode = "HUR",       // hours
            UnitPrice = 150.00m,
            VatPercent = 19,
            VatCategoryCode = "S"
        },
        new InvoiceLine
        {
            Description = "Licenta software",
            Quantity = 1,
            UnitCode = "C62",       // piece
            UnitPrice = 500.00m,
            VatPercent = 19,
            VatCategoryCode = "S",
            ItemId = "SW-LIC-001"
        }
    },
    Payment = new PaymentInfo
    {
        Iban = "RO49AAAA1B31007593840000",
        BankName = "Banca Exemplu",
        PaymentMeansCode = "30",    // bank transfer
        PaymentTerms = "30 zile de la data facturii"
    }
};

// 2. Convert to UBL 2.1 XML (CIUS-RO)
var xml = Mapper.MapToXml(invoice);

// 3. Validate (free, no authentication required)
var validationResult = await ApiClient.ValidateInvoiceAsync(xml, "FACT1");

// 4. Upload to ANAF
var uploadResult = await ApiClient.UploadInvoiceAsync(xml, "UBL", invoice.Supplier.Cif);

if (uploadResult.IsSuccess)
{
    Console.WriteLine($"Uploaded successfully. Index: {uploadResult.UploadIndex}");
}

// 5. Check processing status
var status = await ApiClient.GetMessageStatusAsync(uploadResult.UploadIndex!.Value);
// status.Stare: "ok", "nok", "in prelucrare"

// 6. Download the signed response when ready
if (status.IsOk && status.IdDescarcare.HasValue)
{
    byte[] zip = await ApiClient.DownloadResponseAsync(status.IdDescarcare.Value);
    File.WriteAllBytes("response.zip", zip);
    // ZIP contains: original invoice XML + Ministry of Finance digital signature XML
}

API Reference

All authenticated methods require a valid token stored via InMemoryTokenStore.SetTokenAsync().

AnafApiClient

Method Description Auth
UploadInvoiceAsync(xml, standard, cif, flags?) Upload a B2B invoice Yes
UploadB2CInvoiceAsync(xml, standard, cif, flags?) Upload a B2C invoice Yes
GetMessageStatusAsync(idIncarcare) Check invoice processing status Yes
ListMessagesAsync(days, cif, filter?) List messages for the last N days (1-60) Yes
ListMessagesPaginatedAsync(startMs, endMs, cif, page, filter?) List messages by date range Yes
DownloadResponseAsync(id) Download response ZIP (invoice + signature) Yes
ValidateInvoiceAsync(xml, standard?) Validate XML without uploading No
ConvertToPdfAsync(xml, standard?, skipValidation?) Convert invoice XML to PDF No
TestOauthAsync(name?) Test that your OAuth token works Yes

Upload standards

Value Usage
UBL Standard invoice
CN Credit note
CII CII format
RASP Buyer response message

Upload flags

Use UploadFlags for special cases:

// Foreign buyer (no Romanian CUI/NIF)
await ApiClient.UploadInvoiceAsync(xml, "UBL", cif, new UploadFlags { Extern = true });

// Self-billing (buyer issues invoice on behalf of supplier)
await ApiClient.UploadInvoiceAsync(xml, "UBL", cif, new UploadFlags { AutoFactura = true });

Validation standards

Value Usage
FACT1 Invoice validation
FCN Credit note validation

Message list filters

Value Meaning
E Errors (rejected invoices)
T Sent invoices
P Received invoices
R Buyer messages

Invoice Model Reference

InvoiceData

Property Type Default Description
InvoiceNumber string "" Invoice number (e.g., "FV-2024-001")
IssueDate DateTime Today Invoice issue date
DueDate DateTime? null Payment due date
CurrencyCode string "RON" ISO 4217 currency code
InvoiceTypeCode string "380" 380=Invoice, 381=Credit Note, 389=Self-billing
Supplier PartyInfo Seller/supplier details
Customer PartyInfo Buyer/customer details
Lines List<InvoiceLine> Invoice line items
Note string? null Free-text note
Payment PaymentInfo? null Payment details (IBAN, bank, terms)
DeliveryDate DateTime? null Actual delivery date
OrderReference string? null Purchase order reference

PartyInfo

Property Type Default Description
Name string "" Company name
VatNumber string "" VAT number with country prefix (e.g., "RO12345678")
Cif string "" Numeric CIF only (e.g., "12345678")
RegistrationNumber string? null Trade register number (e.g., "J40/1234/2020")
StreetAddress string "" Street address
City string "" City name
County string? null County/region (e.g., "RO-B")
PostalCode string? null Postal code
CountryCode string "RO" ISO 3166-1 alpha-2 country code
Email string? null Contact email
Phone string? null Contact phone

InvoiceLine

Property Type Default Description
Description string "" Item/service description
Quantity decimal 1 Quantity
UnitCode string "C62" UN/ECE unit code (C62=piece, HUR=hour, KGM=kg, MON=month)
UnitPrice decimal 0 Unit price excluding VAT
VatPercent decimal 19 VAT rate percentage
VatCategoryCode string "S" S=Standard, Z=Zero, E=Exempt, AE=Reverse charge
ItemId string? null Optional seller item identifier
LineTotal decimal computed Quantity * UnitPrice (read-only)
VatAmount decimal computed LineTotal * VatPercent / 100 (read-only)

PaymentInfo

Property Type Default Description
Iban string? null IBAN account number
BankName string? null Bank name
Bic string? null Bank BIC/SWIFT code
PaymentMeansCode string "30" 30=Bank transfer, 10=Cash, 48=Card
PaymentTerms string? null Payment terms text

Project Structure

AnafIntegration/
  AnafEnvironment.cs              URL constants (Test / Production)
  Auth/
    AnafOAuthOptions.cs           ClientId, ClientSecret, RedirectUri, Environment
    AnafOAuthService.cs           OAuth flow: authorization URL, code exchange, token refresh
    TokenInfo.cs                  AccessToken, RefreshToken, ExpiresAt, IsExpired
  Storage/
    InMemoryTokenStore.cs         Thread-safe token store with OnTokenChanged event
  Api/
    AnafApiClient.cs              All e-Factura API endpoints
    Models/
      UploadResponse.cs           Upload result (upload_index, errors)
      MessageStatus.cs            Processing status (ok, nok, in prelucrare)
      MessageListResponse.cs      Message list with pagination
      UploadFlags.cs              Extern, AutoFactura, Executare flags
  Invoice/
    InvoiceModel.cs               POCO models: InvoiceData, PartyInfo, InvoiceLine, PaymentInfo
    InvoiceToUblMapper.cs         Converts InvoiceData to UBL 2.1 XML (CIUS-RO)
  Extensions/
    ServiceCollectionExtensions.cs    AddAnafIntegration() DI registration

ANAF API Limits

Parameter Value
Rate limit 1000 requests / minute
Access token lifetime 90 days
Refresh token lifetime 365 days
Token acquisition window 60 seconds
Message list lookback 1-60 days

HTTP Status Codes

Code Meaning
200 OK Success
403 Forbidden Unauthorized (invalid/expired token or insufficient permissions)
429 Too Many Requests Rate limit exceeded (>1000 requests/minute)

Environment URLs

Environment API Base Auth
Test https://api.anaf.ro/test/FCTEL/rest https://logincert.anaf.ro/anaf-oauth2/v1/authorize
Production https://api.anaf.ro/prod/FCTEL/rest https://logincert.anaf.ro/anaf-oauth2/v1/authorize
Validation (no auth) https://api.anaf.ro/prod/FCTEL/rest/validare N/A
Product Compatible and additional computed target framework versions.
.NET net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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.5 134 3/5/2026
1.0.4 105 3/5/2026