---
title: "Keep API for notes, saved items, and Markdown context | Keep"
description: "Search notes and saved items, update Markdown notes, attach sources, fetch content, and manage Keep from an AI tool, script, or app."
canonical: "https://keep.md/docs/api"
language: "en"
---

# Keep REST API reference

Search notes and saved items, update Markdown notes, attach sources, fetch content, and manage Keep from an AI tool, script, or app.

The Keep API lets you search Notes and Items, update Markdown Notes, manage Projects, fetch saved content, and manage sources. Responses are JSON unless a route states another format.

## Base URL

```
https://keep.md/api
```

## API version

The current API version is `2026-08-24`. You can send it in the optional `Keep-API-Version` header. If you omit the header, Keep uses the current version and returns it in the response.

```
curl https://keep.md/api/me \
  -H "Authorization: Bearer $KEEP_API_KEY" \
  -H "Keep-API-Version: 2026-08-24"
```

Keep uses a new date for a breaking change. A deprecated version stays available for at least six months. Its responses include `Deprecation`, `Sunset`, and a `Link` to migration information before it is removed.

## Authentication

All requests require a Bearer token in the `Authorization` header. Create a personal key in [Connection settings](https://app.keep.md/settings/connections#api). See [API keys](https://keep.md/docs/api-keys) for personal, connected client, and read-only keys.

```
curl https://keep.md/api/me \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

## Connected client keys

Use a current personal key to create a named library credential for an AI tool or other client. The new key is returned once and can read and write Items, Notes, tags, collections, Projects, and highlights.

```
curl https://keep.md/api/connected-clients \
  -X POST \
  -H "Authorization: Bearer $KEEP_PERSONAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Codex"}'
```

`GET /api/connected-clients` lists active clients. Revoke one without affecting other credentials with `POST /api/connected-clients/revoke` and a JSON body containing its `id`. Connected client keys cannot create or revoke credentials.

## Rate limits

The API allows 300 requests per credential or IP in 60 seconds. Public tools that use conversion or external services allow 60 requests per IP in 60 seconds. Credential and device sign-in starts allow 10 requests per IP in 60 seconds.

Responses include `RateLimit-Policy`. A `429` response also includes `RateLimit` and `Retry-After`. Wait for the stated time before you try again.

Paid plans also count full-content items per billing cycle. When a plan limit is reached, a write that adds another full-content item returns `429` with `error: "quota_reached"`.

## Errors

Errors return JSON with a stable `error` code and an appropriate HTTP status. An error can also include a human-readable `message`, a suggested `resolution`, and fields that are specific to the route.

```
// 401: missing or invalid token
{ "error": "unauthorized" }

// 429: plan limit reached
{
  "error": "quota_reached",
  "plan": "plus",
  "limitScope": "billing_cycle",
  "linkLimit": 500,
  "linkCount": 500
}

// 404: item not found
{ "error": "not_found" }

// 404: API route not found
{
  "error": "not_found",
  "message": "The requested API route does not exist.",
  "resolution": "Check the path and method in the API reference at https://keep.md/docs/api."
}
```

## GET /api/me

Returns your plan, limits, and usage counts.

```
curl https://keep.md/api/me \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

```
{
  "plan": "plus",
  "linkLimit": 500,
  "linkCount": 42,
  "linkCountMonth": 12,
  "linkCountPeriod": 12,
  "linkCountLifetime": 87
}
```

## GET /api/stats

Usage statistics for a date range.

`since` is the start of the range as a timestamp or ISO date. `until` is the optional end of the range.

```
curl "https://keep.md/api/stats?since=2026-06-01" \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

```
{
  "total": 12,
  "byStatus": { "stashed": 10, "flagged": 2 },
  "range": { "since": "...", "until": "...", "count": 12 }
}
```

## GET /api/items

List your saved items. Archived items are excluded by default.

`since` and `until` filter by time. `status` is a comma-separated status filter. `tags` accepts tag names or slugs. `collection` accepts an ID, name, or slug. `source` limits results to one capture source or website. `include=content` adds structured content and rendered Markdown. `limit` is 1-1000 and defaults to 200. `offset` controls pagination.

```
curl "https://keep.md/api/items?collection=x-articles&tags=agent-tooling&limit=10&include=content" \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

