Comprehensive guide for interacting with the Memos REST API
Generated from usememos/dotcom and usememos/memos
- Overview
- Base URL
- Authentication
- API Services
- Common Patterns
- Error Handling
- Code Examples
- Webhook Integration
Memos provides a comprehensive REST API for managing memos, users, attachments, and more. The API follows RESTful principles with resource-oriented URLs, standard HTTP methods, and JSON request/response bodies.
- RESTful Design: Standard HTTP methods (GET, POST, PATCH, DELETE)
- Google AIP Compliance: Follows Google API Improvement Proposals for pagination, filtering, and field masks
- Multiple Authentication Methods: Password, SSO, and Personal Access Tokens
- Webhook Support: Real-time event notifications
- CEL Filtering: Powerful filter expressions for list operations
All API endpoints are prefixed with /api/v1:
https://your-memos-instance.com/api/v1
For testing purposes, you can use the demo server:
https://demo.usememos.com/api/v1
The Memos API supports multiple authentication methods:
For most endpoints, include the access token in the Authorization header:
Authorization: Bearer <your-access-token>Authenticate with username and password to receive access and refresh tokens.
Endpoint: POST /api/v1/auth/signin
Request Body:
{
"passwordCredentials": {
"username": "your-username",
"password": "your-password"
}
}Response:
{
"user": {
"name": "users/123",
"role": "USER",
"username": "johndoe",
"email": "john@example.com",
"state": "NORMAL"
},
"accessToken": "eyJhbGciOiJIUzI1NiIs...",
"accessTokenExpiresAt": "2026-02-18T12:00:00Z"
}Notes:
- The refresh token is automatically set as an HttpOnly cookie
- The access token is short-lived (expires quickly)
- Use the refresh token endpoint to get a new access token
Authenticate via an Identity Provider (IdP) using OAuth/OIDC.
Request Body:
{
"ssoCredentials": {
"idpId": 1,
"code": "authorization-code-from-idp",
"redirectUri": "https://your-app.com/callback",
"codeVerifier": "pkce-code-verifier" // Optional, for PKCE
}
}PATs are long-lived tokens perfect for scripts and API integrations.
Endpoint: POST /api/v1/users/{user}/personalAccessTokens
Request Body:
{
"parent": "users/123",
"description": "My API integration",
"expiresInDays": 365
}Response:
{
"personalAccessToken": {
"name": "users/123/personalAccessTokens/abc123",
"description": "My API integration",
"createTime": "2026-02-18T00:00:00Z"
},
"token": "mtr_xxxxxxxxxxxxxxxx" // Only shown once!
}Important: The token value is only returned once at creation. Store it securely!
Authorization: Bearer mtr_xxxxxxxxxxxxxxxxEndpoint: GET /api/v1/users/{user}/personalAccessTokens
Endpoint: DELETE /api/v1/users/{user}/personalAccessTokens/{token}
When your access token expires, use the refresh token to get a new one.
Endpoint: POST /api/v1/auth/refresh
- The refresh token is automatically read from the HttpOnly cookie
- Returns a new access token
Response:
{
"accessToken": "eyJhbGciOiJIUzI1NiIs...",
"accessTokenExpiresAt": "2026-02-18T13:00:00Z"
}Verify your authentication and get user details.
Endpoint: GET /api/v1/auth/me
Equivalent to OIDC's /userinfo endpoint.
Response:
{
"user": {
"name": "users/123",
"username": "johndoe",
"role": "USER"
}
}Endpoint: POST /api/v1/auth/signout
Invalidates the current session and refresh token.
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/auth/signin |
Authenticate with credentials |
| POST | /api/v1/auth/signout |
Sign out current user |
| GET | /api/v1/auth/me |
Get current user info |
| POST | /api/v1/auth/refresh |
Refresh access token |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/users |
List users |
| POST | /api/v1/users |
Create user |
| GET | /api/v1/users/{user} |
Get user |
| PATCH | /api/v1/users/{user} |
Update user |
| DELETE | /api/v1/users/{user} |
Delete user |
| GET | /api/v1/users/{user}/settings |
List user settings |
| GET | /api/v1/users/{user}/settings/{setting} |
Get user setting |
| PATCH | /api/v1/users/{user}/settings/{setting} |
Update user setting |
| GET | /api/v1/users/{user}/stats |
Get user stats |
| GET | /api/v1/users:stats |
List all user stats |
| GET | /api/v1/users/{user}/personalAccessTokens |
List PATs |
| POST | /api/v1/users/{user}/personalAccessTokens |
Create PAT |
| DELETE | /api/v1/users/{user}/personalAccessTokens/{token} |
Delete PAT |
| GET | /api/v1/users/{user}/notifications |
List notifications |
| PATCH | /api/v1/users/{user}/notifications/{notification} |
Update notification |
| DELETE | /api/v1/users/{user}/notifications/{notification} |
Delete notification |
| GET | /api/v1/users/{user}/webhooks |
List webhooks |
| POST | /api/v1/users/{user}/webhooks |
Create webhook |
| PATCH | /api/v1/users/{user}/webhooks/{webhook} |
Update webhook |
| DELETE | /api/v1/users/{user}/webhooks/{webhook} |
Delete webhook |
{
"name": "users/123",
"role": "USER", // ADMIN, USER
"username": "johndoe",
"email": "john@example.com",
"displayName": "John Doe",
"avatarUrl": "https://...",
"description": "Bio here",
"state": "NORMAL", // NORMAL, ARCHIVED
"createTime": "2026-01-01T00:00:00Z",
"updateTime": "2026-02-01T00:00:00Z"
}The core service for managing memos (notes).
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/memos |
List memos |
| POST | /api/v1/memos |
Create memo |
| GET | /api/v1/memos/{memo} |
Get memo |
| PATCH | /api/v1/memos/{memo} |
Update memo |
| DELETE | /api/v1/memos/{memo} |
Delete memo |
| GET | /api/v1/memos/{memo}/comments |
List comments |
| POST | /api/v1/memos/{memo}/comments |
Create comment |
| GET | /api/v1/memos/{memo}/attachments |
List attachments |
| PATCH | /api/v1/memos/{memo}/attachments |
Set attachments |
| GET | /api/v1/memos/{memo}/relations |
List relations |
| PATCH | /api/v1/memos/{memo}/relations |
Set relations |
| GET | /api/v1/memos/{memo}/reactions |
List reactions |
| POST | /api/v1/memos/{memo}/reactions |
Add reaction |
| DELETE | /api/v1/memos/{memo}/reactions/{reaction} |
Delete reaction |
{
"name": "memos/abc123",
"state": "NORMAL", // NORMAL, ARCHIVED
"creator": "users/123",
"createTime": "2026-02-18T00:00:00Z",
"updateTime": "2026-02-18T01:00:00Z",
"displayTime": "2026-02-18T00:00:00Z",
"content": "# My Memo\n\nThis is content in **Markdown**.",
"visibility": "PRIVATE", // PRIVATE, PROTECTED, PUBLIC
"tags": ["tag1", "tag2"],
"pinned": false,
"attachments": [],
"relations": [],
"reactions": [],
"snippet": "My Memo This is content in Markdown.",
"parent": "memos/parent123"
}Endpoint: POST /api/v1/memos
Query Parameters:
memoId(optional): Specify a custom memo ID
Request Body:
{
"content": "# Hello World\n\nMy first memo!",
"visibility": "PRIVATE",
"state": "NORMAL"
}Endpoint: GET /api/v1/memos
Query Parameters:
pageSize(int): Maximum items to return (default: 50, max: 1000)pageToken(string): Pagination token from previous responsefilter(string): CEL filter expressionorderBy(string): Sort order (e.g., "display_time desc")state(enum): Filter by state (NORMAL, ARCHIVED)
Example with Filter:
GET /api/v1/memos?filter=visibility=="PUBLIC"&orderBy=create_time desc&pageSize=10
Endpoint: PATCH /api/v1/memos/{memo}?updateMask=content,visibility
The updateMask query parameter is required and specifies which fields to update.
Request Body:
{
"content": "Updated content",
"visibility": "PUBLIC"
}Manage file attachments.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/attachments |
List attachments |
| POST | /api/v1/attachments |
Create/upload attachment |
| GET | /api/v1/attachments/{attachment} |
Get attachment |
| PATCH | /api/v1/attachments/{attachment} |
Update attachment |
| DELETE | /api/v1/attachments/{attachment} |
Delete attachment |
Filter Examples:
filename.contains("test")
mime_type=="image/png"
create_time>"2026-01-01"
Track user activities.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/activities |
List activities |
| GET | /api/v1/activities/{activity} |
Get activity |
Manage instance-wide settings.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/instance/profile |
Get instance profile |
| GET | /api/v1/instance/settings/{setting} |
Get instance setting |
| PATCH | /api/v1/instance/settings/{setting} |
Update instance setting |
Manage SSO identity providers (admin only).
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/identity-providers |
List IdPs |
| POST | /api/v1/identity-providers |
Create IdP |
| GET | /api/v1/identity-providers/{id} |
Get IdP |
| PATCH | /api/v1/identity-providers/{id} |
Update IdP |
| DELETE | /api/v1/identity-providers/{id} |
Delete IdP |
Manage user shortcuts.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/users/{user}/shortcuts |
List shortcuts |
| POST | /api/v1/users/{user}/shortcuts |
Create shortcut |
| GET | /api/v1/users/{user}/shortcuts/{shortcut} |
Get shortcut |
| PATCH | /api/v1/users/{user}/shortcuts/{shortcut} |
Update shortcut |
| DELETE | /api/v1/users/{user}/shortcuts/{shortcut} |
Delete shortcut |
List endpoints support cursor-based pagination using pageSize and pageToken:
Request:
GET /api/v1/memos?pageSize=10
Response:
{
"memos": [...],
"nextPageToken": "eyJwYWdlIjoyfQ=="
}Next Request:
GET /api/v1/memos?pageSize=10&pageToken=eyJwYWdlIjoyfQ==
Limits:
- Default page size: 50 (varies by endpoint)
- Maximum page size: 1000
List endpoints support CEL (Common Expression Language) filtering following Google AIP-160.
Operators:
==(equals)!=(not equals)<,<=,>,>=(comparison):(contains)in(membership)
Examples:
# Filter memos by visibility
visibility == "PUBLIC"
# Filter attachments by MIME type
mime_type == "image/png"
# Filter users by username
username == 'johndoe'
# Filter by partial match
filename.contains("test")
# Combined filters
visibility == "PUBLIC" && create_time > "2026-01-01"
Use the orderBy parameter to sort results:
Examples:
# Single field
orderBy=create_time desc
# Multiple fields
orderBy=pinned desc, display_time desc
# Memo fields
orderBy=create_time asc
orderBy=update_time desc
orderBy=display_time desc
PATCH operations use field masks to specify which fields to update.
Format: Comma-separated field paths
Examples:
# Update single field
PATCH /api/v1/memos/abc123?updateMask=content
# Update multiple fields
PATCH /api/v1/memos/abc123?updateMask=content,visibility
# Update user settings
PATCH /api/v1/users/123/settings/locale?updateMask=value
The API returns standard HTTP status codes and JSON error responses.
{
"code": 3,
"message": "Invalid argument: visibility is required",
"details": []
}| Code | Meaning |
|---|---|
| 200 | Success |
| 400 | Bad Request - Invalid input |
| 401 | Unauthorized - Authentication required |
| 403 | Forbidden - Insufficient permissions |
| 404 | Not Found - Resource doesn't exist |
| 409 | Conflict - Resource already exists |
| 500 | Internal Server Error |
| Code | Name | Description |
|---|---|---|
| 0 | OK | Success |
| 1 | CANCELLED | Operation cancelled |
| 2 | UNKNOWN | Unknown error |
| 3 | INVALID_ARGUMENT | Invalid request parameter |
| 4 | DEADLINE_EXCEEDED | Request timeout |
| 5 | NOT_FOUND | Resource not found |
| 6 | ALREADY_EXISTS | Resource already exists |
| 7 | PERMISSION_DENIED | Insufficient permissions |
| 16 | UNAUTHENTICATED | Authentication required |
curl -X POST https://demo.usememos.com/api/v1/auth/signin \
-H "Content-Type: application/json" \
-d '{
"passwordCredentials": {
"username": "your-username",
"password": "your-password"
}
}'curl -X POST https://demo.usememos.com/api/v1/memos \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"content": "# Hello from API\n\nThis is my memo!",
"visibility": "PRIVATE",
"state": "NORMAL"
}'curl "https://demo.usememos.com/api/v1/memos?filter=visibility==%22PUBLIC%22&pageSize=10" \
-H "Authorization: Bearer YOUR_TOKEN"curl -X PATCH "https://demo.usememos.com/api/v1/memos/abc123?updateMask=content" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"content": "Updated content!"
}'import requests
BASE_URL = "https://demo.usememos.com/api/v1"
def sign_in(username, password):
response = requests.post(f"{BASE_URL}/auth/signin", json={
"passwordCredentials": {
"username": username,
"password": password
}
})
return response.json()["accessToken"]
def create_memo(token, content, visibility="PRIVATE"):
response = requests.post(
f"{BASE_URL}/memos",
headers={"Authorization": f"Bearer {token}"},
json={
"content": content,
"visibility": visibility,
"state": "NORMAL"
}
)
return response.json()
def list_memos(token, filter_expr=None):
params = {"pageSize": 50}
if filter_expr:
params["filter"] = filter_expr
response = requests.get(
f"{BASE_URL}/memos",
headers={"Authorization": f"Bearer {token}"},
params=params
)
return response.json()
# Usage
token = sign_in("your-username", "your-password")
memo = create_memo(token, "# Hello World\n\nMy first API memo!")
memos = list_memos(token, 'visibility=="PUBLIC"')const BASE_URL = 'https://demo.usememos.com/api/v1';
async function signIn(username, password) {
const response = await fetch(`${BASE_URL}/auth/signin`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
passwordCredentials: { username, password }
})
});
const data = await response.json();
return data.accessToken;
}
async function createMemo(token, content, visibility = 'PRIVATE') {
const response = await fetch(`${BASE_URL}/memos`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
content,
visibility,
state: 'NORMAL'
})
});
return response.json();
}
async function listMemos(token, filter) {
const params = new URLSearchParams({ pageSize: '50' });
if (filter) params.append('filter', filter);
const response = await fetch(`${BASE_URL}/memos?${params}`, {
headers: { 'Authorization': `Bearer ${token}` }
});
return response.json();
}
// Usage
const token = await signIn('your-username', 'your-password');
const memo = await createMemo(token, '# Hello World!');
const memos = await listMemos(token, 'visibility=="PUBLIC"');Webhooks allow you to receive real-time notifications when events occur.
{
"name": "users/123/webhooks/abc123",
"url": "https://your-app.com/webhook",
"displayName": "My Webhook",
"createTime": "2026-02-18T00:00:00Z",
"updateTime": "2026-02-18T01:00:00Z"
}Endpoint: POST /api/v1/users/{user}/webhooks
Request Body:
{
"url": "https://your-app.com/webhooks/memos",
"displayName": "Production Webhook"
}Endpoint: PATCH /api/v1/users/{user}/webhooks/{webhook}?updateMask=url
When events occur, Memos will POST to your webhook URL with event data. The exact payload structure depends on the event type.
Security Note: Always verify webhook signatures when available, and use HTTPS endpoints.
- Main Repository: https://github.com/usememos/memos
- Documentation Site: https://github.com/usememos/dotcom
- OpenAPI Spec: https://github.com/usememos/memos/blob/main/proto/gen/openapi.yaml
- Demo Instance: https://demo.usememos.com
This documentation was compiled from the Memos open-source project. For the latest updates, refer to the official repositories.