Internal, product-neutral typed HTTP client for signed service-to-service communication with DreamConsistency.Billing.Api. The initial release provides Invoice List and Invoice Details reads.
DreamConsistency.Billing.Client is the standard HTTP integration package for Dream Consistency backend services that need to call DreamConsistency.Billing.Api. It provides a typed client, request/response models, consistent transport error handling, and request signing through the existing ServiceAuth infrastructure.
Its first published release, 1.0.0, exposes Invoice List and Invoice Details. It does not create, issue, cancel, or otherwise mutate Invoices.
| Property | Current Decision |
|---|---|
| Package ID | DreamConsistency.Billing.Client |
| Initial Release | 1.0.0 — published 28 October 2026 |
| Target Framework | netstandard2.1 (.NET Standard 2.1) |
| NuGet Feed | https://nuget.dreamconsistency.com/v3/index.json |
| Hosting | Private BaGetter package feed |
| Repository | Bitbucket — dreamconsistency.billing.client |
| Release Pipeline | DreamConsistency.Billing.Client - NuGet Release |
| Jenkins Folder | DreamConsistency - Packages |
| Publication | Manual, parameter-controlled Jenkins publish from master |
| Versioning | Semantic Versioning — MAJOR.MINOR.PATCH |
| Scope | Internal Dream Consistency shared library |
| Package | Version | Purpose |
|---|---|---|
DreamConsistency.Extensions |
1.2.0 |
Shared BaseClient infrastructure, service descriptor and serialization dependencies. |
DreamConsistency.Security.ServiceAuth |
1.0.1 |
Signed outbound API-to-API requests using the existing ServiceAuth handler. |
Microsoft.Extensions.DependencyInjection.Abstractions |
6.0.0 |
Service registration abstractions. |
Microsoft.Extensions.Http |
6.0.0 |
Typed HttpClientFactory registration. |
System.Security.Cryptography.Pkcs |
10.0.13 |
Patched dependency floor for an otherwise vulnerable transitive package. |
System.Security.Cryptography.Pkcs 10.0.13 reference prevents the older vulnerable transitive versions brought in through Extensions → MailKit → MimeKit. The release pipeline includes a full dependency vulnerability audit.| Area | Responsibility |
|---|---|
| Typed API integration | Expose approved Billing.Api operations through stable client methods and typed models. |
| Invoice List | Read paginated invoices belonging to a canonical Realm TenantID. |
| Invoice Details | Read one Invoice, its items and persisted party snapshots. |
| Service-to-service authentication | Attach DreamConsistencyInternalServiceAuthHandler to outbound requests. |
| Endpoint discovery | Resolve Billing.Api base URL from the Dream Consistency service descriptor. |
| Response validation | Reject malformed responses and missing required wire fields. |
| Error handling | Preserve Billing HTTP 420 outcomes and distinguish transport/server failures. |
| Cancellation | Propagate caller cancellation; do not automatically retry requests. |
The public API is deliberately small. Consumers request an IBillingClient from IBillingClientFactory. Internal wire models validate the API response before populating the public DTOs.
Billing.Client obtains its endpoint exclusively from the configured Dream Consistency service descriptor:
This value must be the reachable Billing.Api base address for the current environment. The client is product-neutral and Realm-neutral: it does not select Realms using a request parameter.
Configure the internal NuGet package feed in the consuming repository. For example:
Install the published package:
Alternatively, add the following to the consuming project file:
Register the package from the consuming backend startup (typically Program.cs):
The extension registers the named typed HttpClient Billing Client, attaches DreamConsistencyInternalServiceAuthHandler, and adds a singleton IBillingClientFactory. The public IBillingClient is intentionally obtained through the factory rather than registered for direct injection.
Use dependency injection to obtain the factory and create a client. The TenantRefID parameter is always the internal Realm TenantID, not TenantUUID.
| Client method | HTTP route | Key parameters |
|---|---|---|
GetInvoiceList |
GET /api/billing/tenants/{tenantRefId}/invoices |
TenantRefID, optional Limit, optional AfterInvoiceID |
GetInvoiceDetails |
GET /api/billing/tenants/{tenantRefId}/invoices/{invoiceId} |
TenantRefID, InvoiceID |
Both operations are reads. GetInvoiceList returns an InvoiceListResponse with Items and NextAfterInvoiceID. GetInvoiceDetails returns header fields, item snapshots, and stored party snapshots.
Create Draft, Issue Invoice, refunds, payments, credit notes, BillingRun dispatch and automated financial execution are not exposed by this package release.
| Property | Behavior |
|---|---|
| Ordering | CreationTimestamp DESC, then InvoiceID DESC (Billing.Api ordering). |
Limit |
Optional integer; default 50 on the server; accepted range 1–100. |
AfterInvoiceID |
Optional Guid cursor from the previous response. |
NextAfterInvoiceID |
Guid cursor for the next page; null on the last page. |
| Invalid paging inputs | Sent unchanged to Billing.Api; the server validates and refuses invalid values. |
| Tenant scope | The same authorized Realm TenantID must be used on every page. |
Example:
| Contract area | Behavior |
|---|---|
| Identifiers | C# Guid values; lowercase D-format in routes. |
| Amounts, rates, quantities | JSON numeric values deserialized as decimal, not double. |
| Timestamps | C# DateTime values normalized to UTC. Offset-free timestamps are interpreted as UTC. |
| Status | Use InvoiceStatusUUID for identity; InvoiceStatusName is display-only. |
| Invoice list | Contains InvoiceSummaryResponse items and a nullable next-page cursor. |
| Invoice details | Includes item and party snapshot arrays as returned by Billing.Api. |
| Nullability | Nullable financial/party fields remain nullable. Empty collections are returned as empty arrays/lists. |
| Required fields | Missing required wire fields produce JsonException rather than default zero/empty values. |
| JSON naming | Matches Billing.Api camelCase naming, including properties such as invoiceID, tenantRefID and vatIdentificationNumber. |
| HTTP / outcome | Client behavior |
|---|---|
200 |
Returns typed Invoice response. |
420 |
Throws InvoiceListFailedException or InvoiceDetailsFailedException with Billing ErrorCode. |
400 / 401 / 404 / 500 / 503 |
Throws HttpRequestException (HTTP status is preserved by transport). |
| Invalid success or error JSON | Throws JsonException. |
| Network failure | Propagates the transport exception. |
| Cancellation | Propagates OperationCanceledException. |
Declared Billing error codes for these reads:
| Billing error code | Meaning |
|---|---|
30001 |
InvalidRequest — invalid tenant, limit or cursor. |
30004 |
InvoiceNotFound — absent, soft-deleted or cross-Tenant Invoice; intentionally indistinguishable. |
500 |
Invoice access refused inside HTTP 420; not an HTTP 500 response. |
Example:
FrontDebugMessage is for internal diagnostics only. Never parse it to make authorization decisions or display it directly to end users.| Security area | Responsibility |
|---|---|
| User authentication | The consuming backend (e.g. Hestino.Management.Api). |
| User permissions and Tenant access | The consuming backend resolves authorized Tenant selection. |
| Canonical Tenant reference | Route uses the Realm TenantID, never TenantUUID. |
| Service authentication | DreamConsistency.Security.ServiceAuth 1.0.1 signs outbound internal requests. |
| Service authorization | Billing.Api must verify the calling service and expressly permit Invoice read operations. |
| Tenant isolation | Billing.Api filters Invoice lists by persisted Tenant and checks ownership for Details. |
| Secrets | Configured by the consuming runtime, never shipped with the package. |
| Transport | Use HTTPS/TLS in deployment; HMAC signing alone does not encrypt transport. |
| Retries | No automatic retries. |
The existing ServiceAuth handler signs the HTTP method and final path/query through its V2 request signature. This does not independently establish the permissions of the human Management user.
| Allowed in Billing.Client | Not Allowed in Billing.Client |
|---|---|
| Typed Billing.Api HTTP methods | Billing server-side financial business logic |
| Request, response and error DTOs | Direct BillingDB or EntityManager access |
| HTTP transport and DI registration | Management user permissions or RAP evaluation |
| Factory abstraction | Creating, issuing or correcting Invoices without an approved API contract |
| Shared ServiceAuth handler integration | Custom service identity headers or a new signing framework |
| Response parsing and UTC normalization | Business calculation of Invoice totals and taxes |
| Transport error reporting | Product-specific Hestino or Legislator rules |
Package releases are controlled by the Product Owner through Jenkins after reviewed changes reach master. Published NuGet versions are immutable.
PUBLISH_PACKAGE=false first. Publishing requires PUBLISH_PACKAGE=true, an allowed master checkout and Jenkins credential dreamconsistency-nuget-api-key. Never overwrite an existing NuGet version.| Setting | Value |
|---|---|
| Jenkins Folder | DreamConsistency - Packages |
| Job Name | DreamConsistency.Billing.Client - NuGet Release |
| Repository | git@bitbucket.org:skyrocket_novisad/dreamconsistency.billing.client.git |
| Branch | master |
| Script Path | Jenkinsfile |
| Agent Image | mcr.microsoft.com/dotnet/sdk:10.0 |
| Version Parameter | PACKAGE_VERSION=1.0.0 for initial release |
| Publish Parameter | PUBLISH_PACKAGE=false for validation; true for controlled release |
| NuGet Credential | dreamconsistency-nuget-api-key |
| NuGet Feed | https://nuget.dreamconsistency.com/v3/index.json |
| Output | artifacts/nuget archived by Jenkins |
| Validation | Restore, full transitive audit, Debug/Release build and tests, formatting, package creation. |
Jenkins runs in a Linux container. File and directory capitalization must match Git exactly (especially the NuGet configuration path in Jenkinsfile). This was an issue during initial pipeline setup and was resolved before the first package publication.
| Check | Initial release evidence |
|---|---|
| Offline unit tests | 62/62 PASS in both Debug and Release (7 foundation + 55 Invoice tests). |
| Package creation | 1.0.0 package prepared and published to internal BaGetter feed. |
| NuGet vulnerability audit | No vulnerable dependencies reported after Pkcs 10.0.13 fix. |
| Request signing | Offline tests cover the existing ServiceAuth handler and request-bound V2 signature. |
| Invoice wire formats | Offline tests cover response mapping, money precision, UTC normalization and HTTP 420. |
| Real Billing.Api List/Get | Not yet demonstrated by the Client package release alone. |
| Real BillingDB 1.5.0 read | Separate controlled end-to-end integration validation required. |
| Version type | Example | When to use |
|---|---|---|
| Initial | 1.0.0 |
First published package including the typed List/Get API. |
| Patch | 1.0.1 |
Compatible bug fix or security correction. |
| Minor | 1.1.0 |
New backward-compatible Billing API method or model. |
| Major | 2.0.0 |
Breaking public method, model or serialization change. |
1.0.0 is already published. Any subsequent change requires a new version; do not re-publish or replace 1.0.0.| Step | Action |
|---|---|
| 1 | Install DreamConsistency.Billing.Client 1.0.0 in the approved Management.Api branch. |
| 2 | Configure RealmCoreMsLocations.Billing and ServiceAuth runtime credentials. |
| 3 | Register the client using AddBillingClient(). |
| 4 | Enforce Management user permissions and resolve TenantUUID to Realm TenantID. |
| 5 | Consume GetInvoiceList and GetInvoiceDetails through the factory. |
| 6 | Verify Billing.Api accepts only the explicitly approved Management caller for Invoice reads. |
| 7 | Perform controlled real-service tests against BillingDB 1.5.0 before declaring the workflow operational. |
| Risk / note | Required behavior |
|---|---|
| Service identity ambiguity | A shared signing key or identifier header is not sufficient by itself; Billing.Api must verify the authorized caller. |
| TenantUUID vs TenantID | Resolve the canonical Realm TenantID before calling Billing.Client. |
| Billing 420 vs HTTP 500 | Always distinguish HTTP status before Billing error code. |
| UTC timestamp format | Handle Z, explicit offsets and offset-free dates consistently as UTC. |
| Snapshot integrity | Read the financial snapshot as persisted; do not reconstruct it from changing Management records. |
| New invoice operations | Only add methods after the Billing.Api HTTP and DTO contract is explicitly accepted. |
| NuGet security findings | Keep transitive auditing enabled and update vulnerable dependencies in future releases. |
| Jenkins Linux case sensitivity | Keep NuGet configuration filename capitalization consistent between Git and Jenkinsfile. |
| Functional readiness | Passing offline tests and publishing NuGet do not prove a live authenticated Billing API call. |
Maintain detailed developer usage, public method changes, dependency versions and release notes in the Billing.Client repository README.md. This Wiki.js page is the shared operational and integration reference for consumers and the release pipeline.
| Date | Change | Author |
|---|---|---|
| 2026-10-28 | First package DreamConsistency.Billing.Client 1.0.0 published to the internal NuGet feed. |
Dream Consistency |
| 2026-10-28 | Typed Invoice List/Get operations, DTOs, HTTP 420 handling, ServiceAuth signing and patched Pkcs dependency documented. | Dream Consistency |
| 2026-10-28 | Jenkins release pipeline configured and first package publication verified. | Dream Consistency |