```
{
  "items": [
    {
      "id": "a1b2c3",
      "url": "https://github.com/iannuttall/seo",
      "title": "SEO CLI",
      "status": "stashed",
      "collectionName": "X Articles",
      "collectionSlug": "x-articles",
      "tagSlugs": ["agent-tooling"],
      "createdAt": 1709251200,
      "contentAvailable": true,
      "contentMarkdown": "---\ntitle: \"SEO CLI\"\n---\n\n# SEO CLI\n\nAudit websites from the command line...",
      "content": {
        "schemaVersion": 2,
        "meta": {
          "frontmatter": {
            "title": "SEO CLI",
            "source": "https://github.com/iannuttall/seo",
            "content_type": "repository"
          }
        },
        "items": {
          "content": {
            "format": "markdown",
            "markdown": "# SEO CLI\n\nAudit websites from the command line...\n"
          }
        },
        "media": []
      }
    }
  ],
  "limit": 10,
  "offset": 0,
  "count": 1
}
```

## GET /api/items/search

Search saved Items by title, URL, notes, tags, and meaning.

`q` is required. This route supports the same filters as `/api/items`, including `source`. Set `mode` to `lexical`, `semantic`, or `hybrid`.

```
curl "https://keep.md/api/items/search?q=react%20hooks&collection=x-articles&tags=agent-tooling&limit=10" \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

## GET /api/items/:id/read

Read a saved Item without returning the whole captured document. `view` defaults to `overview` and accepts `overview`, `search`, `lines`, or `full`.

```
curl "https://keep.md/api/items/a1b2c3/read?view=overview" \
  -H "Authorization: Bearer $KEEP_API_KEY"

curl "https://keep.md/api/items/a1b2c3/read?view=search&q=payment%20failure&contextLines=2&limit=5" \
  -H "Authorization: Bearer $KEEP_API_KEY"

curl "https://keep.md/api/items/a1b2c3/read?view=lines&lines=40:90" \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

Overview returns metadata, document statistics, and headings. Search returns at most 200 lines and 16 KB across its windows. An exact slice can contain at most 200 lines and 32 KB. `view=full` is the deliberate opt-in for the whole document.

## GET /api/items/:id/highlights

Add `limit` and `offset` for a bounded highlight page. `limit` defaults to 25 and cannot exceed 100. The response includes `hasMore` and `nextOffset`.

## GET /api/items/:id/media

Return ordered media references without the captured document or private storage keys. `limit` defaults to 20 and cannot exceed 100. Pass `nextOffset` back as `offset` to fetch the next page.

## GET /api/search

Search Notes and saved Items together. `q` is required. Use `types=item,note` to choose resource types. `mode` accepts `lexical`, `semantic`, or `hybrid`.

Project and path values help current handoffs rank higher. Add `exactProject=true` or `exactPath=true` when they must be filters. You can also filter Notes with `kind`, `state`, and `tags`.

```
curl "https://keep.md/api/search?q=note%20sync&types=item,note&mode=hybrid&limit=10" \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

Search results contain a stable resource type and ID, a snippet of at most 600 UTF-8 bytes, and the matched field. Note matches also include the current revision and a relevant line range when Keep can locate it. Full content stays out of the response unless you add `include=content`; explicit content is shared fairly across results and reports truncation. A client can pass the returned revision and range directly to the progressive Note read endpoint.

## GET /api/context/brief

Return a bounded index of recent Notes for one Git project. `project` is required. `path` improves ranking for directory-specific Notes, and `limit` is capped at 20.

```
curl "https://keep.md/api/context/brief?project=https%3A%2F%2Fgithub.com%2Fiannuttall%2Fkeep&path=packages%2Fcli" \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

The response contains Note IDs, titles, descriptions, kind, state, paths, tags, updated times, and stable URLs. It never includes Note bodies or attached Item content.

## Notes

Notes are Markdown documents with revision checks. Replacements, metadata changes, archive actions, and restores require the current `expectedRevision`. Appends can omit it because Keep applies them to the latest revision without discarding another writer’s appended Markdown.

Note responses use the bare ID shown by Keep. Routes also accept older IDs that begin with `note_`.

| endpoint | use |
| --- | --- |
| `POST /api/notes` | Create a note |
| `GET /api/notes` | List compact Note manifests; add `include=content` for bodies |
| `GET /api/notes/search?q=...` | Search notes as compact result coordinates |
| `GET /api/notes/export` | Download all notes as a Markdown ZIP |
| `GET /api/notes/:id` | Read a note |
| `GET /api/notes/:id/read` | Read an overview, search result, or line range |
| `PATCH /api/notes/:id` | Update the supplied Note fields |
| `POST /api/notes/:id/append` | Append Markdown |
| `POST /api/notes/:id/archive` | Archive a note |
| `POST /api/notes/:id/restore` | Restore a note |
| `GET /api/notes/:id/history` | Read revision summaries; add `include=content` for bodies |
| `POST /api/notes/:id/revisions/:revision/restore` | Restore an older revision as a new revision |

