# n8n usage notes Use the TypeScript SDK from an n8n **Code** node when n8n can import local or bundled npm packages. In self-hosted n8n this usually means installing the SDK where n8n can resolve it and allowing external modules, for example with `NODE_FUNCTION_ALLOW_EXTERNAL=@obsidian-api/sdk` or `NODE_FUNCTION_ALLOW_EXTERNAL=*`. The SDK only sends structured `args` arrays to the HTTP API. It never sends shell command strings. ## Environment variables Recommended n8n env vars: ```env OBSIDIAN_API_URL=http://obsidian-api:8080 OBSIDIAN_API_JWT= OBSIDIAN_VAULT=work ``` Recommended: use a restricted JWT for n8n. Create it with: ```bash OBSIDIAN_JWT_SECRET=change-this-long-random-secret \ python scripts/create_jwt.py \ --sub n8n \ --vault work \ --path Inbox/n8n/ \ --path Automation.md \ --command create \ --command read \ --command append \ --command search \ --command search:context \ --days 365 ``` The JWT contains claims like: ```json { "sub": "n8n", "vaults": ["work"], "paths": ["Inbox/n8n/", "Automation.md"], "commands": ["create", "read", "append", "search", "search:context"], "exp": 1791536000 } ``` If n8n runs outside the Docker network, use the exposed host URL instead: ```env OBSIDIAN_API_URL=http://localhost:8080 ``` ## Basic Code node ```ts import { ObsidianCliClient } from '@obsidian-api/sdk'; const obsidian = new ObsidianCliClient({ baseUrl: process.env.OBSIDIAN_API_URL!, token: process.env.OBSIDIAN_API_JWT!, vault: process.env.OBSIDIAN_VAULT, }); const title = $json.title ?? 'n8n note'; const content = `# ${title}\n\nCreated from n8n.\n`; const result = await obsidian.create({ path: `Inbox/${title}.md`, content, overwrite: true, }); return [{ json: result }]; ``` ## Append incoming webhook payload to a daily note ```ts import { ObsidianCliClient } from '@obsidian-api/sdk'; const obsidian = new ObsidianCliClient({ baseUrl: process.env.OBSIDIAN_API_URL!, token: process.env.OBSIDIAN_API_JWT!, vault: process.env.OBSIDIAN_VAULT, }); const payload = JSON.stringify($json, null, 2).replace(/```/g, '``\\`'); const result = await obsidian.dailyAppend( `\n## n8n event\n\n\`\`\`json\n${payload}\n\`\`\`\n`, ); return [{ json: result }]; ``` ## Search notes ```ts import { ObsidianCliClient } from '@obsidian-api/sdk'; const obsidian = new ObsidianCliClient({ baseUrl: process.env.OBSIDIAN_API_URL!, token: process.env.OBSIDIAN_API_JWT!, vault: process.env.OBSIDIAN_VAULT, }); const result = await obsidian.search($json.query, { format: 'json' }); return [{ json: { matches: JSON.parse(result.stdout) } }]; ``` ## Multi-vault usage If the API container registers multiple vaults, use a scoped client per vault: ```ts const base = new ObsidianCliClient({ baseUrl: process.env.OBSIDIAN_API_URL!, token: process.env.OBSIDIAN_API_JWT!, }); const work = base.inVault('work'); const personal = base.inVault('personal'); await work.create({ path: 'Inbox/Work.md', content: 'Work note', overwrite: true }); await personal.create({ path: 'Inbox/Personal.md', content: 'Personal note', overwrite: true }); ``` ## Without SDK If package imports are not available in your n8n environment, call the HTTP API directly: ```ts const response = await fetch(`${process.env.OBSIDIAN_API_URL}/commands`, { method: 'POST', headers: { authorization: `Bearer ${process.env.OBSIDIAN_API_JWT}`, 'content-type': 'application/json', }, body: JSON.stringify({ args: ['vault=work', 'create', 'path=Inbox/n8n.md', 'content=Hello from n8n', 'overwrite'], }), }); return [{ json: await response.json() }]; ```