GoodMemGoodMem
ReferenceClient SDKs.NET

.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.2
using 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/info and /v1/system/init are callable without one); every other endpoint returns 401.
  • To supply your own HttpClient (proxy, custom TLS, handlers), pass it via GoodmemClientOptions.HttpClient. In bring-your-own mode you own the redirect policy; the SDK-built default refuses redirects so the x-api-key header 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

NamespaceDescriptionReference
EmbeddersEmbedder managementclient.Embedders
RerankersReranker managementclient.Rerankers
LlmsLLM managementclient.Llms
SpacesMemory space managementclient.Spaces
MemoriesMemory CRUD, retrieval, and batch operationsclient.Memories
OcrDocument text extractionclient.Ocr
SystemServer info and initializationclient.System
InstanceSingleton instance identity and ownershipclient.Instance
UsersUser lookupclient.Users
ServiceIdentitiesProduction service identity lifecycleclient.ServiceIdentities
UserEnrollmentsOne-time human-user enrollment completionclient.UserEnrollments
AdminServer lifecycle operationsclient.Admin
AccessPolicyDirect grants and scoped role assignmentsclient.AccessPolicy
ApiKeysAPI key lifecycle managementclient.ApiKeys
PingEndpoint 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.

PropertyTypeJSON (wire)Description
KindCredentialKindkindSelected credential strategy
ApiKeyApiKeyAuthapiKeyConfiguration when kind is CREDENTIAL_KIND_API_KEY (optional)
GcpAdcGcpAdcAuthgcpAdcConfiguration when kind is CREDENTIAL_KIND_GCP_ADC (optional)
LabelsIReadOnlyDictionary<string, string>labelsOptional 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.

PropertyTypeJSON (wire)Description
InlineSecretstringinlineSecretSecret stored directly in GoodMem (mutually exclusive with secretRef) (optional)
SecretRefSecretReferencesecretRefReference to an external secret manager entry (mutually exclusive with inlineSecret) (optional)
HeaderNamestringheaderNameDesired HTTP header to carry the credential (defaults to Authorization) (optional)
PrefixstringprefixOptional prefix prepended to the secret (e.g., "Bearer ") (optional)

GcpAdcAuth

Configuration for Google Application Default Credentials (ADC).

PropertyTypeJSON (wire)Description
ScopesIReadOnlyList<string>scopesAdditional OAuth scopes. Empty list falls back to the default cloud-platform scope. (optional)
QuotaProjectIdstringquotaProjectIdOptional quota project used for billing (optional)

SecretReference