Create a note:

```
curl -X POST https://keep.md/api/notes \
  -H "Authorization: Bearer $KEEP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "OAuth verification handoff",
    "bodyMarkdown": "## Current state\n\nThe review passed.",
    "kind": "handoff",
    "state": "open",
    "properties": { "path": "packages/cli" },
    "clientRequestId": "handoff-2026-07-21"
  }'
```

Update metadata without replacing the body:

```
curl -X PATCH https://keep.md/api/notes/c4e2a975-d582-4fb9-b952-5911365332c7 \
  -H "Authorization: Bearer $KEEP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "expectedRevision": 1,
    "tags": [],
    "project": null,
    "state": "closed",
    "clientRequestId": "close-handoff-1"
  }'
```

Fields omitted from an update stay unchanged. Send an empty `tags` array to remove every tag. Send `null` for `project`, `repository`, `kind`, or `state` to clear that field. `properties` contains custom metadata only. Updating it does not change tags, Project, repository, kind, or state.

Successful write responses are compact receipts. `note` contains `id`, `title`, and `currentRevision`; `revision` contains `revisionNumber` and `operation`. They do not echo Markdown. Read the returned Note revision only when you need to verify content. The receipt’s `metadataDiff` contains added and removed tag slugs plus before and after values for Project, kind, or state when they changed. Project values in the diff are Project IDs.

Append a later result without reading the current revision first:

```
curl -X POST https://keep.md/api/notes/c4e2a975-d582-4fb9-b952-5911365332c7/append \
  -H "Authorization: Bearer $KEEP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "bodyMarkdown": "## Result\n\nThe production check passed.",
    "clientRequestId": "production-check-1"
  }'
```

Keep resolves the latest revision and safely retries one concurrent append. Include `expectedRevision` only when the append must stay pinned to a known version. A stale pinned revision returns `409` with `error: "revision_conflict"`. Send `Accept: text/markdown` to `GET /api/notes/:id` when you want a full frontmatter document.

Restore an older version without deleting the revisions that followed it:

```
curl -X POST https://keep.md/api/notes/c4e2a975-d582-4fb9-b952-5911365332c7/revisions/2/restore \
  -H "Authorization: Bearer $KEEP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "expectedRevision": 5,
    "clientRequestId": "restore-note-123-v2"
  }'
```

The restored content becomes revision 6 in this example. The full history stays available.

Open the authenticated Note page at `https://app.keep.md/notes/:id` to read its Markdown, properties, references, and recent history.

Download every current and archived Note as a ZIP with one Markdown file per Note:

```
curl https://keep.md/api/notes/export \
  -H "Authorization: Bearer $KEEP_API_KEY" \
  --output keep-notes.zip
```

The route requires `notes.read`. Each file preserves the stable Note ID, revision, timestamps, archive state when present, custom properties, and Markdown body.

### Progressive Note reads

Use `GET /api/notes/:id/read` when a client does not need the full body.

Set `view` to one of these values:

| Mode | Required parameters | Result |
| --- | --- | --- |
| `overview` | none | Revision, counts, and heading outline |
| `search` | `q` | Matching line windows |
| `lines` | `lines=start:end` | One exact line range |

You can add `revision` to pin the read to one revision. An exact range can contain at most 200 lines and 32 KB. Search results use bounded context windows and return at most 200 lines and 16 KB in total. A `413` response means the requested exact range is still too large; request a narrower range. These reads do not use Note credits.

```
curl "https://keep.md/api/notes/c4e2a975-d582-4fb9-b952-5911365332c7/read?view=overview" \
  -H "Authorization: Bearer $KEEP_API_KEY"

curl "https://keep.md/api/notes/c4e2a975-d582-4fb9-b952-5911365332c7/read?view=search&q=rollout&revision=4" \
  -H "Authorization: Bearer $KEEP_API_KEY"

curl "https://keep.md/api/notes/c4e2a975-d582-4fb9-b952-5911365332c7/read?view=lines&lines=40%3A90&revision=4" \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

## Note sources and context

Attach a saved item or highlight to a note:

```
curl -X POST https://keep.md/api/notes/c4e2a975-d582-4fb9-b952-5911365332c7/item-links \
  -H "Authorization: Bearer $KEEP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "itemId": "a1b2c3",
    "highlightId": "hl_123",
    "relation": "evidence",
    "annotation": "Supports the retrieval decision."
  }'
