The Omamo API
The Omamo API lets your own scripts and tools read and save your links and notes. A key acts as you: it sees what you can see in Omamo, and it can change only what you can change. The API is free on every plan, inside the limits below.
For AI apps such as Claude or ChatGPT, use the MCP server instead. You sign in there, and no key is needed.
Make a key
Section titled “Make a key”- Open Settings and find API keys.
- Press New key, and name it after the script or tool that will use it.
- Pick the access. Read only can list and read. Read and write can also save, change, move, and delete items, and make and rename boards and collections.
- Pick an expiry: 30 days, 90 days, a year, or never.
- Press Make key, and copy the key. Omamo shows it only this once.
If you signed in more than 15 minutes ago, Omamo asks you to sign in again before it makes a key. A key can act as you for months, so it needs a recent sign-in.
A key is omamo_ and 43 random characters. Omamo keeps only a fingerprint of it, a SHA-256 hash. Nobody at Omamo can read your key, and Omamo cannot show a lost key again. Make a new one instead.
Make a request
Section titled “Make a request”Every path starts with https://omamo.app/api/public/v1. Send the key in the Authorization header:
export OMAMO_KEY="omamo_…"
curl "https://omamo.app/api/public/v1/spaces" \
-H "Authorization: Bearer $OMAMO_KEY"
{
"data": [
{ "id": "cmw2enyni005mlzqn5sacm6z2", "name": "Desk", "description": null, "boards": 3, "members": 1 }
]
}
Save a link into a collection. Omamo then reads the page for its title, picture, and description:
curl -X POST "https://omamo.app/api/public/v1/collections/<collectionId>/links" \
-H "Authorization: Bearer $OMAMO_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/", "tags": ["read later"]}'
Write a note. Each line of the text becomes a paragraph:
curl -X POST "https://omamo.app/api/public/v1/collections/<collectionId>/notes" \
-H "Authorization: Bearer $OMAMO_KEY" \
-H "Content-Type: application/json" \
-d '{"title": "Ideas", "text": "First idea\nSecond idea"}'
The reference lists every endpoint with its fields. Spaces hold boards, boards hold collections, and collections hold items, so start with the spaces and follow the ids down.
What a key cannot do
Section titled “What a key cannot do”A key never deletes spaces, boards, or collections, never invites people, and never reaches the trash, billing, your account, or your API keys. Do those in the app. Deleted items go to the trash, where you can restore them for 30 days.
Answers
Section titled “Answers”Answers are JSON. A success carries data:
{ "data": { "id": "…", "title": "…" } }
A failure carries error, with a code your code can check and a message a person can read. For invalid_request, details names each field that is wrong:
{
"error": {
"code": "invalid_request",
"message": "The request is not valid.",
"details": [{ "path": "url", "message": "Invalid URL" }]
}
}
| Status | Code | What it means |
|---|---|---|
| 400 | invalid_request |
The path, query, or body is not valid. |
| 401 | unauthorized |
No key, or a key that is not valid, revoked, or expired. |
| 402 | payment_required |
Over your plan’s limits, or a Pro feature. |
| 403 | forbidden |
You cannot do this in Omamo, or the request came from a web page. |
| 403 | insufficient_scope |
A read only key tried to change something. |
| 404 | not_found |
It does not exist, or you cannot open it. |
| 429 | rate_limited |
Too many requests. Wait for the seconds in Retry-After. |
| 500 | server_error |
Something went wrong at Omamo. Try again. |
The item lists come a page at a time. limit sets the page size, up to 100, and the default is 50. For each page after the first, send the nextCursor of the page before as cursor. On the last page, nextCursor is null. Treat the cursor as opaque: pass it back as it came.
const base = 'https://omamo.app/api/public/v1';
const headers = { Authorization: `Bearer ${process.env.OMAMO_KEY}` };
async function allItems(collectionId) {
const items = [];
let cursor = null;
do {
const query = new URLSearchParams({ limit: '100', ...(cursor ? { cursor } : {}) });
const response = await fetch(`${base}/collections/${collectionId}/items?${query}`, { headers });
if (!response.ok) throw new Error((await response.json()).error.message);
const page = await response.json();
items.push(...page.data);
cursor = page.nextCursor;
} while (cursor);
return items;
}
Limits
Section titled “Limits”- Each key can make 120 requests a minute. Every answer carries
RateLimit-Limit,RateLimit-Remaining, andRateLimit-Reset(seconds until the minute starts over). - Saving is also limited to 60 saves a minute for you, across the app, the extension, MCP, and the API.
- Your plan’s limits apply, as in the app. On Free, you hold 200 saves across the spaces you own, and a save past that answers 402.
- A body can be up to 2 MB, and a note’s text up to 100,000 characters.
- Saved articles (
GET /items/{itemId}/article) are part of Omamo Pro.
When you get 429, wait for the seconds in Retry-After, then try again.
Keep your keys safe
Section titled “Keep your keys safe”- Use keys only from servers, scripts, and command lines. Omamo refuses any request that comes from a web page, because a key in a web page is a key anyone can copy.
- Keep the key in an environment variable or a secret store, not in your code or in git.
- Give each script its own key. If a script only reads, make its key read only.
- Pick an expiry. When a key expires, make a new one.
- If a key leaks, revoke it in Settings. It stops working on its next request.
Settings shows the day each key was last used. Revoke the keys that no script uses.
Versions
Section titled “Versions”This is version 1. Omamo can add endpoints and add fields to answers without warning, so ignore fields you do not know. A change that breaks code will come as version 2, at a new address, and version 1 will keep working for a while.
The OpenAPI file describes the same endpoints for tools that read OpenAPI.