PropertyTypeJSON (wire)Description
UristringuriURI identifying where the secret can be resolved (e.g., vault://, env://)
HintsIReadOnlyDictionary<string, string>hintsOptional metadata to help resolvers decode the secret (e.g., {"encoding":"base64"}) (optional)

GoodMemStatus

Warning or non-fatal status with granular codes (operation continues)

PropertyTypeJSON (wire)Description
CodestringcodeStatus code for the warning or informational message
MessagestringmessageHuman-readable status message
DetailsIReadOnlyDictionary<string, string>detailsAdditional contextual details (optional)

ChunkingConfiguration

Configuration for text chunking strategy used when processing content. Exactly one of none, recursive, or sentence must be provided.

PropertyTypeJSON (wire)Description
NoneNoChunkingConfigurationnoneNo chunking strategy - preserve original content as single unit (optional)
RecursiveRecursiveChunkingConfigurationrecursiveRecursive hierarchical chunking strategy with configurable separators (optional)
SentenceSentenceChunkingConfigurationsentenceSentence-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

PropertyTypeJSON (wire)Description
ChunkSizeintchunkSizeMaximum size of a chunk (should be ≤ context window)
ChunkOverlapintchunkOverlapSliding overlap between chunks
SeparatorsIReadOnlyList<string>separatorsHierarchical separator list (order = preference) (optional)
KeepStrategySeparatorKeepStrategykeepStrategyHow to handle separators after splitting. KEEP_NONE is deprecated and behaves as KEEP_END.
SeparatorIsRegexboolseparatorIsRegexWhether separators are regex patterns (optional)
LengthMeasurementLengthMeasurementlengthMeasurementHow to measure chunk length

SentenceChunkingConfiguration

Sentence-based chunking strategy with language detection support

PropertyTypeJSON (wire)Description
MaxChunkSizeintmaxChunkSizeMaximum size of a chunk
MinChunkSizeintminChunkSizeMinimum size before creating a new chunk
EnableLanguageDetectionboolenableLanguageDetectionWhether to detect language for better segmentation (optional)
LengthMeasurementLengthMeasurementlengthMeasurementHow 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.

PropertyTypeJSON (wire)Description
NewOwnerIdstringnewOwnerIdExisting principal UUID that will become the new owner.

GoodMemInstance

The singleton GoodMem instance and its ownership audit metadata.

PropertyTypeJSON (wire)Description
InstanceIdstringinstanceIdDurable UUID of the singleton GoodMem instance.
OwnerIdstringownerIdCurrent human owner principal UUID.
CreatedAtDateTimeOffsetcreatedAtInitialization timestamp in milliseconds since the Unix epoch.
UpdatedAtDateTimeOffsetupdatedAtMost recent ownership-transfer timestamp in milliseconds since the Unix epoch.
CreatedByIdstringcreatedByIdPrincipal or API-key actor UUID that initialized the instance.
UpdatedByIdstringupdatedByIdPrincipal or API-key actor UUID that last transferred ownership.

ApiKeyResponse

API key metadata without sensitive information.

PropertyTypeJSON (wire)Description
ApiKeyIdstringapiKeyIdUnique identifier for the API key.
SubjectPrincipalIdstringsubjectPrincipalIdPrincipal authenticated by this API key.
OwnerPrincipalIdstringownerPrincipalIdPrincipal that administratively owns this API key.
AuthorityModeApiKeyAuthorityModeauthorityModeImmutable authority derivation mode.
CeilingIReadOnlyList<AccessPolicyRule>ceilingComplete immutable issuance ceiling; omitted only when ceilingOmitted is true. (optional)
CeilingOmittedboolceilingOmittedTrue only when a BASIC list projection intentionally omitted the immutable ceiling.
KeyPrefixstringkeyPrefixFirst few characters of the key for display/identification purposes.
StatusstringstatusCompatibility usability status. ACTIVE means USABLE; INACTIVE combines NOT_YET_VALID, EXPIRED, and REVOKED.
LifecycleStatestringlifecycleStatePrecise lifecycle state at the response evaluation instant.
LabelsIReadOnlyDictionary<string, string>labelsUser-defined labels for organization and filtering.
ExpiresAtDateTimeOffsetexpiresAtExpiration timestamp in milliseconds since epoch. If not provided, the key does not expire. (optional)
ValidFromDateTimeOffsetvalidFromInclusive activation time in milliseconds since epoch.
RevokedAtDateTimeOffsetrevokedAtPermanent revocation time in milliseconds since epoch. (optional)
RevokedByIdstringrevokedByIdExact audit actor UUID that revoked this key. (optional)
LastUsedAtDateTimeOffsetlastUsedAtLast time this API key was used, in milliseconds since epoch. (optional)
CreatedAtDateTimeOffsetcreatedAtWhen the API key was created, in milliseconds since epoch.
UpdatedAtDateTimeOffsetupdatedAtWhen the API key was last updated, in milliseconds since epoch.
CreatedByIdstringcreatedByIdExact principal or API-key actor that created this API key.
UpdatedByIdstringupdatedByIdExact 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.

PropertyTypeJSON (wire)Description
OperationOperationoperationProtected operation.
SelectorSelectorselectorResource-selection semantics.
AssignedResourceAccessPolicyTargetassignedResourceRequired 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.

PropertyTypeJSON (wire)Description
KindResourceKindkindConcrete target kind.
ResourceIdstringresourceIdConcrete 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.