```

`relation` accepts `source`, `evidence`, `example`, `inspiration`, or `annotation`. Repeating the same attachment returns the existing link.

Read the note with bounded source summaries and highlights:

```
curl "https://keep.md/api/notes/c4e2a975-d582-4fb9-b952-5911365332c7/context?history=1" \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

Add `content=1` when full Item content is needed. `sourceLimit`, `historyLimit`, and `contentBytes` keep the response within a useful size. A missing or archived Item is marked unavailable without failing the whole Note response.

Remove an attachment with `DELETE /api/notes/:id/item-links/:linkId`.

## Projects

Projects group Note and repository context. Project states are `active`, `paused`, and `completed`.

| Endpoint | Use |
| --- | --- |
| `GET /api/projects` | List active Projects |
| `GET /api/projects?includeArchived=true` | Include archived Projects |
| `GET /api/projects/:id` | Get one Project |
| `POST /api/projects` | Create a Project |
| `PATCH /api/projects/:id` | Update a Project |
| `DELETE /api/projects/:id` | Archive a Project |

Create a Project:

```
curl -X POST https://keep.md/api/projects \
  -H "Authorization: Bearer $KEEP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "SEO CLI",
    "description": "Project memory for the SEO command-line tool.",
    "color": "#f97316",
    "state": "active",
    "repositories": ["https://github.com/iannuttall/seo"]
  }'
```

Project routes require `projects.read` or `projects.write`. Deleting a Project archives it. It does not delete its Notes or Items.

## GET /api/items/:id

Get a single Item by ID with its complete saved content. Use `GET /api/items/:id/read` for an overview, search window, or line slice. If the Item has saved highlights, this full response includes a `highlights` array. Callers with `notes.read` also receive connected Notes.

```
curl https://keep.md/api/items/a1b2c3 \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

Captured images are ordered in `content.media`. Web captures use their source HTTPS URL. A direct image upload uses an authenticated Keep URL.

## GET /api/items/:id/media/:mediaId

Returns one directly uploaded image owned by the Item. The same Bearer token and `items.read` permission used for the Item are required.

## GET /api/items/:id/highlights

List the highlights attached to one Item. Add `limit` and `offset` for a bounded page. A bounded response includes `hasMore` and `nextOffset`.

```
curl "https://keep.md/api/items/a1b2c3/highlights?limit=25&offset=0" \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

```
{
  "highlights": [
    {
      "id": "hl_123",
      "itemId": "a1b2c3",
      "text": "Important selected text",
      "prefix": "Text before the highlight",
      "suffix": "Text after the highlight",
      "note": "Optional note",
      "createdAt": 1709251200,
      "updatedAt": 1709251200
    }
  ]
}
```

## GET /api/highlights/:id

Get one highlight by ID.

```
curl https://keep.md/api/highlights/hl_123 \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

```
{
  "highlight": {
    "id": "hl_123",
    "itemId": "a1b2c3",
    "text": "Important selected text",
    "prefix": "Text before the highlight",
    "suffix": "Text after the highlight",
    "note": "Optional note",
    "createdAt": 1709251200,
    "updatedAt": 1709251200
  }
}
```

## Change highlights

Create a highlight with `POST /api/items/:id/highlights`. Send `text`, plus optional `prefix`, `suffix`, `note`, `startOffset`, and `endOffset` fields.

Update an existing highlight with `PATCH /api/highlights/:id`. You can change the selected text, anchors, offsets, or note.

Delete a highlight with `DELETE /api/highlights/:id`. Deletion is permanent.

## POST /api/items/:id

Update item metadata or state.

Supports `title`, `notes`, `tags`, `collectionId`, `collectionIds`, `archived`, and `processed`. Collection inputs accept ids, names, or slugs.

```
curl -X POST https://keep.md/api/items/a1b2c3 \
  -H "Authorization: Bearer $KEEP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "title": "Better title", "tags": ["AI Research"], "collectionIds": ["x-articles"], "processed": true }'
