Send item changes to your own app with webhooks

Webhooks let Keep notify another app whenever your items change. When something happens (a new item is saved, a tag is added, an item is removed from a collection), Keep sends a signed HTTP POST to a URL you control. Use them to mirror your library into another tool, trigger automations, or keep an external system in sync.

Create and manage webhooks from your settings.

Create a webhook

  1. Go to Settings / Integrations / Webhooks.
  2. Select New webhook.
  3. Enter the URL Keep should call and an optional name.
  4. Choose which events to receive and an optional scope.
  5. Select Create webhook.

When the webhook is created, Keep shows the signing secret once. Copy it right away. You use it to verify deliveries, and it is not shown again. If you lose it, rotate the secret to generate a new one.

Events

A webhook can listen for all events or a specific subset.

eventwhen it fires
item.createdA new item is saved
item.updatedAn item's metadata changes
item.deletedAn item is deleted
item.taggedA tag is added to an item
item.untaggedA tag is removed from an item
item.collection_addedAn item is added to a collection
item.collection_removedAn item is removed from a collection
item.removed_from_scopeAn item leaves the webhook's tag or collection scope
webhook.testA test delivery you triggered from settings

Selecting All events subscribes the endpoint to every event type, including new ones added later.

Scope

By default a webhook fires for every item in your account. You can narrow it to a single tag or a single collection so you only receive changes that matter to that endpoint. When an item moves out of a scoped webhook's tag or collection, Keep sends an item.removed_from_scope event so you can drop it on your side.

Payload

Every delivery is a JSON body with this shape:

{
  "id": "evt_...",
  "type": "item.created",
  "createdAt": 1709251200000,
  "accountId": "acct_...",
  "data": {
    "eventId": "...",
    "itemId": "a1b2c3",
    "beforeScope": {
      "status": "stashed",
      "tagSlugs": ["reading"],
      "collectionIds": ["col_1"]
    },
    "afterScope": {
      "status": "stashed",
      "tagSlugs": ["reading", "ai"],
      "collectionIds": ["col_1"]
    },
    "payload": {
      "changedFields": ["tags"],
      "tagSlugsAdded": ["ai"]
    }
  }
}

beforeScope and afterScope describe the item's status, tags, and collections before and after the change. payload carries the specifics of what changed. The body references the item by itemId and does not include the full content. Fetch it from the API with GET /api/items/:id when you need the title, markdown, or other fields.

Verify the signature

Keep signs every request using the Standard Webhooks specification. Each delivery includes these headers:

headerdescription
webhook-idUnique id for this delivery
webhook-timestampUnix timestamp (seconds) when the request was signed
webhook-signatureSignature over the id, timestamp, and raw body

Verify the signature with your endpoint's secret before trusting a payload. Any Standard Webhooks library works. For example, in Node:

import { Webhook } from 'standardwebhooks'

const wh = new Webhook(process.env.KEEP_WEBHOOK_SECRET)

// `body` must be the raw request body string, not a re-serialized object
const payload = wh.verify(body, {
  'webhook-id': req.headers['webhook-id'],
  'webhook-timestamp': req.headers['webhook-timestamp'],
  'webhook-signature': req.headers['webhook-signature'],
})

Use the raw request body for verification. Parsing and re-serializing the JSON can change the bytes and break the signature.

Test deliveries

Use Send test event in settings to send a webhook.test delivery to an active endpoint. Recent deliveries and their status appear under each webhook so you can confirm your endpoint is receiving and accepting events.

Retries and failures

Your endpoint should respond with a 2xx status within 10 seconds. If it returns another status or times out, Keep retries with increasing delays (after roughly 1 minute, 5 minutes, 15 minutes, and 1 hour) for up to 5 attempts per delivery. After repeated consecutive failures, Keep automatically disables the endpoint. Re-enable it from settings once your endpoint is healthy again.

Manage webhooks from the API

You can also manage endpoints programmatically with a personal API key.

curl -X POST https://keep.md/api/webhooks \
  -H "Authorization: Bearer $KEEP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Research sync",
    "url": "https://example.com/keep",
    "eventTypes": ["*"],
    "resourceScope": { "tagSlugs": ["ai"] }
  }'

Other endpoints let you list (GET /api/webhooks), update (PATCH /api/webhooks/:id), pause or resume (set status), rotate the secret (POST /api/webhooks/:id/rotate-secret), send a test (POST /api/webhooks/:id/test), inspect deliveries (GET /api/webhooks/:id/deliveries), and delete (DELETE /api/webhooks/:id).