.NET SDK
Install and configure the GoodMem .NET SDK. Reference asynchronous clients and cancellation, resource methods, errors, and shared data models.
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.
Current package version: 2.0.2
Installation
dotnet add package PairSystems.Goodmem.Client --version 2.0.2using 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 |
Instance | Singleton instance identity and ownership | client.Instance |
Users | User lookup | client.Users |
ServiceIdentities | Production service identity lifecycle | client.ServiceIdentities |
UserEnrollments | One-time human-user enrollment completion | client.UserEnrollments |
Admin | Server lifecycle operations | client.Admin |
AccessPolicy | Direct grants and scoped role assignments | client.AccessPolicy |
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" · "DASHSCOPE" · "GEMINI"
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) |
DashScopeApiDialect
DashScope request and response API dialect
String enum: "UNSPECIFIED" · "EMBEDDING_NATIVE_TEXT" · "EMBEDDING_NATIVE_CONTENTS" · "LLM_NATIVE_TEXT" · "LLM_NATIVE_MULTIMODAL" · "RERANK_NATIVE_NESTED" · "OPENAI_COMPATIBLE" · "RERANK_COMPATIBLE_FLAT"
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"
TransferOwnershipRequest
Names the principal that will become the resource owner.
| Property | Type | JSON (wire) | Description |
|---|---|---|---|
NewOwnerId | string | newOwnerId | Existing principal UUID that will become the new owner. |
GoodMemInstance
The singleton GoodMem instance and its ownership audit metadata.
| Property | Type | JSON (wire) | Description |
|---|---|---|---|
InstanceId | string | instanceId | Durable UUID of the singleton GoodMem instance. |
OwnerId | string | ownerId | Current human owner principal UUID. |
CreatedAt | DateTimeOffset | createdAt | Initialization timestamp in milliseconds since the Unix epoch. |
UpdatedAt | DateTimeOffset | updatedAt | Most recent ownership-transfer timestamp in milliseconds since the Unix epoch. |
CreatedById | string | createdById | Principal or API-key actor UUID that initialized the instance. |
UpdatedById | string | updatedById | Principal or API-key actor UUID that last transferred ownership. |
ApiKeyResponse
API key metadata without sensitive information.
| Property | Type | JSON (wire) | Description |
|---|---|---|---|
ApiKeyId | string | apiKeyId | Unique identifier for the API key. |
SubjectPrincipalId | string | subjectPrincipalId | Principal authenticated by this API key. |
OwnerPrincipalId | string | ownerPrincipalId | Principal that administratively owns this API key. |
AuthorityMode | ApiKeyAuthorityMode | authorityMode | Immutable authority derivation mode. |
Ceiling | IReadOnlyList<AccessPolicyRule> | ceiling | Complete immutable issuance ceiling; omitted only when ceilingOmitted is true. (optional) |
CeilingOmitted | bool | ceilingOmitted | True only when a BASIC list projection intentionally omitted the immutable ceiling. |
KeyPrefix | string | keyPrefix | First few characters of the key for display/identification purposes. |
Status | string | status | Compatibility usability status. ACTIVE means USABLE; INACTIVE combines NOT_YET_VALID, EXPIRED, and REVOKED. |
LifecycleState | string | lifecycleState | Precise lifecycle state at the response evaluation instant. |
Labels | IReadOnlyDictionary<string, string> | labels | User-defined labels for organization and filtering. |
ExpiresAt | DateTimeOffset | expiresAt | Expiration timestamp in milliseconds since epoch. If not provided, the key does not expire. (optional) |
ValidFrom | DateTimeOffset | validFrom | Inclusive activation time in milliseconds since epoch. |
RevokedAt | DateTimeOffset | revokedAt | Permanent revocation time in milliseconds since epoch. (optional) |
RevokedById | string | revokedById | Exact audit actor UUID that revoked this key. (optional) |
LastUsedAt | DateTimeOffset | lastUsedAt | Last time this API key was used, in milliseconds since epoch. (optional) |
CreatedAt | DateTimeOffset | createdAt | When the API key was created, in milliseconds since epoch. |
UpdatedAt | DateTimeOffset | updatedAt | When the API key was last updated, in milliseconds since epoch. |
CreatedById | string | createdById | Exact principal or API-key actor that created this API key. |
UpdatedById | string | updatedById | Exact principal or API-key actor that last updated this API key. |
ApiKeyAuthorityMode
INHERIT_SUBJECT follows a human subject's live authority. SCOPED intersects the subject's live authority with an immutable, nonempty issuance ceiling.
String enum: "INHERIT_SUBJECT" · "SCOPED"
AccessPolicyRule
One operation, selector, and optional assigned resource.
| Property | Type | JSON (wire) | Description |
|---|---|---|---|
Operation | Operation | operation | Protected operation. |
Selector | Selector | selector | Resource-selection semantics. |
AssignedResource | AccessPolicyTarget | assignedResource | Required exactly for EXACT and DIRECT_MEMBERS_OF selectors. (optional) |
Operation
String enum: "CREATE_USER" · "READ_USER" · "UPDATE_USER" · "DELETE_USER" · "LIST_USER" · "MANAGE_USER_ENROLLMENT" · "CREATE_SERVICE_IDENTITY" · "READ_SERVICE_IDENTITY" · "UPDATE_SERVICE_IDENTITY" · "DELETE_SERVICE_IDENTITY" · "LIST_SERVICE_IDENTITY" · "CREATE_SPACE" · "READ_SPACE" · "UPDATE_SPACE" · "DELETE_SPACE" · "LIST_SPACE" · "CREATE_API_KEY" · "READ_API_KEY" · "UPDATE_API_KEY" · "DELETE_API_KEY" · "LIST_API_KEY" · "CREATE_EMBEDDER" · "READ_EMBEDDER" · "UPDATE_EMBEDDER" · "DELETE_EMBEDDER" · "LIST_EMBEDDER" · "PING_EMBEDDER" · "EXECUTE_EMBEDDER" · "READ_EMBEDDER_CREDENTIALS" · "CREATE_RERANKER" · "READ_RERANKER" · "UPDATE_RERANKER" · "DELETE_RERANKER" · "LIST_RERANKER" · "PING_RERANKER" · "EXECUTE_RERANKER" · "READ_RERANKER_CREDENTIALS" · "CREATE_LLM" · "READ_LLM" · "UPDATE_LLM" · "DELETE_LLM" · "LIST_LLM" · "PING_LLM" · "EXECUTE_LLM" · "READ_LLM_CREDENTIALS" · "PROXY_INFERENCE_TARGET" · "OCR_DOCUMENT" · "CREATE_MEMORY" · "READ_MEMORY" · "DELETE_MEMORY" · "LIST_MEMORY" · "CREATE_EXTENSION" · "READ_EXTENSION" · "UPDATE_EXTENSION" · "DELETE_EXTENSION" · "LIST_EXTENSION" · "DOWNLOAD_EXTENSION" · "READ_INSTANCE" · "TRANSFER_INSTANCE_OWNERSHIP" · "TRANSFER_RESOURCE_OWNERSHIP" · "RELOAD_LICENSE" · "DRAIN_SERVER" · "PURGE_BACKGROUND_JOBS" · "CREATE_RETRIEVE_MEMORY_LOG_POLICY" · "READ_RETRIEVE_MEMORY_LOG_POLICY" · "LIST_RETRIEVE_MEMORY_LOG_POLICY" · "DELETE_RETRIEVE_MEMORY_LOG_POLICY" · "MANAGE_ACCESS"
Selector
String enum: "ANY" · "OWN" · "EXACT" · "DIRECT_MEMBERS_OF"
AccessPolicyTarget
A typed access-policy target. resourceId is omitted for INSTANCE and required otherwise.
| Property | Type | JSON (wire) | Description |
|---|---|---|---|
Kind | ResourceKind | kind | Concrete target kind. |
ResourceId | string | resourceId | Concrete resource UUID; omitted for the singleton INSTANCE target. (optional) |
ResourceKind
String enum: "INSTANCE" · "USER" · "SERVICE_IDENTITY" · "SPACE" · "API_KEY" · "EMBEDDER" · "RERANKER" · "LLM" · "MEMORY" · "EXTENSION" · "RETRIEVE_MEMORY_LOG_POLICY"
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.