```

```
{
  "id": "a1b2c3",
  "title": "Better title",
  "tags": ["AI Research"],
  "tagSlugs": ["ai-research"],
  "collectionName": "X Articles",
  "collectionSlug": "x-articles",
  "processedAt": 1709251200
}
```

## GET /api/tags

List the distinct tags currently used by your visible items. Each tag includes its display name and slug.

```
curl "https://keep.md/api/tags" \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

```
{
  "tags": [
    { "name": "X Articles", "slug": "x-articles" },
    { "name": "Agent Tooling", "slug": "agent-tooling" }
  ]
}
```

## Change tags

| Endpoint | Use |
| --- | --- |
| `POST /api/tags` | Create a tag with a `name` |
| `PATCH /api/tags/:slug` | Change the name or description |
| `DELETE /api/tags/:slug` | Remove the tag from Notes and Items |

Deleting a tag does not delete any Note or Item.

## GET /api/collections

List your collections. Each collection includes an id, display name, and slug.

```
curl "https://keep.md/api/collections" \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

## POST /api/collections

Create a collection by name. If it already exists, the existing one is returned.

```
curl -X POST "https://keep.md/api/collections" \
  -H "Authorization: Bearer $KEEP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "X Articles" }'
```

Collections can group Items. The current public API can list and create collections. Add or remove collection IDs through `POST /api/items/:id`.

## GET /api/items/:id/content

Returns the rendered markdown as plain text. Response headers include `x-content-size` and `x-content-truncated`.

```
curl https://keep.md/api/items/a1b2c3/content \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

## POST /api/ingest

Save a URL. Keep fetches the page, normalizes it into structured content, and renders markdown from that contract. Duplicate URLs are deduplicated automatically.

```
curl -X POST https://keep.md/api/ingest \
  -H "Authorization: Bearer $KEEP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://suganthan.com/blog/webmcp-implementation-guide/" }'
```

```
{
  "ok": true,
  "id": "a1b2c3",
  "url": "https://suganthan.com/blog/webmcp-implementation-guide/",
  "extracted": true
}
```

## POST /api/items/archive

Archive items by ID. Archived items are hidden from the default list.

```
curl -X POST https://keep.md/api/items/archive \
  -H "Authorization: Bearer $KEEP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "ids": ["a1b2c3"] }'
```

```
{ "requested": 1, "archived": 1 }
```

## POST /api/items/delete

Permanently delete items by ID.

```
curl -X POST https://keep.md/api/items/delete \
  -H "Authorization: Bearer $KEEP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "ids": ["a1b2c3"] }'
```

```
{ "requested": 1, "deleted": 1 }
```

## GET /api/feed

Returns unprocessed items with structured content plus rendered markdown. Designed for AI tools and scripts that use your saved items as context. Supports the same `since`, `until`, `q`, `tags`, `collection`, `limit`, and `offset` params as `/api/items/search`.

```
curl "https://keep.md/api/feed?limit=5" \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

## POST /api/items/mark-processed

Mark items as processed so they no longer appear in the feed.

```
curl -X POST https://keep.md/api/items/mark-processed \
  -H "Authorization: Bearer $KEEP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "ids": ["a1b2c3", "d4e5f6"] }'
```

```
{ "processed": 2 }
```

## GET /api/items/changes

Stream item change events for delta sync. Use this to keep an external system in sync without re-listing your whole library: poll with a cursor and apply only what changed. For push delivery instead of polling, see [Webhooks](https://keep.md/docs/webhooks).

Requires a personal [API key](https://keep.md/docs/api-keys). A scoped key only returns changes for items inside its scope.

| Parameter | Use |
| --- | --- |
| `cursor` | Opaque `nextCursor` value from the previous response |
| `updated_since` | Return changes at or after a timestamp or ISO date |
| `tags` | Filter by comma-separated tag names or slugs |
| `collection` | Filter by collection ID, name, or slug |
| `limit` | Return 1-1000 events. The default is 200 |
| `include=content` | Add structured content and rendered Markdown to an attached Item |

```
curl "https://keep.md/api/items/changes?updated_since=2026-06-01&limit=100" \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

```
{
  "events": [
    {
      "id": "evt_123",
      "type": "item.tagged",
      "changedAt": 1709251200000,
      "itemId": "a1b2c3",
      "beforeScope": {
        "status": "stashed",
        "tagSlugs": ["reading"],
        "collectionIds": ["col_1"]
      },
      "afterScope": {
        "status": "stashed",
        "tagSlugs": ["reading", "ai"],
        "collectionIds": ["col_1"]
      },
      "payload": { "changedFields": ["tags"], "tagSlugsAdded": ["ai"] },
      "item": {
        "id": "a1b2c3",
        "url": "https://suganthan.com/blog/webmcp-implementation-guide/",
        "title": "WebMCP implementation guide"
      }
    }
  ],
  "nextCursor": "...",
  "hasMore": false,
  "limit": 100
}
```

