Configuration

RepostClientOptions, credential and endpoint precedence, timeouts and retries with production defaults, and the injectable transport, clock, and generators.

The generated client takes a RepostClientOptions. The constructor validates every value and snapshots the result; mutating the options instance afterwards never affects a constructed client. The defaults are the production values.

Client options

await using var repost = new RepostClient(new RepostClientOptions
{
    ApiKey = Environment.GetEnvironmentVariable("REPOST_SEND_API_KEY"),
    BaseUri = "https://api.repost.sh",
    OperationTimeout = TimeSpan.FromSeconds(30),
    MaxAttempts = 4,
});

Credential and endpoint precedence

Credentials, highest first: an ApiKeyProvider (resolved once per send) or a fixed ApiKey (the two conflict, so set only one), then the REPOST_SEND_API_KEY environment variable, then REPOST_TOKEN, both snapshotted at construction. With none set, the first send fails with a Configuration error and never touches the network.

Base URI: an explicit BaseUri, then REPOST_API_URL, then the default https://api.repost.sh. Trailing slashes are stripped and /v1/messages is appended. Lowercase http:// is accepted only for loopback hosts.

RepostClientOptions.ToString() is redacted: it never prints your credential.

Defaults

The defaults are production-ready:

OptionDefaultNotes
ConnectTimeout10sConnection establishment.
AttemptTimeout30sOne HTTP attempt, clamped to the remaining operation budget.
OperationTimeout120sWhole operation, including retries: the one deadline that bounds a send.
MaxAttempts41–10. Transport attempts before giving up.
RetryBaseDelay / RetryMaxDelay250ms / 60sExponential backoff with full jitter.
MaxInFlightOperations2561–65,536. Bounded admission. See Reliability.
MaxBufferedBytes64 MiB4 MiB–1 GiB. Aggregate request/response byte budget.
TelemetryEnabledtrueThe built-in Repost.Client ActivitySource and Meter.
TraceParentPropagationEnabledtrueW3C traceparent/tracestate request headers.

Every request goes to POST <BaseUri>/v1/messages with Authorization: Bearer, Content-Type: application/json, and Idempotency-Key headers.

Custom transport and enterprise networking

Retries, timeouts, and cancellation always stay with the runtime; a transport executes exactly one attempt. Set HttpTransportOptions to configure the built-in transport (an explicit HttpProxyOptions, a custom X509Certificate2Collection trust store, client certificates for mutual TLS, and, on .NET 8, a custom IDnsResolver), or set Transport to a custom ITransport. The two conflict.

Injectable generators

The runtime asks injectable functions for values it has to invent. Set DefaultValueGenerators for the @default(now()/uuid()/cuid()) seams and the envelope timestamp, and IdempotencyKeyGenerator for minted keys:

var options = new RepostClientOptions
{
    IdempotencyKeyGenerator = () => Guid.NewGuid().ToString(),
};

Now() is snapshotted once per send, so the envelope timestamp and any @default(now()) field in the same event always match. The default idempotency-key generator is Guid.NewGuid().ToString(), and the default value generators are the system implementations. TimeProvider (deadlines, retry pacing, and Retry-After evaluation) and RetryEntropy (CSPRNG-backed jitter) are injectable too; Testing covers the deterministic implementations that ship in Repost.Client.Testing.

Dependency injection

The Repost.Client.DependencyInjection package registers RepostClientOptions with the options pattern and binds it from IConfiguration. Scalar options bind by name (ApiKey, BaseUri, the TimeSpan timeouts, MaxAttempts, …); the non-scalar options (Transport, Observer, ApiKeyProvider, and the generators) stay code-only through a configure action:

services.AddRepostClient(configuration.GetSection("Repost"));
services.AddRepostClient(options => options.Observer = new MyObserver());

Continue