Repository navigation
Description
Feature Request: Standardize Server OpenAPI Interface Format
Background
memind-server currently exposes /open/v1/* and /admin/v1/* APIs. Most endpoints already use shared response
models such as ApiResult<T> and PageResult<T>, but the API format is not yet formally standardized across response
structure, pagination, error codes, timestamps, and OpenAPI documentation.
This makes it harder for the UI, Java client, Python client, and future SDKs to rely on a stable API contract.
Goal
Define and enforce a consistent OpenAPI interface format for memind-server.
Scope
The standard should cover:
- Unified success response format
- Unified error response format
- Standard error codes and HTTP status mappings
- Pagination response format
- Request and response field naming conventions
- OpenAPI schema annotations and examples
- Versioning rules for
/open/v1/*and/admin/v1/* - Contract expectations for generated clients and frontend consumers
Acceptance Criteria
- Add an API format document, for example docs/server-api-format.md
- Document the meaning of ApiResult and PageResult
- Define standard success, error, empty result, and pagination responses
- Define stable error codes and HTTP status mappings
- Ensure /open/v1/* endpoints follow the standard
- Ensure /admin/v1/* endpoints follow the standard or provide a migration checklist
- Ensure generated OpenAPI docs correctly describe response and error schemas
- Ensure UI, Java client, and Python client can parse responses consistently
- Add tests or contract checks to prevent new endpoints from diverging from the standard
Non-goals
- Refactoring business logic
- Changing existing API semantics
- Introducing authentication or gateway features
- Removing backward-compatible fields without a migration plan
Expand to show specification
Memind Server API Format
Status: proposed v1 contract for memind-server.
This document defines the HTTP and OpenAPI contract for all
/open/v1/* and /admin/v1/* endpoints. It is the API shape that UI,
generated clients, Java clients, Python integrations, and future SDKs
should rely on.
Goals
- Provide one response format for success responses.
- Provide one response format for error responses.
- Keep HTTP status codes and Memind error codes separate.
- Standardize pagination, timestamps, request IDs, and field naming.
- Make async endpoints explicit about accepted work versus completed work.
- Make generated OpenAPI clients predictable.
Scope
This standard applies to every JSON endpoint under:
/open/v1/*/admin/v1/*
It does not define authentication, gateway behavior, or business logic
semantics.
Core Rules
- HTTP status codes describe transport, protocol, and resource outcome.
- Memind error codes describe domain or application error semantics.
- Success responses do not contain a business
code. - Error responses contain
error.code; this value is not an HTTP status. - JSON API endpoints should not use
204 No Content; return a standard
success envelope withdata: nullinstead. - Every response includes
meta.requestIdandmeta.timestamp. - If the request includes
X-Request-Id, the server echoes it in
meta.requestIdand the responseX-Request-Idheader. Otherwise the
server generates one.
Response Envelopes
ApiResult
ApiResult<T> is the success envelope. It means the HTTP request succeeded
and the response body contains the requested result.
{
"data": {
"status": "UP",
"service": "memind-server"
},
"meta": {
"requestId": "018f0d67-8a2d-7a8a-bb70-3f50ddde27f5",
"timestamp": "2026-05-11T08:00:00Z"
}
}For commands that complete successfully but have no result:
{
"data": null,
"meta": {
"requestId": "018f0d67-8a2d-7a8a-bb70-3f50ddde27f5",
"timestamp": "2026-05-11T08:00:00Z"
}
}ApiErrorResult
ApiErrorResult is the error envelope. It is used with non-2xx HTTP status
codes.
{
"error": {
"code": "validation_failed",
"message": "Request validation failed",
"details": {
"fieldErrors": {
"userId": "must not be blank"
}
}
},
"meta": {
"requestId": "018f0d67-8a2d-7a8a-bb70-3f50ddde27f5",
"timestamp": "2026-05-11T08:00:00Z"
}
}error.details is optional. It should contain structured machine-readable
details when available, such as validation field errors.
Pagination
List endpoints return ApiResult<PageResult<T>>.
Request parameters:
page: 1-based page number. Default:1.pageSize: number of items per page. Default: endpoint-specific, normally
20. Maximum:100unless the endpoint documents a smaller limit.
Response:
{
"data": {
"items": [],
"page": {
"page": 1,
"pageSize": 20,
"totalItems": 123,
"totalPages": 7,
"hasPrevious": false,
"hasNext": true
}
},
"meta": {
"requestId": "018f0d67-8a2d-7a8a-bb70-3f50ddde27f5",
"timestamp": "2026-05-11T08:00:00Z"
}
}PageResult<T> means:
items: the current page contents.page.page: the current 1-based page number.page.pageSize: requested page size after server validation.page.totalItems: total number of matching items.page.totalPages:ceil(totalItems / pageSize).page.hasPrevious: whether a previous page exists.page.hasNext: whether a next page exists.
Async Operations
Endpoints that complete work before responding return 200 OK.
Endpoints that accept work for later processing return 202 Accepted with an
operation result. 202 Accepted means the server accepted or durably queued
the request. It does not mean the business operation completed.
{
"data": {
"operationId": "op_01HX8Y3V4E8ZJ9N7M6Q5P4R3T2",
"status": "accepted",
"mode": "async"
},
"meta": {
"requestId": "018f0d67-8a2d-7a8a-bb70-3f50ddde27f5",
"timestamp": "2026-05-11T08:00:00Z"
}
}Fire-and-forget endpoints that only schedule in-process work must not return
success unless the request has been persisted or otherwise made retry-safe.
Retry-aware clients must be able to distinguish accepted work from completed
work.
Standard HTTP Status and Error Codes
| HTTP status | Error code | Meaning |
|---|---|---|
| 400 | bad_request |
Request cannot be processed because its shape or parameters are invalid. |
| 400 | validation_failed |
Bean validation or semantic request validation failed. |
| 400 | malformed_json |
Request body is not valid JSON or cannot be decoded. |
| 404 | not_found |
Requested resource does not exist. |
| 409 | conflict |
Request conflicts with current server state. |
| 409 | version_conflict |
Optimistic locking or expected version check failed. |
| 415 | unsupported_media_type |
Request content type is not supported. |
| 429 | rate_limited |
Caller exceeded an enforced rate limit. Reserved until rate limiting exists. |
| 500 | internal_error |
Unexpected server failure. |
| 503 | runtime_unavailable |
Memory runtime is not ready or cannot serve requests. |
| 503 | dependency_unavailable |
Required external dependency is unavailable. |
Rules:
- Do not use numeric strings such as
"200"or"500"as Memind error
codes. - Do not return
200 OKwith an error envelope. - Do not return a success envelope for failed async work.
- Use the most specific code available.
internal_erroris only for unexpected server bugs or uncategorized
failures.
Naming Conventions
- JSON fields use
camelCase. - Query parameters use
camelCase. - Resource identifiers use the domain suffix:
userId,agentId,
rawDataId,itemId,insightId,threadKey. - Collection fields use plural names, normally
items. - Paginated collections always use
data.items, neverdata.list. - Timestamps are ISO-8601 strings in UTC, for example
2026-05-11T08:00:00Z. - Public enum values should use
lower_snake_case. If internal Java enums use
UPPER_SNAKE_CASE, translate them at the API boundary. - Optional fields may be omitted when unset. Required nullable fields must be
marked as nullable in OpenAPI.
OpenAPI Requirements
Every operation must define:
operationIdtagssummary- Request schema, if the operation accepts a body.
- Query and path parameters with validation limits.
- One success response schema and example.
- Common error responses:
400,404where applicable,409where
applicable,500, and503.
Reusable schemas should be declared once under components.schemas.
components:
schemas:
ResponseMeta:
type: object
required: [requestId, timestamp]
properties:
requestId:
type: string
timestamp:
type: string
format: date-time
ApiResult:
type: object
required: [data, meta]
properties:
data:
nullable: true
meta:
$ref: '#/components/schemas/ResponseMeta'
ApiError:
type: object
required: [code, message]
properties:
code:
type: string
message:
type: string
details:
type: object
additionalProperties: true
ApiErrorResult:
type: object
required: [error, meta]
properties:
error:
$ref: '#/components/schemas/ApiError'
meta:
$ref: '#/components/schemas/ResponseMeta'
PageMeta:
type: object
required: [page, pageSize, totalItems, totalPages, hasPrevious, hasNext]
properties:
page:
type: integer
minimum: 1
pageSize:
type: integer
minimum: 1
maximum: 100
totalItems:
type: integer
format: int64
minimum: 0
totalPages:
type: integer
minimum: 0
hasPrevious:
type: boolean
hasNext:
type: boolean
PageResult:
type: object
required: [items, page]
properties:
items:
type: array
items: {}
page:
$ref: '#/components/schemas/PageMeta'
OperationAccepted:
type: object
required: [operationId, status, mode]
properties:
operationId:
type: string
status:
type: string
enum: [accepted]
mode:
type: string
enum: [async]OpenAPI does not support Java-style generics directly. For each endpoint,
compose ApiResult with the concrete data schema in the operation response.
For example, GET /open/v1/health should document data as
OpenMemoryHealth.
Polymorphic request or response types must use oneOf with a discriminator.
This is required for raw content, content blocks, and source payloads.
Client Contract
Clients must:
- Treat 2xx HTTP responses as successful transport outcomes.
- Parse successful responses from
data. - Treat
202 Acceptedas accepted asynchronous work, not completed work. - Treat non-2xx responses as errors and parse
error. - Preserve and surface
meta.requestIdfor diagnostics.
Clients must not:
- Decide success by comparing a body field to
"success"or"200". - Expect error details in
data. - Retry all failures blindly. Retry policy should use HTTP status and
endpoint semantics.
Recommended retry behavior:
- Retry transport failures, timeouts,
429, and503when the operation is
idempotent or has an idempotency key. - Do not retry
400,404, or validation failures without changing the
request. - Do not mark async write operations as completed after
202 Accepted.
Versioning
- The major API version is encoded in the URL:
/open/v1and/admin/v1. - Backward-incompatible wire changes require a new major URL version.
- Additive fields are allowed in the same version.
- Removing fields, renaming fields, changing field types, or changing enum
values is breaking. - Deprecated fields must be marked with
deprecated: truein OpenAPI and kept
until the next major API version. /open/v1/*is a public client contract./admin/v1/*is primarily for the UI, but it must still follow this
document so generated clients and contract tests remain reliable.
Endpoint Examples
Health
GET /open/v1/health{
"data": {
"status": "up",
"service": "memind-server"
},
"meta": {
"requestId": "018f0d67-8a2d-7a8a-bb70-3f50ddde27f5",
"timestamp": "2026-05-11T08:00:00Z"
}
}Retrieve Memory
POST /open/v1/memory/retrieve{
"userId": "user-1",
"agentId": "agent-1",
"query": "What does the user prefer for backend architecture?",
"strategy": "simple",
"trace": false
}{
"data": {
"status": "completed",
"items": [],
"insights": [],
"rawData": [],
"evidences": [],
"strategy": "simple",
"query": "What does the user prefer for backend architecture?",
"trace": null
},
"meta": {
"requestId": "018f0d67-8a2d-7a8a-bb70-3f50ddde27f5",
"timestamp": "2026-05-11T08:00:00Z"
}
}Admin Page
GET /admin/v1/items?page=1&pageSize=20&userId=user-1{
"data": {
"items": [],
"page": {
"page": 1,
"pageSize": 20,
"totalItems": 0,
"totalPages": 0,
"hasPrevious": false,
"hasNext": false
}
},
"meta": {
"requestId": "018f0d67-8a2d-7a8a-bb70-3f50ddde27f5",
"timestamp": "2026-05-11T08:00:00Z"
}
}Migration Checklist
Use this checklist when implementing the standard:
- Replace success response bodies with
ApiResult<T>usingdataandmeta. - Replace error response bodies with
ApiErrorResult. - Remove success business codes such as
"success"and"200"from response
bodies. - Move validation details from
datatoerror.details. - Change pagination from
total/list/currenttoitems/page. - Change list query parameters from
pageNotopage. - Add request ID generation and response header echoing.
- Make async write endpoints return
202 Acceptedonly after durable
acceptance, or make them synchronous and return200 OKonly after
completion. - Add OpenAPI schemas, examples, and common error responses.
- Update UI and SDK clients to rely on HTTP status and the new envelopes.
Contract Checks
The server should include automated checks that prevent new endpoints from
drifting from this standard:
- Controller return types are
ApiResult<T>,
ResponseEntity<ApiResult<T>>, orResponseEntity<ApiErrorResult>. - All exception handlers produce
ApiErrorResult. - OpenAPI output contains the common response schemas.
- Every operation documents at least one 2xx response and the common error
responses. - Paginated endpoints use
PageResult<T>. - Error codes in OpenAPI match the standard error code list.
- Async endpoints never document
200 OKunless the work completes before the
response is sent.
Activity
me0106 commentedon May 11, 2026
related issue: #56