Each event carries the event `type`, the `itemId`, and `beforeScope` / `afterScope` snapshots of the item’s status, tags, and collections. The current `item` is attached when it still exists and is in scope; `item.deleted` events have no attached item. When a scoped key or filter is used and an item leaves that scope, an `item.removed_from_scope` event is emitted so you can drop it on your side.

Pass `nextCursor` as the `cursor` on your next request and keep going while `hasMore` is `true`. Event types match the [webhook events](https://keep.md/docs/webhooks#events).

## GET /api/sources

List sources and subscriptions. Source routes require a session, Keep service key, or personal token with `items.write`. Read-only keys cannot view or change source settings.

The default response is a compact status manifest. It omits configuration, tag rules, and internal cursors.

```
curl https://keep.md/api/sources \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

Add `include=settings` to inspect redacted configuration and tag rules:

```
curl "https://keep.md/api/sources?include=settings" \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

Add `include=sensitive` only while debugging a source you control:

```
curl "https://keep.md/api/sources?include=sensitive" \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

This response includes complete source configuration and internal cursors. It may contain credentials. Do not paste it into a chat, issue, log, or Note. The MCP `list_sources` tool always uses the safe response and cannot request this view.

## POST /api/sources

Create an RSS, YouTube, X articles, or email inbox source.

```
curl -X POST https://keep.md/api/sources \
  -H "Authorization: Bearer $KEEP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "type": "rss", "feedUrl": "https://simonwillison.net/atom/everything/" }'
```

## POST /api/sources/:id/delete

Remove a source.

```
curl -X POST https://keep.md/api/sources/src_123/delete \
  -H "Authorization: Bearer $KEEP_API_KEY"
```

## Manage sources

| Endpoint | Use |
| --- | --- |
| `POST /api/sources/:id/pause` | Pause automatic sync |
| `POST /api/sources/:id/resume` | Resume automatic sync |
| `POST /api/sources/:id/settings` | Update name, tags, rules, content, summaries, or rollup |
| `POST /api/sources/:id/default-tags` | Replace default tags |
| `POST /api/sources/:id/rollup` | Turn Feed rollup on or off |
| `GET /api/sources/:id/events` | List recent source events |
| `POST /api/sources/import-opml` | Import feed sources from OPML |
| `GET /api/sources/export-opml` | Download feed sources as OPML |

The settings request can contain `name`, `defaultTags`, `smartTagRules`, `expandFullContent`, `autoSummarize`, and `rollupEnabled`. Available settings depend on the source type and plan.

Email inbox sources also provide confirmation and recent-message routes. Use the app for provider confirmation links, raw message inspection, and private inbox administration.

## Item export jobs

Use export jobs for saved Items. Use `GET /api/notes/export` for the direct Notes ZIP.

| Endpoint | Use |
| --- | --- |
| `POST /api/exports` | Start an Item export job |
| `GET /api/exports` | List recent export jobs |
| `GET /api/exports/:jobId/download` | Download a complete export |

The create request chooses Markdown ZIP, JSON, or CSV. It can limit Items by tag, collection, stashed state, or archived state. It can include saved content and omit personal Item notes. See [Export](https://keep.md/docs/export) for the user-facing options.

## Webhooks

Webhook routes let a personal key manage signed Item-change deliveries.

| Endpoint | Use |
| --- | --- |
| `GET /api/webhooks` | List endpoints |
| `POST /api/webhooks` | Create an endpoint |
| `GET /api/webhooks/:id` | Read one endpoint |
| `PATCH /api/webhooks/:id` | Change its URL, events, scope, name, or status |
| `POST /api/webhooks/:id/test` | Queue a test delivery |
| `POST /api/webhooks/:id/rotate-secret` | Replace its signing secret |
| `GET /api/webhooks/:id/deliveries` | List recent deliveries |
| `DELETE /api/webhooks/:id` | Delete the endpoint |

See [Webhooks](https://keep.md/docs/webhooks) for events, signatures, retries, and resource scope.

[openapi.json](https://keep.md/openapi.json)
