Create Accountor Login
Docs

Webhooks

Part of the MountDev Ops Workspace documentation. Updated October 7, 2026

MountDev Ops Workspace documentation | Updated October 7, 2026

Webhooks tell your other systems the moment something changes in your workspace, and let them add records to it. Owners and admins manage them in the workspace menu, Integrations. AI agents never see or change webhooks.

Outbound Webhooks

On the Webhooks tab (action core.webhooks.list), each webhook is an https address that hears about the events you choose.

  • Add a Webhook (action core.webhooks.save): a name, the address, and the events to send. The address must start with https:// and be on the public internet: addresses on private networks (such as 10.x, 192.168.x, or localhost) and link-local addresses are refused, whether written as numbers or reached through a name.
  • Its secret is shown once when it is added, with Copy. Your receiver uses it to check each delivery. It is kept encrypted and never shown again. Change can replace it, and the new one is shown once.
  • Send Test (action core.webhooks.test) sends one sample event straight away, signed like any other, and shows the answer.
  • Deliveries (action core.webhooks.deliveries) shows the newest 50 deliveries: the event, Delivered, Waiting, or Failed, the number of tries, the receiver's last answer, and when the next try is. Send Again (action core.webhooks.retry) sends a failed delivery again from the first try.
  • Turn Off (action core.webhooks.turn_off) stops new deliveries; Turn On (action core.webhooks.turn_on) starts them again.
  • Delete (action core.webhooks.delete) deletes the webhook and its secret, and cancels deliveries still waiting.

Events

Every module has three events: a record was added (<module>.created), changed (<module>.updated), or deleted (<module>.deleted), such as crm.contacts.created. Apps add their own:

EventWhen
helpdesk.ticket.openedA ticket starts
helpdesk.ticket.repliedA reply goes out on a ticket
helpdesk.ticket.client_repliedA client writes on a ticket
helpdesk.ticket.closedA ticket is closed
forms.form.submittedA website form is sent
billing.invoice.paidAn invoice is paid in full

An app's events are offered once the app is added. Changes from people, AI agents, API keys, inbound webhooks, email, and automations all count. Importing records sends no events, because an import can bring in thousands of records at once.

What Is Sent

Each delivery is a POST with a JSON body:

{ "id": "evt_1042", "type": "crm.contacts.updated", "at": "2026-10-07T17:00:00.000Z", "via": "screen", "module": "crm.contacts", "record": { "id": 17, "module_id": "crm.contacts", "data": { "name": "Ann Lee" }, "owner_id": 2, "version": 4, "created_at": "...", "updated_at": "..." }, "changes": { "phone": { "from": null, "to": "555-0100" } } }

changes comes with updates only. record.data holds the fields that are on; for a deleted record, its last values. via says who made the change: screen, agent, api, automation, webhook, email, or system.

Headers: X-MDO-Event (the event), X-MDO-Delivery (the delivery's number, the same on every try), and X-MDO-Signature.

Checking the Signature

X-MDO-Signature looks like t=1791392400,v1=5d41.... To check it, take t, a period, and the raw body, make the HMAC-SHA256 of that with your webhook's secret, and compare it in constant time with v1. Refuse a delivery whose t is more than a few minutes old, so an old delivery cannot be sent to you again.

Tries

Answer with any 2xx status to say a delivery arrived. Anything else (or no answer within 10 seconds) is tried again after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours, and 12 hours. After the last try it is marked Failed, and the webhook shows it. Redirects are never followed. A delivery may arrive more than once, so use its event id to skip one you already have.

Inbound Webhooks

On the Inbound Webhooks tab (action core.inbound_hooks.list), each inbound webhook is an address another system posts JSON to. Each post becomes a record in the module you choose.

  • Add an Inbound Webhook (action core.inbound_hooks.save): a name, the module its records go in, and which value in the JSON fills each field, by its key, such as email, or contact.email for a value inside contact. Fields left empty are skipped.
  • Its address is shown with Copy. Treat it like a password: anyone with it can add records.
  • Values are checked exactly as on the screens. A post that does not fit (a required field missing, a choice that is not one of the field's choices) is refused with the reason, and the webhook shows the last refusal.
  • Send a POST with a JSON object of up to 64 KB. The answer is { "ok": true, "id": <the new record> }, or { "error": "..." }.
  • Turn Off (action core.inbound_hooks.turn_off) refuses posts until Turn On (action core.inbound_hooks.turn_on). Delete (action core.inbound_hooks.delete) ends the address for good. Records it added stay.

Records an inbound webhook adds are marked Inbound webhook in their history, and they set off webhooks and automations like any other new record.

Ask Us Anything

We’d love to hear from you!