Eventing SDK
.NET — Axowl.Sdk.Eventing.Client
Section titled “.NET — Axowl.Sdk.Eventing.Client”dotnet add package Axowl.Sdk.Eventing.ClientThe SDK is bi-directional:
- Publish customer-defined events (
custom.wallet.topup, …) — Axowl seals and archives them in the same chain as managed events (user.login,korean_identity.verified, …). - Poll events back — cursor-based, unary RPC (no streaming, so it works behind free-tier proxies).
builder.Services.AddAxowlEventing(opts =>{ opts.ApiKey = builder.Configuration["Axowl:ApiKey"]!; // org API key (ah_live_...) opts.Transport = TransportMode.GrpcWithFallback;});
// inject IAxowlEventClientvar sealedEvent = await axowl.PublishAsync( eventType: "custom.wallet.topup", businessDataJson: JsonSerializer.Serialize(new { req.UserId, req.Amount }), triggeredBy: principal.ConnectedId?.ToString()); // the actor's ConnectedId
var page = await axowl.PollAsync(cursor: null, eventTypes: new[] { "custom.wallet.*" });// page.Events, page.NextCursor (pass it to the next call), page.HasMorePublishAsync returns the sealed proof — LogId, IntegrityHash, Signature, SealedAt — which you can
store next to your own row. Rules the server enforces:
eventTypemust start withcustom.; any other name is refused withPERMISSION_DENIED.businessDataJsonmust be valid JSON (or empty); otherwiseINVALID_ARGUMENT.triggeredByis the actor’s ConnectedId (a GUID), or empty for a system actor; any other value isINVALID_ARGUMENT.- A key that lists allowed scopes must include
ledger.writeto publish; otherwisePERMISSION_DENIED. A key with no allowed-scope list can publish.
PollAsync returns events after cursor in time order. eventTypes accepts wildcards (custom.*);
limit defaults to 100 and is capped at 500. Polling serves the most recent three days of events; with no
cursor and no sinceUtc it starts from the oldest event in that window. Polling returns the
organization’s events, so it needs an org-wide key: a key scoped to one App Group or one
application is refused with PERMISSION_DENIED.
Options
Section titled “Options”| Option | Default | What it is |
|---|---|---|
ApiKey | — (required) | Org API key, sent as Authorization: Bearer …. |
Transport | TransportMode.Grpc | Grpc, GrpcWithFallback (gRPC first, REST when gRPC cannot get through) or RestOnly. |
ServerAddress | https://grpc.axowl.com | gRPC endpoint. |
RestServerAddress | https://api.axowl.com | REST endpoint (POST /v1/events/publish, POST /v1/events/poll). |
CallTimeout | 10 seconds | Deadline for each call. |
PollInterval | 5 seconds | Polling service: wait between polls when nothing new arrived. |
Limit | 100 | Polling service: batch size. |
EventTypes / Categories | empty (everything) | Polling service: filters. |
SinceUtc | null | Polling service: where to start when there is no cursor yet (null = the oldest event in the three-day window). |
Background polling — IAxowlEventHandler
Section titled “Background polling — IAxowlEventHandler”Pass enablePollingService: true to run a hosted background poller that hands each event to your handlers:
builder.Services.AddAxowlEventing(opts =>{ opts.ApiKey = builder.Configuration["Axowl:ApiKey"]!; opts.EventTypes = new[] { "custom.*", "korean_identity.*" };}, enablePollingService: true);
builder.Services.AddSingleton<IAxowlEventHandler, WalletHandler>();
public sealed class WalletHandler : IAxowlEventHandler{ public IReadOnlyList<string> EventTypePatterns => new[] { "custom.wallet.*" };
public Task HandleAsync(AxowlEvent e, CancellationToken ct) { // e.LogId, e.EventType, e.BusinessData (raw JSON), e.IntegrityHash return Task.CompletedTask; }}The poller keeps its cursor in memory, so after a restart it starts again from SinceUtc. AxowlEvent.LogId
is the idempotency key — de-duplicate on it in your handler. A handler that throws is logged and the event is
not delivered to it again.
Events published through the SDK join the sealed audit chain (see Events catalog).