.NET SDK
Install the .NET SDK, build a client, see every method with a .NET sample, and verify records offline.
.NET
Invoance on NuGet.
.NET 8.0. Every network method ends in Async, returns a Task and takes an optional CancellationToken.
dotnet add package Invoance
| ApiKey | The API key. Falls back to INVOANCE_API_KEY; ArgumentException when neither is set. |
|---|---|
| BaseUrl | API host. Falls back to INVOANCE_BASE_URL, then https://api.invoance.com. Trailing slashes are removed. |
| ApiVersion | Path prefix put before every request path. Default v1. |
| Timeout | Per-request timeout as a TimeSpan. Default 30 seconds; past it the call throws TimeoutException. |
| IdempotencyKey | Default Idempotency-Key header for every mutating request; a per-call key wins. |
| ExtraHeaders | Headers merged into every request. |
| Retries | None. Each request is sent once; on TimeoutException or NetworkException, retry it yourself with the same Idempotency-Key. |
using Invoance;
// Reads INVOANCE_API_KEY and INVOANCE_BASE_URL from the environment.
using var client = new InvoanceClient();
// Or pass options.
using var configured = new InvoanceClient(new InvoanceClientOptions
{
ApiKey = "invoance_live_...",
BaseUrl = "https://api.invoance.com",
Timeout = TimeSpan.FromSeconds(60),
});
// Never throws.
var (valid, reason, baseUrl) = await client.ValidateAsync();
Console.WriteLine($"{valid} {reason} {baseUrl}");
Every endpoint with a .NET sample, by resource. Open a row for the sample; the link opens the endpoint card with its fields, response and errors.
POST/v1/events
using Invoance;
using Invoance.Models;
// Reads INVOANCE_API_KEY from the environment.
using var client = new InvoanceClient();
var result = await client.Events.IngestAsync(new IngestEventParams
{
EventType = "policy.approval",
EventTime = "2026-09-22T08:14:07Z",
Payload = new Dictionary<string, object?>
{
["policy_id"] = "pol_8472",
["approved_by"] = "risk_committee",
["decision"] = "approved",
},
IdempotencyKey = "policy-approval-pol_8472",
});
Console.WriteLine(result.EventId + " " + result.IngestedAt);
GET/v1/events
using Invoance;
using Invoance.Models;
// Reads INVOANCE_API_KEY from the environment.
using var client = new InvoanceClient();
var page = await client.Events.ListAsync(new ListEventsParams
{
Page = 1,
Limit = 50,
EventType = "policy.approval",
});
Console.WriteLine(page.Total + " " + page.HasMore);
foreach (var item in page.Events)
{
Console.WriteLine(item.EventId + " " + item.IngestedAt + " " + item.PayloadHash);
}
GET/v1/events/{event_id}
using Invoance;
using Invoance.Models;
// Reads INVOANCE_API_KEY from the environment.
using var client = new InvoanceClient();
ComplianceEvent ev = await client.Events.GetAsync("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4");
Console.WriteLine(ev.EventType + " " + ev.IngestedAt);
Console.WriteLine(ev.PayloadHash + " " + ev.EventHash + " " + ev.RequestHash);
foreach (var pair in ev.Payload)
{
Console.WriteLine(pair.Key + "=" + pair.Value);
}
POST/v1/events/{event_id}/verify
using Invoance;
using Invoance.Models;
// Reads INVOANCE_API_KEY from the environment.
using var client = new InvoanceClient();
var result = await client.Events.VerifyAsync("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4", new VerifyEventParams
{
Payload = new Dictionary<string, object?>
{
["policy_id"] = "pol_8472",
["approved_by"] = "risk_committee",
["decision"] = "approved",
},
});
Console.WriteLine(result.MatchResult + " " + result.MatchedField);
Console.WriteLine(result.AnchoredHash + " " + result.SubmittedHash + " " + result.AnchoredAt);
POST/v1/document/anchor
using System.Security.Cryptography;
using Invoance;
using Invoance.Models;
var file = await File.ReadAllBytesAsync("./INV-2026-0917.pdf");
var documentHash = Convert.ToHexString(SHA256.HashData(file)).ToLowerInvariant();
// Reads INVOANCE_API_KEY from the environment.
using var client = new InvoanceClient();
var result = await client.Documents.AnchorAsync(new AnchorDocumentParams
{
DocumentHash = documentHash,
DocumentRef = "INV-2026-0917.pdf",
EventType = "invoice.issued",
Metadata = new Dictionary<string, object?>
{
["invoice_number"] = "INV-2026-0917",
["amount"] = 5230,
["currency"] = "USD",
},
IdempotencyKey = "anchor-" + documentHash,
});
Console.WriteLine(result.EventId + " " + result.Status);
GET/v1/document
using Invoance;
using Invoance.Models;
// Reads INVOANCE_API_KEY from the environment.
using var client = new InvoanceClient();
var page = await client.Documents.ListAsync(new ListDocumentsParams
{
Limit = 25,
DateFrom = "2026-09-01T00:00:00Z",
});
Console.WriteLine(page.Total + " " + page.HasMore);
foreach (var d in page.Documents)
{
Console.WriteLine(d.EventId + " " + d.DocumentRef + " " + d.HasOriginal);
}
GET/v1/document/{event_id}
using Invoance;
// Reads INVOANCE_API_KEY from the environment.
using var client = new InvoanceClient();
var doc = await client.Documents.GetAsync("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4");
Console.WriteLine(doc.DocumentHash + " " + doc.HasOriginal + " " + doc.CreatedAt);
if (doc.Organization != null)
{
Console.WriteLine(doc.Organization.IssuerName + " " + doc.Organization.DomainVerified);
}
GET/v1/document/{event_id}/original
using Invoance;
// Reads INVOANCE_API_KEY from the environment.
using var client = new InvoanceClient();
var data = await client.Documents.GetOriginalAsync("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4");
await File.WriteAllBytesAsync("./INV-2026-0917.pdf", data);
Console.WriteLine(data.Length);
POST/v1/document/{event_id}/verify
using System.Security.Cryptography;
using Invoance;
using Invoance.Models;
var file = await File.ReadAllBytesAsync("./INV-2026-0917.pdf");
var documentHash = Convert.ToHexString(SHA256.HashData(file)).ToLowerInvariant();
// Reads INVOANCE_API_KEY from the environment.
using var client = new InvoanceClient();
var result = await client.Documents.VerifyAsync("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4", new VerifyDocumentParams
{
DocumentHash = documentHash,
});
Console.WriteLine(result.MatchResult + " " + result.AnchoredHash + " " + result.AnchoredAt);
POST/v1/ai/attestations
using Invoance;
using Invoance.Models;
// Reads INVOANCE_API_KEY from the environment.
using var client = new InvoanceClient();
var result = await client.Attestations.IngestAsync(new IngestAttestationParams
{
Type = "output",
Input = "Summarize the termination clause in contract CT-8472.",
Output = "Either party may terminate with 30 days written notice. Early termination fees do not apply after month 12.",
ModelProvider = "openai",
ModelName = "gpt-4.1",
ModelVersion = "2026-04-14",
Subject = new AttestationSubject
{
UserId = "u_4821",
SessionId = "sess_9f3a",
Extra = new Dictionary<string, object?> { ["department"] = "legal" },
},
IdempotencyKey = "ct-8472-summary-1",
});
Console.WriteLine($"{result.AttestationId} {result.PayloadHash}");
GET/v1/ai/attestations
using Invoance;
using Invoance.Models;
// Reads INVOANCE_API_KEY from the environment.
using var client = new InvoanceClient();
var page = await client.Attestations.ListAsync(new ListAttestationsParams
{
Limit = 50,
AttestationType = "output",
ModelProvider = "openai",
});
Console.WriteLine($"{page.Total} {page.HasMore} {page.Attestations.Count}");
GET/v1/ai/attestations/{attestation_id}
using Invoance;
// Reads INVOANCE_API_KEY from the environment.
using var client = new InvoanceClient();
var att = await client.Attestations.GetAsync("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4");
Console.WriteLine($"{att.AttestationHash} {att.SignatureAlg} {att.PublicKey}");
GET/v1/ai/attestations/{attestation_id}/raw
using Invoance;
// Reads INVOANCE_API_KEY from the environment.
using var client = new InvoanceClient();
var raw = await client.Attestations.GetRawAsync("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4");
Console.WriteLine(raw?["type"]?.ToString());
Console.WriteLine(raw?["context"]?["model_name"]?.ToString());
POST/v1/ai/attestations/{attestation_id}/verify
using Invoance;
using Invoance.Models;
// Reads INVOANCE_API_KEY from the environment.
using var client = new InvoanceClient();
var result = await client.Attestations.VerifyAsync("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4", new VerifyAttestationParams
{
ContentHash = "c4efe15781214a84046ad7e0592977c634a5cf45f4c1e06160daf760a295a8df",
});
Console.WriteLine($"{result.MatchResult} {result.MatchedField}");
POST/v1/traces
using Invoance;
using Invoance.Models;
// Reads INVOANCE_API_KEY from the environment.
using var client = new InvoanceClient();
var trace = await client.Traces.CreateAsync(new CreateTraceParams
{
Label = "Invoice batch 2026-09",
Metadata = new Dictionary<string, object?>
{
["batch_id"] = "b_4471",
["region"] = "eu-west",
},
});
Console.WriteLine($"{trace.TraceId} {trace.Status}");
POST/v1/traces/{trace_id}/seal
using Invoance;
// Reads INVOANCE_API_KEY from the environment.
using var client = new InvoanceClient();
var sealed = await client.Traces.SealAsync("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4");
Console.WriteLine($"{sealed.Status} {sealed.Message}");
POST/v1/audit/events
using Invoance;
using Invoance.Models;
// Reads INVOANCE_API_KEY from the environment.
using var client = new InvoanceClient();
var result = await client.Audit.Events.IngestAsync(new IngestAuditEventParams
{
OrganizationId = "org_8472",
Action = "user.signed_in",
OccurredAt = "2026-09-22T08:14:07Z",
Actor = new Dictionary<string, object?>
{
["type"] = "user",
["id"] = "u_4821",
["name"] = "Ada Lovelace",
},
Targets = new List<IDictionary<string, object?>>
{
new Dictionary<string, object?> { ["type"] = "workspace", ["id"] = "ws_17" },
},
Context = new Dictionary<string, object?>
{
["location"] = "203.0.113.10",
["user_agent"] = "Mozilla/5.0",
},
Metadata = new Dictionary<string, object?> { ["method"] = "sso", ["mfa"] = true },
IdempotencyKey = "signin-u_4821-2026-09-22T08:14:07Z",
});
Console.WriteLine(result?["event_id"] + " " + result?["ingested_at"]);
POST/v1/audit/orgs
using Invoance;
using Invoance.Models;
// Reads INVOANCE_API_KEY from the environment.
using var client = new InvoanceClient();
var org = await client.Audit.Orgs.CreateAsync(new CreateAuditOrgParams
{
OrganizationId = "org_8472",
Name = "Acme Robotics",
});
Console.WriteLine(org?["id"] + " " + org?["retention_days"]);
GET/v1/me
using Invoance;
// Reads INVOANCE_API_KEY from the environment.
using var client = new InvoanceClient();
var me = await client.MeAsync();
Console.WriteLine(me?["organization"]?["primary_domain"]);
Console.WriteLine(me?["limits"]?["rate_limit_per_sec"]);
Two checks run without trusting the server: Attestations.VerifySignatureAsync fetches the record and checks its Ed25519 signature over signed_payload; AuditVerify.VerifyAuditEvent (namespace Invoance.Internal) rebuilds the invoance.audit/1 bytes of an audit event, given as a dictionary of its wire fields, and checks its signature. Pass the hex key from GET /keys/{domain} as the second argument to pin it instead of the key on the row.
using Invoance;
using Invoance.Internal;
using var client = new InvoanceClient();
// AI attestation: Ed25519 over signed_payload, checked locally.
var sig = await client.Attestations.VerifySignatureAsync("a1d4f8c2-7b3e-4e9a-b5c6-0d2e8f4a7c19");
Console.WriteLine($"{sig.Valid} {sig.Reason}");
// Audit event: canonical bytes rebuilt locally, signature checked
// against a pinned key (the public_key from GET /keys/{domain}, base64url decoded to hex).
var pinnedHexKey = "d4443bd9d30ef4c2e0e5db03467e3c5c740358482c1a1e30cdb27a2e02a38176";
var evt = await client.Audit.Events.GetAsync("aevt_01J8F3KQ2R7VWX9YB4ND6MCZAH");
var map = new Dictionary<string, object?>
{
["id"] = evt.Id,
["org_id"] = evt.OrgId,
["seq"] = evt.Seq,
["occurred_at"] = evt.OccurredAt,
["ingested_at"] = evt.IngestedAt,
["action"] = evt.Action,
["actor"] = evt.Actor,
["targets"] = evt.Targets,
["context"] = evt.Context,
["metadata"] = evt.Metadata,
["payload_hash"] = evt.PayloadHash,
["signature"] = evt.Signature,
["signing_public_key"] = evt.SigningPublicKey,
};
var result = AuditVerify.VerifyAuditEvent(map, pinnedHexKey);
Console.WriteLine($"{result.Valid} {result.Reason} {result.KeySource}"); // pinned