.NET SDK
The GoodMem .NET SDK offers an OpenAI-style API where any operation is accessed through client.<Namespace>.<Method>Async(...) on a GoodmemClient. The surface is async-only — every network method returns a Task<T> (or an IAsyncEnumerable<T> for pagination and streaming) and takes a CancellationToken; deadlines and cancellation come from the token you pass in.
Installation
dotnet add package PairSystems.Goodmem.Clientusing Goodmem.Client;Requirements: .NET 8 or later — the package targets net8.0 and net10.0, so it works on .NET 8 (LTS), 9, and 10. The SDK depends only on the base class library (System.Text.Json).
Client
GoodmemClient is safe for concurrent use. Construct it in one of two mutually exclusive modes.
// SDK-managed HttpClient (base URL + API key):
using var client = new GoodmemClient(new GoodmemClientOptions
{
BaseUrl = "http://localhost:8080",
ApiKey = "gm_...",
});- The base URL may carry a mount-path prefix (e.g.
https://host/api) — it is preserved on every request. - An empty API key is allowed (the unauthenticated bootstrap endpoints
/v1/system/infoand/v1/system/initare callable without one); every other endpoint returns401. - To supply your own
HttpClient(proxy, custom TLS, handlers), pass it viaGoodmemClientOptions.HttpClient. In bring-your-own mode you own the redirect policy; the SDK-built default refuses redirects so thex-api-keyheader cannot leak across a host boundary.
Pagination
List methods return an IAsyncEnumerable<T>; await foreach walks every item across pages transparently, and break stops fetching further pages.
await foreach (var memory in client.Memories.ListAsync(spaceId))
{
// handle each memory
}Streaming
Streaming methods (memories.retrieve, ping.stream) also return an IAsyncEnumerable<T> over the NDJSON event stream; the connection is released when iteration ends or you break.
await foreach (var ev in client.Memories.RetrieveAsync("What do you know about ...?"))
{
// handle each retrieval event
}Errors
Every method throws a typed exception on failure. Transport problems surface as NetworkException; non-2xx HTTP responses surface as an ApiException (or one of its status-specific subtypes). All derive from GoodmemException.
try
{
var space = await client.Spaces.GetAsync(spaceId);
}
catch (NotFoundException)
{
// 404 — handle missing space
}
catch (ApiException e)
{
Console.WriteLine($"server returned {e.StatusCode}: {e.Body}");
}The status-specific subtypes are BadRequestException (400), AuthenticationException (401), PermissionDeniedException (403), NotFoundException (404), ConflictException (409), UnprocessableEntityException (422), RateLimitException (429) and InternalServerException (5xx). All derive from ApiException, so a catch (ApiException) matches any of them.
Namespaces
| Namespace | Description | Reference |
|---|---|---|
Embedders | Embedder management | client.Embedders |
Rerankers | Reranker management | client.Rerankers |
Llms | LLM management | client.Llms |
Spaces | Memory space management | client.Spaces |
Memories | Memory CRUD, retrieval, and batch operations | client.Memories |
Ocr | Document text extraction | client.Ocr |
System | Server info and initialization | client.System |
Users | User lookup | client.Users |
Admin | Server lifecycle operations | client.Admin |
ApiKeys | API key lifecycle management | client.ApiKeys |
Ping | Endpoint health probes (single-shot and streaming) | client.Ping |
Common Data Models
Wire types shared across namespaces. Fields are shown with their C# property names; JSON payloads use the camelCase wire name noted on each field.
ProviderType
Embedding provider types
String enum: "OPENAI" · "VLLM" · "TEI" · "LLAMA_CPP" · "VOYAGE" · "COHERE" · "JINA"
Modality
Content modality types supported by embedders
String enum: "TEXT" · "IMAGE" · "AUDIO" · "VIDEO"
EndpointAuthentication
Structured credential payload describing how GoodMem should authenticate with an upstream provider.
| Property | Type | JSON (wire) | Description |
|---|---|---|---|
Kind | CredentialKind | kind | Selected credential strategy |
ApiKey | ApiKeyAuth | apiKey | Configuration when kind is CREDENTIAL_KIND_API_KEY (optional) |
GcpAdc | GcpAdcAuth | gcpAdc | Configuration when kind is CREDENTIAL_KIND_GCP_ADC (optional) |
Labels | IReadOnlyDictionary<string, string> | labels | Optional annotations to aid operators (e.g., "owner=vertex") (optional) |
CredentialKind
Credential kinds supported for upstream endpoint authentication.
String enum: "CREDENTIAL_KIND_UNSPECIFIED" · "CREDENTIAL_KIND_API_KEY" · "CREDENTIAL_KIND_GCP_ADC"
ApiKeyAuth
Configuration for classic API-key authentication.
| Property | Type | JSON (wire) | Description |
|---|---|---|---|
InlineSecret | string | inlineSecret | Secret stored directly in GoodMem (mutually exclusive with secretRef) (optional) |
SecretRef | SecretReference | secretRef | Reference to an external secret manager entry (mutually exclusive with inlineSecret) (optional) |
HeaderName | string | headerName | Desired HTTP header to carry the credential (defaults to Authorization) (optional) |
Prefix | string | prefix | Optional prefix prepended to the secret (e.g., "Bearer ") (optional) |
GcpAdcAuth
Configuration for Google Application Default Credentials (ADC).
| Property | Type | JSON (wire) | Description |
|---|---|---|---|
Scopes | IReadOnlyList<string> | scopes | Additional OAuth scopes. Empty list falls back to the default cloud-platform scope. (optional) |
QuotaProjectId | string | quotaProjectId | Optional quota project used for billing (optional) |
SecretReference
| Property | Type | JSON (wire) | Description |
|---|---|---|---|
Uri | string | uri | URI identifying where the secret can be resolved (e.g., vault://, env://) |
Hints | IReadOnlyDictionary<string, string> | hints | Optional metadata to help resolvers decode the secret (e.g., {"encoding":"base64"}) (optional) |
GoodMemStatus
Warning or non-fatal status with granular codes (operation continues)
| Property | Type | JSON (wire) | Description |
|---|---|---|---|
Code | string | code | Status code for the warning or informational message |
Message | string | message | Human-readable status message |
Details | IReadOnlyDictionary<string, string> | details | Additional contextual details (optional) |
ChunkingConfiguration
Configuration for text chunking strategy used when processing content. Exactly one of none, recursive, or sentence must be provided.
| Property | Type | JSON (wire) | Description |
|---|---|---|---|
None | NoChunkingConfiguration | none | No chunking strategy - preserve original content as single unit (optional) |
Recursive | RecursiveChunkingConfiguration | recursive | Recursive hierarchical chunking strategy with configurable separators (optional) |
Sentence | SentenceChunkingConfiguration | sentence | Sentence-based chunking strategy with language detection (optional) |
NoChunkingConfiguration
No chunking strategy - preserves original content as a single unit
(no fields)
RecursiveChunkingConfiguration
Recursive hierarchical chunking strategy with configurable separators and overlap
| Property | Type | JSON (wire) | Description |
|---|---|---|---|
ChunkSize | int | chunkSize | Maximum size of a chunk (should be ≤ context window) |
ChunkOverlap | int | chunkOverlap | Sliding overlap between chunks |
Separators | IReadOnlyList<string> | separators | Hierarchical separator list (order = preference) (optional) |
KeepStrategy | SeparatorKeepStrategy | keepStrategy | How to handle separators after splitting. KEEP_NONE is deprecated and behaves as KEEP_END. |
SeparatorIsRegex | bool | separatorIsRegex | Whether separators are regex patterns (optional) |
LengthMeasurement | LengthMeasurement | lengthMeasurement | How to measure chunk length |
SentenceChunkingConfiguration
Sentence-based chunking strategy with language detection support
| Property | Type | JSON (wire) | Description |
|---|---|---|---|
MaxChunkSize | int | maxChunkSize | Maximum size of a chunk |
MinChunkSize | int | minChunkSize | Minimum size before creating a new chunk |
EnableLanguageDetection | bool | enableLanguageDetection | Whether to detect language for better segmentation (optional) |
LengthMeasurement | LengthMeasurement | lengthMeasurement | How to measure chunk length |
SeparatorKeepStrategy
Strategy for handling separators after text splitting. KEEP_NONE is deprecated and treated as KEEP_END.
String enum: "KEEP_NONE" · "KEEP_START" · "KEEP_END"
LengthMeasurement
Strategy for measuring chunk length during text splitting
String enum: "CHARACTER_COUNT" · "TOKEN_COUNT" · "CUSTOM"
SortOrder
String enum: "ASCENDING" · "DESCENDING" · "SORT_ORDER_UNSPECIFIED"
Support
File issues against the GoodMem repository. The .NET SDK is generated from the same universal API IR (api_ir.json) that drives the Python, Java, Go and MCP SDKs, so the wire contract is identical across every language.