Skip to content

Send contact form messages to HubSpot or Pipedrive from WordPress, through a webhook ​

A visitor fills in the contact form. The message lands in the site's inbox and in an email, and the sales team, who live in HubSpot or Pipedrive all day, hear about it when someone forwards it on Thursday. On WordPress the fix was a plugin per form and per CRM, each with its own settings page and its own idea of a field name.

A site that moved to Laravel keeps those forms — Contact Form 7's forms and their Flamingo messages come along as they were, see Contact Form 7 in Laravel — and now it tells the CRM itself. kitloom/webhooks has a topic for form messages: one webhook to an address Zapier, Make or n8n gives you, the fields mapped once, and every message from then on is a contact in the CRM within seconds.

Ask the agent ​

With kitloom/ai connected, an agent whose user manages webhooks sets one up and watches it:

  • "Send every contact form message to this Zapier address." (webhooks_create — it answers the secret once, for the receiver)
  • "Did Marie's message from this morning reach Zapier?" (webhooks_deliveries)
  • "Add bookings to the CRM webhook too, and send a test." (webhooks_update with ping: true)

Nothing is deleted: a webhook the team no longer needs is disabled, and its log stays. describe_site tells the agent every topic the site has and how a delivery is signed before it starts.

Set up in the admin ​

In Zapier first: a Zap whose trigger is Webhooks by Zapier, Catch Hook gives you an address to send to; the action is Create Contact in HubSpot or Create Lead in Pipedrive, with the fields mapped from the first message that comes in. Make's Custom webhook and n8n's Webhook node do the same.

Then Webhooks → Webhooks → New:

  1. Name says where it goes. Delivery URL is the address Zapier gave you; the site POSTs there, to a public address only. A webhook to the server's own network is refused, so nobody can use the log to read what the server sees inside it.
  2. Secret signs every delivery. Zapier does not check it; a receiver of your own should, and a secret the receiver gives you can be pasted instead of the one generated.
  3. Topics: tick Forms: Form submitted alone. Orders and bookings can have webhooks of their own, to the warehouse's tools or the salon's calendar.
  4. Save. The webhook is active from now on; Send test sends a ping at once and shows what the receiver answered.

When a visitor writes through the form, the message is kept in the inbox as before, the emails go out, and the webhook fires once the message is safely stored. Deliveries lists each call: the topic, the attempts, the receiver's answer. A 200 means Zapier took it; a failed delivery is tried again after a growing wait, three times, and a receiver that keeps failing pauses the webhook rather than filling the log, with Resume a click away.

What the CRM gets ​

A POST with a JSON body, the topic in X-Kitloom-Topic and an HMAC-SHA256 signature of the body in X-Kitloom-Signature:

json
{
  "id": "6f1c0c6e-2a3b-4a0d-9d2e-5b1f3b7a0c11",
  "topic": "form.submitted",
  "created_at": "2026-11-01T14:03:00Z",
  "site": "https://example.com",
  "data": {
    "form": {"id": 12, "title": "Contact us", "slug": "contact-us"},
    "fields": {"your-name": "Marie Dubois", "your-email": "[email protected]", "your-message": "Do you ship to Belgium?"},
    "page": {"url": "https://example.com/contact/", "post_id": 7},
    "message_id": 1043,
    "submitted_at": "2026-11-01T14:03:00Z"
  }
}

The fields are by name, as the visitor filled them, so your-email maps to the contact's email and your-name to the name once, for every message after. The page says which form on which page it came from; the message id finds it in Contact → Messages. Nothing of the visitor's address, browser or account goes along, and nothing of the spam check: a message the form refused, or one caught as spam, is never sent.

For a Laravel developer ​

The form topic is one class, a WebhookTopic, that listens to the forms module's SubmissionReceived event and shapes the body; the webhooks module never requires the forms module, it only asks whether the event exists. A topic of your own — a review published, an application received — is the same class, tagged in your provider, and lands on the webhook form and in the agent's description of the site.

A receiver of your own checks the signature over the body exactly as received:

php
$expected = hash_hmac('sha256', $request->getContent(), $secret);
abort_unless(hash_equals($expected, $request->header('X-Kitloom-Signature', '')), 403);

Deliveries go out from the queue through spatie/laravel-webhook-server, so a slow CRM never slows the form, and the log keeps every body and answer for the retention days you set. It comes with both admins, Filament and Nova.

Watch it ​

A short lesson from the admin, narrated:

Form messages to a CRM: a webhook to Zapier, a message sent, its delivery and body

Try it ​

Open a sandbox in one click, with no sign-up: Filament or Nova. Every topic the site sends, the headers and the bodies are in the Webhooks guide; the forms themselves are in the Forms guide.

Last updated:

kitloom — modules and themes for Laravel.
Contact · Pricing · Services · License · Refunds · Privacy · Community · YouTube · [email protected]