Skip to main content

webhooks

Configure NocoDB webhooks (HookV3) on a table — insert, update and delete triggers, field scoping, and notification targets URL, Email, Slack, Discord, Telegram, Whatsapp, Twilio or Script, plus listing, updating, testing and deleting hooks. Use when a NocoDB table should notify another system. The business-user view of webhooks is nocodb-ops.

Source facts

Repository
Agents-Store/codex-plugins
Last source activity
November 1, 2026 at 02:46
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
2 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
webhooks
description
Configure NocoDB webhooks (HookV3) on a table — insert, update and delete triggers, field scoping, and notification targets URL, Email, Slack, Discord, Telegram, Whatsapp, Twilio or Script, plus listing, updating, testing and deleting hooks. Use when a NocoDB table should notify another system. The business-user view of webhooks is nocodb-ops.
# Webhooks (HookV3) NocoDB webhooks fire on record events and dispatch to a notification target (URL, Email, a messaging service, or a Script). Hook APIs are available on cloud-hosted Business and above and on licensed self-hosted deployments. Hook lifecycle goes through the MCP `hooks` category on **Cloud / licensed** (`listTools category: "hooks"`, then `callTool`) or through the **REST API** (`curl` on Meta API v3) on Community Edition / as a fallback. See **mcp-patterns** for the contract. The schema reference is `HookV3*` in `api-reference/references/nocodb-meta-openapi.json`: ```bash jq '.components.schemas.HookV3Create' skills/api-reference/references/nocodb-meta-openapi.json ``` ## Hook Anatomy (v3) ```jsonc { "title": "<display name>", "description": "Optional", "event": "record", // "record" | "manual" "operation": ["insert", "update"], // array of "insert" | "update" | "delete" "notification": { "type": "...", "payload": { ... } }, "trigger_fields": ["<columnId>", "<columnId>"], "active": true } ``` Required: `title`, `operation`, `notification`. | Key | Required | Notes | |-----|----------|-------| | `title` | Yes | Free text — keep distinct so logs are readable | | `event` | No | `record` (default) fires on the chosen `operation`(s); `manual` fires only when explicitly invoked from a Button or Script | | `operation` | Yes | **Array** of `insert` / `update` / `delete`. One hook can listen to multiple operations | | `notification` | Yes | URL, Email, a messaging service or Script (see below) | | `trigger_fields` | No | Array of column IDs — for `update` events, only fire when one of these fields changed | | `active` | No | Default `true`; set `false` to disable without deleting | | `description` | No | Free text | > **v3 simplifications you may have seen elsewhere don't apply:** > - There is no `before` / `after` distinction — all v3 hooks are async-after-commit. > - There is no top-level `condition` filter. To gate by record state, use `trigger_fields` for change-detection on update, or use a `Script` notification for richer logic. > - There is no separate `bulkInsert` / `bulkUpdate` / `bulkDelete` operation — `insert` / `update` / `delete` cover both single-record and bulk operations; the destination payload contains `record` (single) or `records` (bulk). ## Notification Types ### URL — generic webhook ```json { "type": "URL", "payload": { "method": "POST", "path": "https://hooks.example.com/nocodb", "body": "{\"id\": \"{{record.Id}}\", \"title\": \"{{record.Title}}\"}", "headers": [ { "name": "Authorization", "value": "Bearer ${API_KEY}" } ] } } ``` `{{record.<FieldName>}}` is the templating syntax. Both single-record and bulk operations send a JSON body — check `record` for single, `records` for bulk. ### Email ```json { "type": "Email", "payload": { "to": "ops@example.com", "subject": "New {{record.Status}} ticket: {{record.Title}}", "body": "<p>Ticket #{{record.Id}} was just created.</p>" } } ``` `to`, `subject` and `body` are all required. Requires the NocoDB SMTP plugin to be configured. ### Messaging — Slack / Discord / Telegram / Whatsapp / Twilio The notification `type` **is** the service; the payload carries the message `body`: ```json { "type": "Slack", "payload": { "body": ":rocket: New high-priority bug: *{{record.Title}}*" } } ``` `type`: `Slack`, `Discord`, `Telegram`, `Whatsapp`, `Twilio` (per `HookNotificationV3Messaging`). The spec's `payload` has no channel or webhook-URL key — the connection to the service comes from the matching NocoDB notification plugin / integration, so configure it in NocoDB first. ### Script ```json { "type": "Script", "payload": { "scriptId": "<scriptId>" } } ``` The Script must already exist on the same base (Script APIs: cloud Enterprise or licensed self-hosted). `method` (default `POST`) and `path` are optional. Scripts run in NocoDB's sandboxed JS environment. All notification types also accept `include_user`, `trigger_form` and `trigger_form_id`. ## Create a Hook REST: ```bash curl -sS -X POST \ -H "xc-token: ${NOCODB_TOKEN}" \ -H "Content-Type: application/json" \ -d @hook.json \ "${NOCODB_URL}/api/v3/meta/bases/${BASE_ID}/tables/${TABLE_ID}/hooks" ``` MCP (Cloud / licensed): ``` mcp__plugin_nocodb-dev_nocodb__listTools category: "hooks" mcp__plugin_nocodb-dev_nocodb__callTool name: "createHook" arguments: { tableId: "<tableId>", title: "Slack on new bug", event: "record", operation: ["insert"], notification: { type: "Slack", payload: { body: "..." } }, active: true } ``` `trigger_fields` in the MCP tool requires `operation` to include `"update"` and `event` `"record"`; any other combination is rejected. ## Worked Example — Slack on Bug Inserts ```bash curl -sS -X POST \ -H "xc-token: ${NOCODB_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "title": "Slack on new bug", "event": "record", "operation": ["insert"], "notification": { "type": "Slack", "payload": { "body": ":bug: *New bug:* {{record.Title}}\nReported by {{record.ReporterEmail}}" } }, "active": true }' \ "${NOCODB_URL}/api/v3/meta/bases/${BASE_ID}/tables/${BUGS_TABLE_ID}/hooks" ``` > v3 hooks have no top-level `condition` field. To fire only on high-priority bugs, choose one of: > 1. **Move the gate into the body** — the destination evaluates `{{record.Priority}}` and ignores Low/Medium. > 2. **Use a `Script` notification** — write a script that inspects the record and dispatches conditionally. > 3. **Use `trigger_fields`** for `update` events (fires only when those columns change). ## List Hooks ```bash curl -sS \ -H "xc-token: ${NOCODB_TOKEN}" \ "${NOCODB_URL}/api/v3/meta/bases/${BASE_ID}/tables/${TABLE_ID}/hooks" ``` MCP: `listHooks` / `getHook` (read tools, always listed). ## Update a Hook ```bash curl -sS -X PATCH \ -H "xc-token: ${NOCODB_TOKEN}" \ -H "Content-Type: application/json" \ -d '{"active":false}' \ "${NOCODB_URL}/api/v3/meta/bases/${BASE_ID}/hooks/${HOOK_ID}" ``` To change the target, send a new `notification` object (`{"notification":{"type":"URL","payload":{...}}}`). The MCP `updateHook` is a **full replacement**, not a patch: read the hook with `getHook` first and resend every key you want to keep, including `notification` — anything omitted is rejected rather than preserved. ## Delete a Hook ```bash curl -sS -X DELETE \ -H "xc-token: ${NOCODB_TOKEN}" \ "${NOCODB_URL}/api/v3/meta/bases/${BASE_ID}/hooks/${HOOK_ID}" ``` MCP: `callTool name: "deleteHook" arguments: { hookId: "<hookId>" }`. ## Testing a Hook NocoDB has a built-in test fire in its UI that does not insert/update real data. Via API / MCP, the safest test is: 1. Create a single test record matching the condition. 2. Confirm the destination receives the payload. 3. Delete the test record. Or temporarily set `active: false` while developing, then enable. ## Pre-Flight Checklist 1. **Destination ready.** The URL endpoint is live; the messaging integration (Slack, Discord, …) is configured in NocoDB; the email recipient mailbox exists; the Script exists on the same base. 2. **Templating fields.** Every `{{record.<X>}}` references a column that exists on the table. Misspellings render literally as `{{record.Misspell}}`. 3. **Idempotency.** All v3 hooks are async-after-commit and NocoDB retries on non-2xx responses; the destination must tolerate replays. 4. **Bulk awareness.** Bulk operations fire one hook per affected record — destinations should batch on their side if they care. 5. **Secrets.** Don't bake long-lived secrets into the body; prefer Authorization headers — and rotate them at the destination. ## Troubleshooting | Symptom | Cause | Fix | |---------|-------|-----| | Hook never fires | `active: false`; wrong `operation` array | Check status; verify `operation` includes the action you expect | | Hook fires twice | Two hooks with overlapping `operation` arrays on the same table | List hooks and de-dup | | `{{record.Field}}` literal in body | Field name typo or case mismatch | Match the column title exactly (case-sensitive) | | 401 on URL hook | Destination requires auth | Add `Authorization` header in `payload.headers` | | `update` hook fires when unrelated fields change | `trigger_fields` not set | Add `trigger_fields: ["<id>", ...]` so only changes to those columns fire | | Bulk-update sends per-record payloads instead of one batched body | NocoDB v3 sends one HTTP request per affected record | Process them in your destination; there's no batched-bulk operation in v3 |
View on GitHub