Webhook reference

Receive incoming MailContact messages in your own app or automation. Available on Pro and Plus.

Want email, Slack or Discord alerts? Follow the notification guide.

The payload

Each new message triggers one HTTP POST to your URL with a Content-Type: application/json body:

POST https://your-app.example/hooks/mailcontact
{
  "id": "d8f2e71a20b4",
  "event": "message.created",
  "project": {
    "id": "prj_8f2k1q",
    "name": "acme-site"
  },
  "source": {
    "type": "form",
    "name": "Website contact form"
  },
  "url": "https://mailcontact.app/app/projects/prj_8f2k1q?message=msg_4t9s2e",
  "reply": {
    "url": "https://mailcontact.app/app/projects/prj_8f2k1q?message=msg_4t9s2e",
    "method": "open_conversation"
  },
  "message": {
    "id": "msg_4t9s2e",
    "from": {
      "name": "Ada Lovelace",
      "email": "[email protected]"
    },
    "subject": "Question about pricing",
    "body": "Hi, quick question about the Pro plan...",
    "receivedAt": "2026-07-14T09:30:00.000Z"
  }
}

Fields

  • event: message.created for an incoming message, or notification.test for the Test button. Test events have a null message and source.
  • project: the project whose inbox received the message (its id and name).
  • source: where the message came from. type is "form" (the form endpoint) or "email" (the project email address); name is the source's label in your inbox.
  • message.from: the sender's email (always present) and name (may be empty when the sender didn't provide one).
  • message.subject: optional on form posts, so it may be empty.
  • message.receivedAt: ISO 8601 timestamp, UTC.
  • reply.url: opens this conversation in Mailcontact, where its owner can reply after signing in. It grants no access on its own. Test events have a null reply.

Delivery

  • Respond fast. Return a 2xx status as soon as you've accepted the payload and do any real work asynchronously. Deliveries will time out after 10 seconds.
  • At-least-once. A slow response or a transient failure can cause the same message to be delivered more than once. Deduplicate using the payload's id, also sent in the Idempotency-Key and X-Mailcontact-Event-Id headers.
  • Temporary failures and HTTP 429 are retried up to five attempts, with exponential delays. Most other 4xx responses stop delivery.
  • Use a public HTTPS endpoint on port 443. Private networks, credentials in URLs and redirects are refused.

Security

Payloads are not signed yet, which means anyone who discovers your webhook URL can POST a fake payload to it. Follow these precautions:

  • Use a long, unguessable path for your webhook URL and don't publish it anywhere.
  • Treat every payload as untrusted input: validate it before acting on it.
  • Don't trigger destructive or irreversible actions from an unsigned webhook. Notifying, logging and queuing are fine; deleting things is not.

Webhook signing is not currently available. Do not treat receipt of a payload as proof of its sender.

Webhooks vs. notification channels

Use the notification guide for email, Slack and Discord alerts. This reference covers the generic webhook format for your own code. See pricing for the current offers.