Obsidian Webhooks
Guides GitHub Log In
EN | RU
← All Guides

How Obsidian Webhooks Works

Architecture, setup, integration examples — all on one page

Architecture

Architecture: Your Service → Server → Queue → Obsidian Plugin → Your Vault

"Vault" is a note storage in Obsidian. A folder on your disk where all .md files live.

1. Your Service — n8n, Make, script, or bot sends an HTTP POST with content

2. Server — validates the webhook_key and saves content to the queue

3. Queue — stores data for up to 30 days, even when Obsidian is closed

4. Obsidian Plugin — online: content arrives via SSE in 1-3 seconds. Was offline: picks up everything on reconnect

5. Your Vault — plugin creates a note and sends delivery confirmation (ACK). Server clears the queue

Quick Start

From signup to your first note in vault — 5 minutes. See also: Self-Hosted Setup Guide

01

Sign up

Check your email → click the login link → open your dashboard. You'll see two keys:

  • webhook_key — for sending content to the server
  • client_key — for connecting the plugin in Obsidian
02

Install the plugin in Obsidian

1. Download: Download Plugin →

2. Extract to your vault:

.obsidian/plugins/obsidian-webhooks/
├── main.js
└── manifest.json

3. Obsidian → Settings → Community plugins → "Obsidian Webhooks" → Enable

4. Settings → Obsidian Webhooks → paste your client_key → Connect. = connected

03

Send your first webhook

Quickest way to check it works — curl:

curl -X POST \
  "https://obsidian-webhooks.khabaroff.studio/webhook/{your_webhook_key}?path=inbox/test.md" \
  -H "Content-Type: application/json" \
  -d '{"content": "# First note\n\nSent via webhook!"}'

A note will appear in your vault within 1-3 seconds at inbox/test.md. For more examples, see 10 Automation Recipes.

Server response:

200 OK — content accepted and queued

400 Bad Request — missing path query parameter

401 Unauthorized — invalid webhook_key

Two Keys for Sending and Receiving

webhook_key

For sending content to the server.

POST https://obsidian-webhooks.khabaroff.studio/webhook/{webhook_key}?path=inbox/note.md
Content-Type: application/json

{
  "title": "My Note",
  "content": "# Title\n\nNote text",
  "tags": ["inbox", "webhook"]
}

path — where to save in vault (required, query param)

content — note body in Markdown

title, tags, date, ... — go to YAML frontmatter

Plain text body is written as-is, without JSON parsing.

client_key

Paste into Obsidian: Settings → Obsidian Webhooks → Client Key.

Each webhook_key is paired with a client_key. Content sent to one is only accessible to its pair.

Keys are generated cryptographically — impossible to guess.

Integration Examples

Works with any service that supports HTTP POST. See 10 ready-to-use recipes for Zapier, Make, n8n, and more.

n8n

1. New Workflow → "HTTP Request" node

2. Method: POST

3. URL: https://obsidian-webhooks.khabaroff.studio/webhook/{webhook_key}?path=inbox/n8n-note.md

{
  "content": "# Note from n8n\n\nWorkflow data",
  "source": "n8n"
}

Make

1. New Scenario → "HTTP" module → "Make a request"

2. Method: POST

3. URL: https://obsidian-webhooks.khabaroff.studio/webhook/{webhook_key}?path=inbox/make-note.md

{
  "content": "# From Make\n\nText",
  "source": "make"
}

Python

import requests

response = requests.post(
    "https://obsidian-webhooks.khabaroff.studio/webhook/{webhook_key}?path=inbox/script-note.md",
    json={
        "content": "# Note from Python\n\nText",
        "source": "python"
    }
)
print(response.status_code)  # 200

Telegram Bot

Telegram doesn't send webhooks to arbitrary URLs. You need a bot — a simple script that forwards messages as HTTP POST.

WEBHOOK_URL = "https://obsidian-webhooks.khabaroff.studio/webhook/{webhook_key}"

def handle_message(update, context):
    text = update.message.text
    requests.post(
        f"{WEBHOOK_URL}?path=inbox/telegram.md",
        json={"content": f"# Telegram\n\n{text}"}
    )

Token: Telegram → @BotFather → /newbot

cURL

curl -X POST \
  "https://obsidian-webhooks.khabaroff.studio/webhook/{webhook_key}?path=inbox/test.md" \
  -H "Content-Type: application/json" \
  -d '{"content": "# Test\n\nIt works!"}'

Dashboard

Keys, stats, request format

Keys and stats

Your webhook_key and client_key with Show/Hide and Copy. Stats: key status, creation date, last used, event count.

Quick start and request format

Step-by-step setup guide, plugin download link, curl example, and a full table of JSON body fields (content, title, tags, ...).

Frequently Asked Questions

The server uses Server-Sent Events (SSE) to push data to the Obsidian plugin the moment it arrives. SSE keeps a persistent connection open between the plugin and the server, so new webhooks are delivered within 1-3 seconds.

The server stores webhooks in an encrypted PostgreSQL queue for up to 30 days. When you reopen Obsidian and the plugin reconnects, all queued webhooks are delivered automatically. No data is lost.

After the plugin writes a note to your vault, it sends an acknowledgment (ACK) back to the server. The server only removes the webhook from the queue after receiving the ACK. This exactly-once delivery guarantee ensures no duplicates or lost messages.

Yes. All webhook payloads stored in the queue are encrypted at rest with AES-256-GCM. The connection between the plugin and the server uses HTTPS (TLS 1.3). No payload data appears in logs or metrics.

Yes. Each vault gets its own webhook_key and client_key pair. Content sent to one key is only accessible to its paired key. One server supports multiple vaults with complete isolation between them.